llvm.org GIT mirror llvm / cc0c5b9
[WebAssembly] Added default stack-only instruction mode for MC. Summary: Moved Explicit Locals pass to last. Made that pass obligatory. Made it convert from register to stack based instructions, and removed the registers. Fixes to related code that was expecting register based instructions. Added the correct testing flag to all tests, depending on what the format they were expecting so far. Translated one test to stack format as example: reg-stackify-stack.ll tested: llvm-lit -v `find test -name WebAssembly` unittests/MC/* Reviewers: dschuff, sunfish Subscribers: sbc100, jgravelle-google, eraman, aheejin, llvm-commits Differential Revision: https://reviews.llvm.org/D49160 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@338164 91177308-0d34-0410-b5e6-96231b3b80d8 Wouter van Oortmerssen 2 years ago
89 changed file(s) with 838 addition(s) and 420 deletion(s). Raw diff Collapse all Expand all
3333
3434 namespace {
3535
36 // We store register types as SimpleValueType to retain SIMD layout
37 // information, but must also be able to supply them as the (unnamed)
38 // register enum from WebAssemblyRegisterInfo.td/.inc.
39 static unsigned MVTToWasmReg(MVT::SimpleValueType Type) {
40 switch(Type) {
41 case MVT::i32: return WebAssembly::I32_0;
42 case MVT::i64: return WebAssembly::I64_0;
43 case MVT::f32: return WebAssembly::F32_0;
44 case MVT::f64: return WebAssembly::F64_0;
45 case MVT::v16i8: return WebAssembly::V128_0;
46 case MVT::v8i16: return WebAssembly::V128_0;
47 case MVT::v4i32: return WebAssembly::V128_0;
48 case MVT::v4f32: return WebAssembly::V128_0;
49 default: return MVT::INVALID_SIMPLE_VALUE_TYPE;
50 }
51 }
52
5336 /// WebAssemblyOperand - Instances of this class represent the operands in a
5437 /// parsed WASM machine instruction.
5538 struct WebAssemblyOperand : public MCParsedAsmOperand {
56 enum KindTy { Token, Local, Stack, Integer, Float, Symbol } Kind;
39 enum KindTy { Token, Integer, Float, Symbol } Kind;
5740
5841 SMLoc StartLoc, EndLoc;
5942
6144 StringRef Tok;
6245 };
6346
64 struct RegOp {
65 // This is a (virtual) local or stack register represented as 0..
66 unsigned RegNo;
67 // In most targets, the register number also encodes the type, but for
68 // wasm we have to track that seperately since we have an unbounded
69 // number of registers.
70 // This has the unfortunate side effect that we supply a different value
71 // to the table-gen matcher at different times in the process (when it
72 // calls getReg() or addRegOperands().
73 // TODO: While this works, it feels brittle. and would be nice to clean up.
74 MVT::SimpleValueType Type;
75 };
76
7747 struct IntOp {
7848 int64_t Val;
7949 };
8858
8959 union {
9060 struct TokOp Tok;
91 struct RegOp Reg;
9261 struct IntOp Int;
9362 struct FltOp Flt;
9463 struct SymOp Sym;
9665
9766 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T)
9867 : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {}
99 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, RegOp R)
100 : Kind(K), StartLoc(Start), EndLoc(End), Reg(R) {}
10168 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)
10269 : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}
10370 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F)
10976 bool isImm() const override { return Kind == Integer ||
11077 Kind == Float ||
11178 Kind == Symbol; }
112 bool isReg() const override { return Kind == Local || Kind == Stack; }
11379 bool isMem() const override { return false; }
80 bool isReg() const override { return false; }
11481
11582 unsigned getReg() const override {
116 assert(isReg());
117 // This is called from the tablegen matcher (MatchInstructionImpl)
118 // where it expects to match the type of register, see RegOp above.
119 return MVTToWasmReg(Reg.Type);
83 llvm_unreachable("Assembly inspects a register operand");
84 return 0;
12085 }
12186
12287 StringRef getToken() const {
12792 SMLoc getStartLoc() const override { return StartLoc; }
12893 SMLoc getEndLoc() const override { return EndLoc; }
12994
130 void addRegOperands(MCInst &Inst, unsigned N) const {
131 assert(N == 1 && "Invalid number of operands!");
132 assert(isReg() && "Not a register operand!");
133 // This is called from the tablegen matcher (MatchInstructionImpl)
134 // where it expects to output the actual register index, see RegOp above.
135 unsigned R = Reg.RegNo;
136 if (Kind == Stack) {
137 // A stack register is represented as a large negative number.
138 // See WebAssemblyRegNumbering::runOnMachineFunction and
139 // getWARegStackId for why this | is needed.
140 R |= INT32_MIN;
141 }
142 Inst.addOperand(MCOperand::createReg(R));
95 void addRegOperands(MCInst &, unsigned) const {
96 // Required by the assembly matcher.
97 llvm_unreachable("Assembly matcher creates register operands");
14398 }
14499
145100 void addImmOperands(MCInst &Inst, unsigned N) const {
159114 case Token:
160115 OS << "Tok:" << Tok.Tok;
161116 break;
162 case Local:
163 OS << "Loc:" << Reg.RegNo << ":" << static_cast(Reg.Type);
164 break;
165 case Stack:
166 OS << "Stk:" << Reg.RegNo << ":" << static_cast(Reg.Type);
167 break;
168117 case Integer:
169118 OS << "Int:" << Int.Val;
170119 break;
181130 class WebAssemblyAsmParser final : public MCTargetAsmParser {
182131 MCAsmParser &Parser;
183132 MCAsmLexer &Lexer;
184 // These are for the current function being parsed:
185 // These are vectors since register assignments are so far non-sparse.
186 // Replace by map if necessary.
187 std::vector LocalTypes;
188 std::vector StackTypes;
189133 MCSymbol *LastLabel;
190134
191135 public:
235179 .Default(MVT::INVALID_SIMPLE_VALUE_TYPE);
236180 }
237181
238 MVT::SimpleValueType &GetType(
239 std::vector &Types, size_t i) {
240 Types.resize(std::max(i + 1, Types.size()), MVT::INVALID_SIMPLE_VALUE_TYPE);
241 return Types[i];
242 }
243
244 bool ParseReg(OperandVector &Operands, StringRef TypePrefix) {
245 if (Lexer.is(AsmToken::Integer)) {
246 auto &Local = Lexer.getTok();
247 // This is a reference to a local, turn it into a virtual register.
248 auto LocalNo = static_cast(Local.getIntVal());
249 Operands.push_back(make_unique(
250 WebAssemblyOperand::Local, Local.getLoc(),
251 Local.getEndLoc(),
252 WebAssemblyOperand::RegOp{LocalNo,
253 GetType(LocalTypes, LocalNo)}));
254 Parser.Lex();
255 } else if (Lexer.is(AsmToken::Identifier)) {
256 auto &StackRegTok = Lexer.getTok();
257 // These are push/pop/drop pseudo stack registers, which we turn
258 // into virtual registers also. The stackify pass will later turn them
259 // back into implicit stack references if possible.
260 auto StackReg = StackRegTok.getString();
261 auto StackOp = StackReg.take_while([](char c) { return isalpha(c); });
262 auto Reg = StackReg.drop_front(StackOp.size());
263 unsigned long long ParsedRegNo = 0;
264 if (!Reg.empty() && getAsUnsignedInteger(Reg, 10, ParsedRegNo))
265 return Error("Cannot parse stack register index: ", StackRegTok);
266 unsigned RegNo = static_cast(ParsedRegNo);
267 if (StackOp == "push") {
268 // This defines a result, record register type.
269 auto RegType = ParseRegType(TypePrefix);
270 GetType(StackTypes, RegNo) = RegType;
271 Operands.push_back(make_unique(
272 WebAssemblyOperand::Stack,
273 StackRegTok.getLoc(),
274 StackRegTok.getEndLoc(),
275 WebAssemblyOperand::RegOp{RegNo, RegType}));
276 } else if (StackOp == "pop") {
277 // This uses a previously defined stack value.
278 auto RegType = GetType(StackTypes, RegNo);
279 Operands.push_back(make_unique(
280 WebAssemblyOperand::Stack,
281 StackRegTok.getLoc(),
282 StackRegTok.getEndLoc(),
283 WebAssemblyOperand::RegOp{RegNo, RegType}));
284 } else if (StackOp == "drop") {
285 // This operand will be dropped, since it is part of an instruction
286 // whose result is void.
287 } else {
288 return Error("Unknown stack register prefix: ", StackRegTok);
289 }
290 Parser.Lex();
291 } else {
292 return Error(
293 "Expected identifier/integer following $, instead got: ",
294 Lexer.getTok());
295 }
296 IsNext(AsmToken::Equal);
297 return false;
298 }
299
300182 void ParseSingleInteger(bool IsNegative, OperandVector &Operands) {
301183 auto &Int = Lexer.getTok();
302184 int64_t Val = Int.getIntVal();
309191
310192 bool ParseOperandStartingWithInteger(bool IsNegative,
311193 OperandVector &Operands,
312 StringRef InstType) {
194 StringRef InstName) {
313195 ParseSingleInteger(IsNegative, Operands);
314 if (Lexer.is(AsmToken::LParen)) {
315 // Parse load/store operands of the form: offset($reg)align
316 auto &LParen = Lexer.getTok();
317 Operands.push_back(
318 make_unique(WebAssemblyOperand::Token,
319 LParen.getLoc(),
320 LParen.getEndLoc(),
321 WebAssemblyOperand::TokOp{
322 LParen.getString()}));
323 Parser.Lex();
324 if (Expect(AsmToken::Dollar, "register")) return true;
325 if (ParseReg(Operands, InstType)) return true;
326 auto &RParen = Lexer.getTok();
327 Operands.push_back(
328 make_unique(WebAssemblyOperand::Token,
329 RParen.getLoc(),
330 RParen.getEndLoc(),
331 WebAssemblyOperand::TokOp{
332 RParen.getString()}));
333 if (Expect(AsmToken::RParen, ")")) return true;
334 if (Lexer.is(AsmToken::Integer)) {
196 // FIXME: there is probably a cleaner way to do this.
197 auto IsLoadStore = InstName.startswith("load") ||
198 InstName.startswith("store") ||
199 InstName.startswith("atomic_load") ||
200 InstName.startswith("atomic_store");
201 if (IsLoadStore) {
202 // Parse load/store operands of the form: offset align
203 auto &Offset = Lexer.getTok();
204 if (Offset.is(AsmToken::Integer)) {
335205 ParseSingleInteger(false, Operands);
336206 } else {
337207 // Alignment not specified.
338208 // FIXME: correctly derive a default from the instruction.
209 // We can't just call WebAssembly::GetDefaultP2Align since we don't have
210 // an opcode until after the assembly matcher.
339211 Operands.push_back(make_unique(
340 WebAssemblyOperand::Integer, RParen.getLoc(),
341 RParen.getEndLoc(), WebAssemblyOperand::IntOp{0}));
212 WebAssemblyOperand::Integer, Offset.getLoc(),
213 Offset.getEndLoc(), WebAssemblyOperand::IntOp{0}));
342214 }
343215 }
344216 return false;
359231 while (Lexer.isNot(AsmToken::EndOfStatement)) {
360232 auto &Tok = Lexer.getTok();
361233 switch (Tok.getKind()) {
362 case AsmToken::Dollar: {
363 Parser.Lex();
364 if (ParseReg(Operands, NamePair.first)) return true;
365 break;
366 }
367234 case AsmToken::Identifier: {
368235 auto &Id = Lexer.getTok();
369236 const MCExpr *Val;
379246 Parser.Lex();
380247 if (Lexer.isNot(AsmToken::Integer))
381248 return Error("Expected integer instead got: ", Lexer.getTok());
382 if (ParseOperandStartingWithInteger(true, Operands, NamePair.first))
249 if (ParseOperandStartingWithInteger(true, Operands, NamePair.second))
383250 return true;
384251 break;
385252 case AsmToken::Integer:
386 if (ParseOperandStartingWithInteger(false, Operands, NamePair.first))
253 if (ParseOperandStartingWithInteger(false, Operands, NamePair.second))
387254 return true;
388255 break;
389256 case AsmToken::Real: {
404271 }
405272 }
406273 Parser.Lex();
407 // Call instructions are vararg, but the tablegen matcher doesn't seem to
408 // support that, so for now we strip these extra operands.
409 // This is problematic if these arguments are not simple $pop stack
410 // registers, since e.g. a local register would get lost, so we check for
411 // this. This can be the case when using -disable-wasm-explicit-locals
412 // which currently s2wasm requires.
413 // TODO: Instead, we can move this code to MatchAndEmitInstruction below and
414 // actually generate get_local instructions on the fly.
415 // Or even better, improve the matcher to support vararg?
416 auto IsIndirect = NamePair.second == "call_indirect";
417 if (IsIndirect || NamePair.second == "call") {
418 // Figure out number of fixed operands from the instruction.
419 size_t CallOperands = 1; // The name token.
420 if (!IsIndirect) CallOperands++; // The function index.
421 if (!NamePair.first.empty()) CallOperands++; // The result register.
422 if (Operands.size() > CallOperands) {
423 // Ensure operands we drop are all $pop.
424 for (size_t I = CallOperands; I < Operands.size(); I++) {
425 auto Operand =
426 reinterpret_cast(Operands[I].get());
427 if (Operand->Kind != WebAssemblyOperand::Stack)
428 Parser.Error(NameLoc,
429 "Call instruction has non-stack arguments, if this code was "
430 "generated with -disable-wasm-explicit-locals please remove it");
431 }
432 // Drop unneeded operands.
433 Operands.resize(CallOperands);
434 }
435 }
436274 // Block instructions require a signature index, but these are missing in
437275 // assembly, so we add a dummy one explicitly (since we have no control
438276 // over signature tables here, we assume these will be regenerated when
441279 Operands.push_back(make_unique(
442280 WebAssemblyOperand::Integer, NameLoc,
443281 NameLoc, WebAssemblyOperand::IntOp{-1}));
444 }
445 // These don't specify the type, which has to derived from the local index.
446 if (NamePair.second == "get_local" || NamePair.second == "tee_local") {
447 if (Operands.size() >= 3 && Operands[1]->isReg() &&
448 Operands[2]->isImm()) {
449 auto Op1 = reinterpret_cast(Operands[1].get());
450 auto Op2 = reinterpret_cast(Operands[2].get());
451 auto Type = GetType(LocalTypes, static_cast(Op2->Int.Val));
452 Op1->Reg.Type = Type;
453 GetType(StackTypes, Op1->Reg.RegNo) = Type;
454 }
455282 }
456283 return false;
457284 }
476303 IsNext(AsmToken::At) &&
477304 Lexer.is(AsmToken::Identifier)))
478305 return Error("Expected label,@type declaration, got: ", Lexer.getTok());
479 if (Lexer.getTok().getString() == "function") {
480 // Track locals from start of function.
481 LocalTypes.clear();
482 StackTypes.clear();
483 }
484306 Parser.Lex();
485307 //Out.EmitSymbolAttribute(??, MCSA_ELF_TypeFunction);
486308 } else if (DirectiveID.getString() == ".param" ||
493315 while (Lexer.is(AsmToken::Identifier)) {
494316 auto RegType = ParseRegType(Lexer.getTok().getString());
495317 if (RegType == MVT::INVALID_SIMPLE_VALUE_TYPE) return true;
496 LocalTypes.push_back(RegType);
497318 if (DirectiveID.getString() == ".param") {
498319 Params.push_back(RegType);
499320 } else {
168168
169169 switch (MI->getOpcode()) {
170170 case WebAssembly::ARGUMENT_I32:
171 case WebAssembly::ARGUMENT_I32_S:
171172 case WebAssembly::ARGUMENT_I64:
173 case WebAssembly::ARGUMENT_I64_S:
172174 case WebAssembly::ARGUMENT_F32:
175 case WebAssembly::ARGUMENT_F32_S:
173176 case WebAssembly::ARGUMENT_F64:
177 case WebAssembly::ARGUMENT_F64_S:
174178 case WebAssembly::ARGUMENT_v16i8:
179 case WebAssembly::ARGUMENT_v16i8_S:
175180 case WebAssembly::ARGUMENT_v8i16:
181 case WebAssembly::ARGUMENT_v8i16_S:
176182 case WebAssembly::ARGUMENT_v4i32:
183 case WebAssembly::ARGUMENT_v4i32_S:
177184 case WebAssembly::ARGUMENT_v4f32:
185 case WebAssembly::ARGUMENT_v4f32_S:
178186 // These represent values which are live into the function entry, so there's
179187 // no instruction to emit.
180188 break;
181189 case WebAssembly::FALLTHROUGH_RETURN_I32:
190 case WebAssembly::FALLTHROUGH_RETURN_I32_S:
182191 case WebAssembly::FALLTHROUGH_RETURN_I64:
192 case WebAssembly::FALLTHROUGH_RETURN_I64_S:
183193 case WebAssembly::FALLTHROUGH_RETURN_F32:
194 case WebAssembly::FALLTHROUGH_RETURN_F32_S:
184195 case WebAssembly::FALLTHROUGH_RETURN_F64:
196 case WebAssembly::FALLTHROUGH_RETURN_F64_S:
185197 case WebAssembly::FALLTHROUGH_RETURN_v16i8:
198 case WebAssembly::FALLTHROUGH_RETURN_v16i8_S:
186199 case WebAssembly::FALLTHROUGH_RETURN_v8i16:
200 case WebAssembly::FALLTHROUGH_RETURN_v8i16_S:
187201 case WebAssembly::FALLTHROUGH_RETURN_v4i32:
188 case WebAssembly::FALLTHROUGH_RETURN_v4f32: {
202 case WebAssembly::FALLTHROUGH_RETURN_v4i32_S:
203 case WebAssembly::FALLTHROUGH_RETURN_v4f32:
204 case WebAssembly::FALLTHROUGH_RETURN_v4f32_S: {
189205 // These instructions represent the implicit return at the end of a
190 // function body. The operand is always a pop.
191 assert(MFI->isVRegStackified(MI->getOperand(0).getReg()));
192
206 // function body. Always pops one value off the stack.
193207 if (isVerbose()) {
194 OutStreamer->AddComment("fallthrough-return: $pop" +
195 Twine(MFI->getWARegStackId(
196 MFI->getWAReg(MI->getOperand(0).getReg()))));
208 OutStreamer->AddComment("fallthrough-return-value");
197209 OutStreamer->AddBlankLine();
198210 }
199211 break;
200212 }
201213 case WebAssembly::FALLTHROUGH_RETURN_VOID:
214 case WebAssembly::FALLTHROUGH_RETURN_VOID_S:
202215 // This instruction represents the implicit return at the end of a
203216 // function body with no return value.
204217 if (isVerbose()) {
205 OutStreamer->AddComment("fallthrough-return");
218 OutStreamer->AddComment("fallthrough-return-void");
206219 OutStreamer->AddBlankLine();
207220 }
208221 break;
243256 OS << MO.getImm();
244257 return false;
245258 case MachineOperand::MO_Register:
259 // FIXME: only opcode that still contains registers, as required by
260 // MachineInstr::getDebugVariable().
261 assert(MI->getOpcode() == WebAssembly::INLINEASM);
246262 OS << regToString(MO);
247263 return false;
248264 case MachineOperand::MO_GlobalAddress:
3030
3131 #define DEBUG_TYPE "wasm-explicit-locals"
3232
33 // A command-line option to disable this pass. Note that this produces output
34 // which is not valid WebAssembly, though it may be more convenient for writing
35 // LLVM unit tests with.
36 static cl::opt DisableWebAssemblyExplicitLocals(
37 "disable-wasm-explicit-locals", cl::ReallyHidden,
38 cl::desc("WebAssembly: Disable emission of get_local/set_local."),
33 // A command-line option to disable this pass, and keep implicit locals and
34 // stackified registers for the purpose of testing with lit/llc ONLY.
35 // This produces output which is not valid WebAssembly, and is not supported
36 // by assemblers/disassemblers and other MC based tools.
37 static cl::opt RegisterCodeGenTestMode(
38 "wasm-register-codegen-test-mode", cl::Hidden,
39 cl::desc("WebAssembly: output stack registers and implicit locals in"
40 " instruction output for test purposes only."),
41 cl::init(false));
42 // This one does explicit locals but keeps stackified registers, as required
43 // by some current tests.
44 static cl::opt ExplicitLocalsCodeGenTestMode(
45 "wasm-explicit-locals-codegen-test-mode", cl::Hidden,
46 cl::desc("WebAssembly: output stack registers and explicit locals in"
47 " instruction output for test purposes only."),
3948 cl::init(false));
4049
4150 namespace {
5766 WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
5867 };
5968 } // end anonymous namespace
69
70 unsigned regInstructionToStackInstruction(unsigned OpCode);
6071
6172 char WebAssemblyExplicitLocals::ID = 0;
6273 INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE,
161172
162173 /// Given a MachineOperand of a stackified vreg, return the instruction at the
163174 /// start of the expression tree.
164 static MachineInstr *FindStartOfTree(MachineOperand &MO,
175 static MachineInstr *findStartOfTree(MachineOperand &MO,
165176 MachineRegisterInfo &MRI,
166177 WebAssemblyFunctionInfo &MFI) {
167178 unsigned Reg = MO.getReg();
172183 for (MachineOperand &DefMO : Def->explicit_uses()) {
173184 if (!DefMO.isReg())
174185 continue;
175 return FindStartOfTree(DefMO, MRI, MFI);
186 return findStartOfTree(DefMO, MRI, MFI);
176187 }
177188
178189 // If there were no stackified uses, we've reached the start.
185196 << MF.getName() << '\n');
186197
187198 // Disable this pass if directed to do so.
188 if (DisableWebAssemblyExplicitLocals)
199 if (RegisterCodeGenTestMode)
189200 return false;
190201
191202 bool Changed = false;
205216 break;
206217 unsigned Reg = MI.getOperand(0).getReg();
207218 assert(!MFI.isVRegStackified(Reg));
208 Reg2Local[Reg] = MI.getOperand(1).getImm();
219 Reg2Local[Reg] = static_cast(MI.getOperand(1).getImm());
209220 MI.eraseFromParent();
210221 Changed = true;
211222 }
212223
213224 // Start assigning local numbers after the last parameter.
214 unsigned CurLocal = MFI.getParams().size();
225 unsigned CurLocal = static_cast(MFI.getParams().size());
215226
216227 // Precompute the set of registers that are unused, so that we can insert
217228 // drops to their defs.
218229 BitVector UseEmpty(MRI.getNumVirtRegs());
219 for (unsigned i = 0, e = MRI.getNumVirtRegs(); i < e; ++i)
220 UseEmpty[i] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(i));
230 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I)
231 UseEmpty[I] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(I));
221232
222233 // Visit each instruction in the function.
223234 for (MachineBasicBlock &MBB : MF) {
321332 // If we see a stackified register, prepare to insert subsequent
322333 // get_locals before the start of its tree.
323334 if (MFI.isVRegStackified(OldReg)) {
324 InsertPt = FindStartOfTree(MO, MRI, MFI);
335 InsertPt = findStartOfTree(MO, MRI, MFI);
325336 continue;
326337 }
327338
355366 Changed = true;
356367 }
357368 }
369
370 if (!ExplicitLocalsCodeGenTestMode) {
371 // Remove all uses of stackified registers to bring the instruction format
372 // into its final stack form, and transition opcodes to their _S variant.
373 // We do this in a seperate loop, since the previous loop adds/removes
374 // instructions.
375 // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
376 // details.
377 // TODO: the code above creates new registers which are then removed here.
378 // That code could be slightly simplified by not doing that, though maybe
379 // it is simpler conceptually to keep the code above in "register mode"
380 // until this transition point.
381 for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
382 I != E;) {
383 MachineInstr &MI = *I++;
384 // FIXME: we are not processing inline assembly, which contains register
385 // operands, because it is used by later target generic code.
386 if (MI.isDebugInstr() || MI.isLabel() || MI.isInlineAsm())
387 continue;
388 auto RegOpcode = MI.getOpcode();
389 auto StackOpcode = regInstructionToStackInstruction(RegOpcode);
390 MI.setDesc(TII->get(StackOpcode));
391 // Now remove all register operands.
392 for (auto I = MI.getNumOperands(); I; --I) {
393 auto &MO = MI.getOperand(I - 1);
394 if (MO.isReg()) {
395 MI.RemoveOperand(I - 1);
396 // TODO: we should also update the MFI here or below to reflect the
397 // removed registers? The MFI is about to be deleted anyway, so
398 // maybe that is not worth it?
399 }
400 }
401 }
402 }
358403 }
359404
360405 // Define the locals.
361406 // TODO: Sort the locals for better compression.
362407 MFI.setNumLocals(CurLocal - MFI.getParams().size());
363 for (size_t i = 0, e = MRI.getNumVirtRegs(); i < e; ++i) {
364 unsigned Reg = TargetRegisterInfo::index2VirtReg(i);
365 auto I = Reg2Local.find(Reg);
366 if (I == Reg2Local.end() || I->second < MFI.getParams().size())
408 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
409 unsigned Reg = TargetRegisterInfo::index2VirtReg(I);
410 auto RL = Reg2Local.find(Reg);
411 if (RL == Reg2Local.end() || RL->second < MFI.getParams().size())
367412 continue;
368413
369 MFI.setLocal(I->second - MFI.getParams().size(),
414 MFI.setLocal(RL->second - MFI.getParams().size(),
370415 typeForRegClass(MRI.getRegClass(Reg)));
371416 Changed = true;
372417 }
373418
374 #ifndef NDEBUG
375 // Assert that all registers have been stackified at this point.
376 for (const MachineBasicBlock &MBB : MF) {
377 for (const MachineInstr &MI : MBB) {
378 if (MI.isDebugInstr() || MI.isLabel())
379 continue;
380 for (const MachineOperand &MO : MI.explicit_operands()) {
381 assert(
382 (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
383 MFI.isVRegStackified(MO.getReg())) &&
384 "WebAssemblyExplicitLocals failed to stackify a register operand");
385 }
386 }
419 return Changed;
420 }
421
422 unsigned regInstructionToStackInstruction(unsigned OpCode) {
423 switch (OpCode) {
424 default:
425 // You may hit this if you add new instructions, please add them below.
426 // For most of these opcodes, this function could have been implemented
427 // as "return OpCode + 1", but since table-gen alphabetically sorts them,
428 // this cannot be guaranteed (see e.g. BR and BR_IF).
429 // The approach below is the same as what the x87 backend does.
430 // TODO(wvo): to make this code cleaner, create a custom tablegen
431 // code generator that emits the table below automatically.
432 llvm_unreachable(
433 "unknown WebAssembly instruction in Explicit Locals pass");
434 case WebAssembly::ABS_F32: return WebAssembly::ABS_F32_S;
435 case WebAssembly::ABS_F64: return WebAssembly::ABS_F64_S;
436 case WebAssembly::ADD_F32: return WebAssembly::ADD_F32_S;
437 case WebAssembly::ADD_F32x4: return WebAssembly::ADD_F32x4_S;
438 case WebAssembly::ADD_F64: return WebAssembly::ADD_F64_S;
439 case WebAssembly::ADD_I16x8: return WebAssembly::ADD_I16x8_S;
440 case WebAssembly::ADD_I32: return WebAssembly::ADD_I32_S;
441 case WebAssembly::ADD_I32x4: return WebAssembly::ADD_I32x4_S;
442 case WebAssembly::ADD_I64: return WebAssembly::ADD_I64_S;
443 case WebAssembly::ADD_I8x16: return WebAssembly::ADD_I8x16_S;
444 case WebAssembly::ADJCALLSTACKDOWN: return WebAssembly::ADJCALLSTACKDOWN_S;
445 case WebAssembly::ADJCALLSTACKUP: return WebAssembly::ADJCALLSTACKUP_S;
446 case WebAssembly::AND_I32: return WebAssembly::AND_I32_S;
447 case WebAssembly::AND_I64: return WebAssembly::AND_I64_S;
448 case WebAssembly::ARGUMENT_EXCEPT_REF: return WebAssembly::ARGUMENT_EXCEPT_REF_S;
449 case WebAssembly::ARGUMENT_F32: return WebAssembly::ARGUMENT_F32_S;
450 case WebAssembly::ARGUMENT_F64: return WebAssembly::ARGUMENT_F64_S;
451 case WebAssembly::ARGUMENT_I32: return WebAssembly::ARGUMENT_I32_S;
452 case WebAssembly::ARGUMENT_I64: return WebAssembly::ARGUMENT_I64_S;
453 case WebAssembly::ARGUMENT_v16i8: return WebAssembly::ARGUMENT_v16i8_S;
454 case WebAssembly::ARGUMENT_v4f32: return WebAssembly::ARGUMENT_v4f32_S;
455 case WebAssembly::ARGUMENT_v4i32: return WebAssembly::ARGUMENT_v4i32_S;
456 case WebAssembly::ARGUMENT_v8i16: return WebAssembly::ARGUMENT_v8i16_S;
457 case WebAssembly::ATOMIC_LOAD16_U_I32: return WebAssembly::ATOMIC_LOAD16_U_I32_S;
458 case WebAssembly::ATOMIC_LOAD16_U_I64: return WebAssembly::ATOMIC_LOAD16_U_I64_S;
459 case WebAssembly::ATOMIC_LOAD32_U_I64: return WebAssembly::ATOMIC_LOAD32_U_I64_S;
460 case WebAssembly::ATOMIC_LOAD8_U_I32: return WebAssembly::ATOMIC_LOAD8_U_I32_S;
461 case WebAssembly::ATOMIC_LOAD8_U_I64: return WebAssembly::ATOMIC_LOAD8_U_I64_S;
462 case WebAssembly::ATOMIC_LOAD_I32: return WebAssembly::ATOMIC_LOAD_I32_S;
463 case WebAssembly::ATOMIC_LOAD_I64: return WebAssembly::ATOMIC_LOAD_I64_S;
464 case WebAssembly::ATOMIC_STORE16_I32: return WebAssembly::ATOMIC_STORE16_I32_S;
465 case WebAssembly::ATOMIC_STORE16_I64: return WebAssembly::ATOMIC_STORE16_I64_S;
466 case WebAssembly::ATOMIC_STORE32_I64: return WebAssembly::ATOMIC_STORE32_I64_S;
467 case WebAssembly::ATOMIC_STORE8_I32: return WebAssembly::ATOMIC_STORE8_I32_S;
468 case WebAssembly::ATOMIC_STORE8_I64: return WebAssembly::ATOMIC_STORE8_I64_S;
469 case WebAssembly::ATOMIC_STORE_I32: return WebAssembly::ATOMIC_STORE_I32_S;
470 case WebAssembly::ATOMIC_STORE_I64: return WebAssembly::ATOMIC_STORE_I64_S;
471 case WebAssembly::BLOCK: return WebAssembly::BLOCK_S;
472 case WebAssembly::BR: return WebAssembly::BR_S;
473 case WebAssembly::BR_IF: return WebAssembly::BR_IF_S;
474 case WebAssembly::BR_TABLE_I32: return WebAssembly::BR_TABLE_I32_S;
475 case WebAssembly::BR_TABLE_I64: return WebAssembly::BR_TABLE_I64_S;
476 case WebAssembly::BR_UNLESS: return WebAssembly::BR_UNLESS_S;
477 case WebAssembly::CALL_EXCEPT_REF: return WebAssembly::CALL_EXCEPT_REF_S;
478 case WebAssembly::CALL_F32: return WebAssembly::CALL_F32_S;
479 case WebAssembly::CALL_F64: return WebAssembly::CALL_F64_S;
480 case WebAssembly::CALL_I32: return WebAssembly::CALL_I32_S;
481 case WebAssembly::CALL_I64: return WebAssembly::CALL_I64_S;
482 case WebAssembly::CALL_INDIRECT_EXCEPT_REF: return WebAssembly::CALL_INDIRECT_EXCEPT_REF_S;
483 case WebAssembly::CALL_INDIRECT_F32: return WebAssembly::CALL_INDIRECT_F32_S;
484 case WebAssembly::CALL_INDIRECT_F64: return WebAssembly::CALL_INDIRECT_F64_S;
485 case WebAssembly::CALL_INDIRECT_I32: return WebAssembly::CALL_INDIRECT_I32_S;
486 case WebAssembly::CALL_INDIRECT_I64: return WebAssembly::CALL_INDIRECT_I64_S;
487 case WebAssembly::CALL_INDIRECT_VOID: return WebAssembly::CALL_INDIRECT_VOID_S;
488 case WebAssembly::CALL_INDIRECT_v16i8: return WebAssembly::CALL_INDIRECT_v16i8_S;
489 case WebAssembly::CALL_INDIRECT_v4f32: return WebAssembly::CALL_INDIRECT_v4f32_S;
490 case WebAssembly::CALL_INDIRECT_v4i32: return WebAssembly::CALL_INDIRECT_v4i32_S;
491 case WebAssembly::CALL_INDIRECT_v8i16: return WebAssembly::CALL_INDIRECT_v8i16_S;
492 case WebAssembly::CALL_VOID: return WebAssembly::CALL_VOID_S;
493 case WebAssembly::CALL_v16i8: return WebAssembly::CALL_v16i8_S;
494 case WebAssembly::CALL_v4f32: return WebAssembly::CALL_v4f32_S;
495 case WebAssembly::CALL_v4i32: return WebAssembly::CALL_v4i32_S;
496 case WebAssembly::CALL_v8i16: return WebAssembly::CALL_v8i16_S;
497 case WebAssembly::CATCHRET: return WebAssembly::CATCHRET_S;
498 case WebAssembly::CATCH_ALL: return WebAssembly::CATCH_ALL_S;
499 case WebAssembly::CATCH_I32: return WebAssembly::CATCH_I32_S;
500 case WebAssembly::CATCH_I64: return WebAssembly::CATCH_I64_S;
501 case WebAssembly::CEIL_F32: return WebAssembly::CEIL_F32_S;
502 case WebAssembly::CEIL_F64: return WebAssembly::CEIL_F64_S;
503 case WebAssembly::CLEANUPRET: return WebAssembly::CLEANUPRET_S;
504 case WebAssembly::CLZ_I32: return WebAssembly::CLZ_I32_S;
505 case WebAssembly::CLZ_I64: return WebAssembly::CLZ_I64_S;
506 case WebAssembly::CONST_F32: return WebAssembly::CONST_F32_S;
507 case WebAssembly::CONST_F64: return WebAssembly::CONST_F64_S;
508 case WebAssembly::CONST_I32: return WebAssembly::CONST_I32_S;
509 case WebAssembly::CONST_I64: return WebAssembly::CONST_I64_S;
510 case WebAssembly::COPYSIGN_F32: return WebAssembly::COPYSIGN_F32_S;
511 case WebAssembly::COPYSIGN_F64: return WebAssembly::COPYSIGN_F64_S;
512 case WebAssembly::COPY_EXCEPT_REF: return WebAssembly::COPY_EXCEPT_REF_S;
513 case WebAssembly::COPY_F32: return WebAssembly::COPY_F32_S;
514 case WebAssembly::COPY_F64: return WebAssembly::COPY_F64_S;
515 case WebAssembly::COPY_I32: return WebAssembly::COPY_I32_S;
516 case WebAssembly::COPY_I64: return WebAssembly::COPY_I64_S;
517 case WebAssembly::COPY_V128: return WebAssembly::COPY_V128_S;
518 case WebAssembly::CTZ_I32: return WebAssembly::CTZ_I32_S;
519 case WebAssembly::CTZ_I64: return WebAssembly::CTZ_I64_S;
520 case WebAssembly::CURRENT_MEMORY_I32: return WebAssembly::CURRENT_MEMORY_I32_S;
521 case WebAssembly::DIV_F32: return WebAssembly::DIV_F32_S;
522 case WebAssembly::DIV_F64: return WebAssembly::DIV_F64_S;
523 case WebAssembly::DIV_S_I32: return WebAssembly::DIV_S_I32_S;
524 case WebAssembly::DIV_S_I64: return WebAssembly::DIV_S_I64_S;
525 case WebAssembly::DIV_U_I32: return WebAssembly::DIV_U_I32_S;
526 case WebAssembly::DIV_U_I64: return WebAssembly::DIV_U_I64_S;
527 case WebAssembly::DROP_EXCEPT_REF: return WebAssembly::DROP_EXCEPT_REF_S;
528 case WebAssembly::DROP_F32: return WebAssembly::DROP_F32_S;
529 case WebAssembly::DROP_F64: return WebAssembly::DROP_F64_S;
530 case WebAssembly::DROP_I32: return WebAssembly::DROP_I32_S;
531 case WebAssembly::DROP_I64: return WebAssembly::DROP_I64_S;
532 case WebAssembly::DROP_V128: return WebAssembly::DROP_V128_S;
533 case WebAssembly::END_BLOCK: return WebAssembly::END_BLOCK_S;
534 case WebAssembly::END_FUNCTION: return WebAssembly::END_FUNCTION_S;
535 case WebAssembly::END_LOOP: return WebAssembly::END_LOOP_S;
536 case WebAssembly::END_TRY: return WebAssembly::END_TRY_S;
537 case WebAssembly::EQZ_I32: return WebAssembly::EQZ_I32_S;
538 case WebAssembly::EQZ_I64: return WebAssembly::EQZ_I64_S;
539 case WebAssembly::EQ_F32: return WebAssembly::EQ_F32_S;
540 case WebAssembly::EQ_F64: return WebAssembly::EQ_F64_S;
541 case WebAssembly::EQ_I32: return WebAssembly::EQ_I32_S;
542 case WebAssembly::EQ_I64: return WebAssembly::EQ_I64_S;
543 case WebAssembly::F32_CONVERT_S_I32: return WebAssembly::F32_CONVERT_S_I32_S;
544 case WebAssembly::F32_CONVERT_S_I64: return WebAssembly::F32_CONVERT_S_I64_S;
545 case WebAssembly::F32_CONVERT_U_I32: return WebAssembly::F32_CONVERT_U_I32_S;
546 case WebAssembly::F32_CONVERT_U_I64: return WebAssembly::F32_CONVERT_U_I64_S;
547 case WebAssembly::F32_DEMOTE_F64: return WebAssembly::F32_DEMOTE_F64_S;
548 case WebAssembly::F32_REINTERPRET_I32: return WebAssembly::F32_REINTERPRET_I32_S;
549 case WebAssembly::F64_CONVERT_S_I32: return WebAssembly::F64_CONVERT_S_I32_S;
550 case WebAssembly::F64_CONVERT_S_I64: return WebAssembly::F64_CONVERT_S_I64_S;
551 case WebAssembly::F64_CONVERT_U_I32: return WebAssembly::F64_CONVERT_U_I32_S;
552 case WebAssembly::F64_CONVERT_U_I64: return WebAssembly::F64_CONVERT_U_I64_S;
553 case WebAssembly::F64_PROMOTE_F32: return WebAssembly::F64_PROMOTE_F32_S;
554 case WebAssembly::F64_REINTERPRET_I64: return WebAssembly::F64_REINTERPRET_I64_S;
555 case WebAssembly::FALLTHROUGH_RETURN_EXCEPT_REF: return WebAssembly::FALLTHROUGH_RETURN_EXCEPT_REF_S;
556 case WebAssembly::FALLTHROUGH_RETURN_F32: return WebAssembly::FALLTHROUGH_RETURN_F32_S;
557 case WebAssembly::FALLTHROUGH_RETURN_F64: return WebAssembly::FALLTHROUGH_RETURN_F64_S;
558 case WebAssembly::FALLTHROUGH_RETURN_I32: return WebAssembly::FALLTHROUGH_RETURN_I32_S;
559 case WebAssembly::FALLTHROUGH_RETURN_I64: return WebAssembly::FALLTHROUGH_RETURN_I64_S;
560 case WebAssembly::FALLTHROUGH_RETURN_VOID: return WebAssembly::FALLTHROUGH_RETURN_VOID_S;
561 case WebAssembly::FALLTHROUGH_RETURN_v16i8: return WebAssembly::FALLTHROUGH_RETURN_v16i8_S;
562 case WebAssembly::FALLTHROUGH_RETURN_v4f32: return WebAssembly::FALLTHROUGH_RETURN_v4f32_S;
563 case WebAssembly::FALLTHROUGH_RETURN_v4i32: return WebAssembly::FALLTHROUGH_RETURN_v4i32_S;
564 case WebAssembly::FALLTHROUGH_RETURN_v8i16: return WebAssembly::FALLTHROUGH_RETURN_v8i16_S;
565 case WebAssembly::FLOOR_F32: return WebAssembly::FLOOR_F32_S;
566 case WebAssembly::FLOOR_F64: return WebAssembly::FLOOR_F64_S;
567 case WebAssembly::FP_TO_SINT_I32_F32: return WebAssembly::FP_TO_SINT_I32_F32_S;
568 case WebAssembly::FP_TO_SINT_I32_F64: return WebAssembly::FP_TO_SINT_I32_F64_S;
569 case WebAssembly::FP_TO_SINT_I64_F32: return WebAssembly::FP_TO_SINT_I64_F32_S;
570 case WebAssembly::FP_TO_SINT_I64_F64: return WebAssembly::FP_TO_SINT_I64_F64_S;
571 case WebAssembly::FP_TO_UINT_I32_F32: return WebAssembly::FP_TO_UINT_I32_F32_S;
572 case WebAssembly::FP_TO_UINT_I32_F64: return WebAssembly::FP_TO_UINT_I32_F64_S;
573 case WebAssembly::FP_TO_UINT_I64_F32: return WebAssembly::FP_TO_UINT_I64_F32_S;
574 case WebAssembly::FP_TO_UINT_I64_F64: return WebAssembly::FP_TO_UINT_I64_F64_S;
575 case WebAssembly::GET_GLOBAL_EXCEPT_REF: return WebAssembly::GET_GLOBAL_EXCEPT_REF_S;
576 case WebAssembly::GET_GLOBAL_F32: return WebAssembly::GET_GLOBAL_F32_S;
577 case WebAssembly::GET_GLOBAL_F64: return WebAssembly::GET_GLOBAL_F64_S;
578 case WebAssembly::GET_GLOBAL_I32: return WebAssembly::GET_GLOBAL_I32_S;
579 case WebAssembly::GET_GLOBAL_I64: return WebAssembly::GET_GLOBAL_I64_S;
580 case WebAssembly::GET_GLOBAL_V128: return WebAssembly::GET_GLOBAL_V128_S;
581 case WebAssembly::GET_LOCAL_EXCEPT_REF: return WebAssembly::GET_LOCAL_EXCEPT_REF_S;
582 case WebAssembly::GET_LOCAL_F32: return WebAssembly::GET_LOCAL_F32_S;
583 case WebAssembly::GET_LOCAL_F64: return WebAssembly::GET_LOCAL_F64_S;
584 case WebAssembly::GET_LOCAL_I32: return WebAssembly::GET_LOCAL_I32_S;
585 case WebAssembly::GET_LOCAL_I64: return WebAssembly::GET_LOCAL_I64_S;
586 case WebAssembly::GET_LOCAL_V128: return WebAssembly::GET_LOCAL_V128_S;
587 case WebAssembly::GE_F32: return WebAssembly::GE_F32_S;
588 case WebAssembly::GE_F64: return WebAssembly::GE_F64_S;
589 case WebAssembly::GE_S_I32: return WebAssembly::GE_S_I32_S;
590 case WebAssembly::GE_S_I64: return WebAssembly::GE_S_I64_S;
591 case WebAssembly::GE_U_I32: return WebAssembly::GE_U_I32_S;
592 case WebAssembly::GE_U_I64: return WebAssembly::GE_U_I64_S;
593 case WebAssembly::GROW_MEMORY_I32: return WebAssembly::GROW_MEMORY_I32_S;
594 case WebAssembly::GT_F32: return WebAssembly::GT_F32_S;
595 case WebAssembly::GT_F64: return WebAssembly::GT_F64_S;
596 case WebAssembly::GT_S_I32: return WebAssembly::GT_S_I32_S;
597 case WebAssembly::GT_S_I64: return WebAssembly::GT_S_I64_S;
598 case WebAssembly::GT_U_I32: return WebAssembly::GT_U_I32_S;
599 case WebAssembly::GT_U_I64: return WebAssembly::GT_U_I64_S;
600 case WebAssembly::I32_EXTEND16_S_I32: return WebAssembly::I32_EXTEND16_S_I32_S;
601 case WebAssembly::I32_EXTEND8_S_I32: return WebAssembly::I32_EXTEND8_S_I32_S;
602 case WebAssembly::I32_REINTERPRET_F32: return WebAssembly::I32_REINTERPRET_F32_S;
603 case WebAssembly::I32_TRUNC_S_F32: return WebAssembly::I32_TRUNC_S_F32_S;
604 case WebAssembly::I32_TRUNC_S_F64: return WebAssembly::I32_TRUNC_S_F64_S;
605 case WebAssembly::I32_TRUNC_S_SAT_F32: return WebAssembly::I32_TRUNC_S_SAT_F32_S;
606 case WebAssembly::I32_TRUNC_S_SAT_F64: return WebAssembly::I32_TRUNC_S_SAT_F64_S;
607 case WebAssembly::I32_TRUNC_U_F32: return WebAssembly::I32_TRUNC_U_F32_S;
608 case WebAssembly::I32_TRUNC_U_F64: return WebAssembly::I32_TRUNC_U_F64_S;
609 case WebAssembly::I32_TRUNC_U_SAT_F32: return WebAssembly::I32_TRUNC_U_SAT_F32_S;
610 case WebAssembly::I32_TRUNC_U_SAT_F64: return WebAssembly::I32_TRUNC_U_SAT_F64_S;
611 case WebAssembly::I32_WRAP_I64: return WebAssembly::I32_WRAP_I64_S;
612 case WebAssembly::I64_EXTEND16_S_I64: return WebAssembly::I64_EXTEND16_S_I64_S;
613 case WebAssembly::I64_EXTEND32_S_I64: return WebAssembly::I64_EXTEND32_S_I64_S;
614 case WebAssembly::I64_EXTEND8_S_I64: return WebAssembly::I64_EXTEND8_S_I64_S;
615 case WebAssembly::I64_EXTEND_S_I32: return WebAssembly::I64_EXTEND_S_I32_S;
616 case WebAssembly::I64_EXTEND_U_I32: return WebAssembly::I64_EXTEND_U_I32_S;
617 case WebAssembly::I64_REINTERPRET_F64: return WebAssembly::I64_REINTERPRET_F64_S;
618 case WebAssembly::I64_TRUNC_S_F32: return WebAssembly::I64_TRUNC_S_F32_S;
619 case WebAssembly::I64_TRUNC_S_F64: return WebAssembly::I64_TRUNC_S_F64_S;
620 case WebAssembly::I64_TRUNC_S_SAT_F32: return WebAssembly::I64_TRUNC_S_SAT_F32_S;
621 case WebAssembly::I64_TRUNC_S_SAT_F64: return WebAssembly::I64_TRUNC_S_SAT_F64_S;
622 case WebAssembly::I64_TRUNC_U_F32: return WebAssembly::I64_TRUNC_U_F32_S;
623 case WebAssembly::I64_TRUNC_U_F64: return WebAssembly::I64_TRUNC_U_F64_S;
624 case WebAssembly::I64_TRUNC_U_SAT_F32: return WebAssembly::I64_TRUNC_U_SAT_F32_S;
625 case WebAssembly::I64_TRUNC_U_SAT_F64: return WebAssembly::I64_TRUNC_U_SAT_F64_S;
626 case WebAssembly::LE_F32: return WebAssembly::LE_F32_S;
627 case WebAssembly::LE_F64: return WebAssembly::LE_F64_S;
628 case WebAssembly::LE_S_I32: return WebAssembly::LE_S_I32_S;
629 case WebAssembly::LE_S_I64: return WebAssembly::LE_S_I64_S;
630 case WebAssembly::LE_U_I32: return WebAssembly::LE_U_I32_S;
631 case WebAssembly::LE_U_I64: return WebAssembly::LE_U_I64_S;
632 case WebAssembly::LOAD16_S_I32: return WebAssembly::LOAD16_S_I32_S;
633 case WebAssembly::LOAD16_S_I64: return WebAssembly::LOAD16_S_I64_S;
634 case WebAssembly::LOAD16_U_I32: return WebAssembly::LOAD16_U_I32_S;
635 case WebAssembly::LOAD16_U_I64: return WebAssembly::LOAD16_U_I64_S;
636 case WebAssembly::LOAD32_S_I64: return WebAssembly::LOAD32_S_I64_S;
637 case WebAssembly::LOAD32_U_I64: return WebAssembly::LOAD32_U_I64_S;
638 case WebAssembly::LOAD8_S_I32: return WebAssembly::LOAD8_S_I32_S;
639 case WebAssembly::LOAD8_S_I64: return WebAssembly::LOAD8_S_I64_S;
640 case WebAssembly::LOAD8_U_I32: return WebAssembly::LOAD8_U_I32_S;
641 case WebAssembly::LOAD8_U_I64: return WebAssembly::LOAD8_U_I64_S;
642 case WebAssembly::LOAD_F32: return WebAssembly::LOAD_F32_S;
643 case WebAssembly::LOAD_F64: return WebAssembly::LOAD_F64_S;
644 case WebAssembly::LOAD_I32: return WebAssembly::LOAD_I32_S;
645 case WebAssembly::LOAD_I64: return WebAssembly::LOAD_I64_S;
646 case WebAssembly::LOOP: return WebAssembly::LOOP_S;
647 case WebAssembly::LT_F32: return WebAssembly::LT_F32_S;
648 case WebAssembly::LT_F64: return WebAssembly::LT_F64_S;
649 case WebAssembly::LT_S_I32: return WebAssembly::LT_S_I32_S;
650 case WebAssembly::LT_S_I64: return WebAssembly::LT_S_I64_S;
651 case WebAssembly::LT_U_I32: return WebAssembly::LT_U_I32_S;
652 case WebAssembly::LT_U_I64: return WebAssembly::LT_U_I64_S;
653 case WebAssembly::MAX_F32: return WebAssembly::MAX_F32_S;
654 case WebAssembly::MAX_F64: return WebAssembly::MAX_F64_S;
655 case WebAssembly::MEMORY_GROW_I32: return WebAssembly::MEMORY_GROW_I32_S;
656 case WebAssembly::MEMORY_SIZE_I32: return WebAssembly::MEMORY_SIZE_I32_S;
657 case WebAssembly::MEM_GROW_I32: return WebAssembly::MEM_GROW_I32_S;
658 case WebAssembly::MEM_SIZE_I32: return WebAssembly::MEM_SIZE_I32_S;
659 case WebAssembly::MIN_F32: return WebAssembly::MIN_F32_S;
660 case WebAssembly::MIN_F64: return WebAssembly::MIN_F64_S;
661 case WebAssembly::MUL_F32: return WebAssembly::MUL_F32_S;
662 case WebAssembly::MUL_F32x4: return WebAssembly::MUL_F32x4_S;
663 case WebAssembly::MUL_F64: return WebAssembly::MUL_F64_S;
664 case WebAssembly::MUL_I16x8: return WebAssembly::MUL_I16x8_S;
665 case WebAssembly::MUL_I32: return WebAssembly::MUL_I32_S;
666 case WebAssembly::MUL_I32x4: return WebAssembly::MUL_I32x4_S;
667 case WebAssembly::MUL_I64: return WebAssembly::MUL_I64_S;
668 case WebAssembly::MUL_I8x16: return WebAssembly::MUL_I8x16_S;
669 case WebAssembly::NEAREST_F32: return WebAssembly::NEAREST_F32_S;
670 case WebAssembly::NEAREST_F64: return WebAssembly::NEAREST_F64_S;
671 case WebAssembly::NEG_F32: return WebAssembly::NEG_F32_S;
672 case WebAssembly::NEG_F64: return WebAssembly::NEG_F64_S;
673 case WebAssembly::NE_F32: return WebAssembly::NE_F32_S;
674 case WebAssembly::NE_F64: return WebAssembly::NE_F64_S;
675 case WebAssembly::NE_I32: return WebAssembly::NE_I32_S;
676 case WebAssembly::NE_I64: return WebAssembly::NE_I64_S;
677 case WebAssembly::NOP: return WebAssembly::NOP_S;
678 case WebAssembly::OR_I32: return WebAssembly::OR_I32_S;
679 case WebAssembly::OR_I64: return WebAssembly::OR_I64_S;
680 case WebAssembly::PCALL_INDIRECT_EXCEPT_REF: return WebAssembly::PCALL_INDIRECT_EXCEPT_REF_S;
681 case WebAssembly::PCALL_INDIRECT_F32: return WebAssembly::PCALL_INDIRECT_F32_S;
682 case WebAssembly::PCALL_INDIRECT_F64: return WebAssembly::PCALL_INDIRECT_F64_S;
683 case WebAssembly::PCALL_INDIRECT_I32: return WebAssembly::PCALL_INDIRECT_I32_S;
684 case WebAssembly::PCALL_INDIRECT_I64: return WebAssembly::PCALL_INDIRECT_I64_S;
685 case WebAssembly::PCALL_INDIRECT_VOID: return WebAssembly::PCALL_INDIRECT_VOID_S;
686 case WebAssembly::PCALL_INDIRECT_v16i8: return WebAssembly::PCALL_INDIRECT_v16i8_S;
687 case WebAssembly::PCALL_INDIRECT_v4f32: return WebAssembly::PCALL_INDIRECT_v4f32_S;
688 case WebAssembly::PCALL_INDIRECT_v4i32: return WebAssembly::PCALL_INDIRECT_v4i32_S;
689 case WebAssembly::PCALL_INDIRECT_v8i16: return WebAssembly::PCALL_INDIRECT_v8i16_S;
690 case WebAssembly::POPCNT_I32: return WebAssembly::POPCNT_I32_S;
691 case WebAssembly::POPCNT_I64: return WebAssembly::POPCNT_I64_S;
692 case WebAssembly::REM_S_I32: return WebAssembly::REM_S_I32_S;
693 case WebAssembly::REM_S_I64: return WebAssembly::REM_S_I64_S;
694 case WebAssembly::REM_U_I32: return WebAssembly::REM_U_I32_S;
695 case WebAssembly::REM_U_I64: return WebAssembly::REM_U_I64_S;
696 case WebAssembly::RETHROW: return WebAssembly::RETHROW_S;
697 case WebAssembly::RETHROW_TO_CALLER: return WebAssembly::RETHROW_TO_CALLER_S;
698 case WebAssembly::RETURN_EXCEPT_REF: return WebAssembly::RETURN_EXCEPT_REF_S;
699 case WebAssembly::RETURN_F32: return WebAssembly::RETURN_F32_S;
700 case WebAssembly::RETURN_F64: return WebAssembly::RETURN_F64_S;
701 case WebAssembly::RETURN_I32: return WebAssembly::RETURN_I32_S;
702 case WebAssembly::RETURN_I64: return WebAssembly::RETURN_I64_S;
703 case WebAssembly::RETURN_VOID: return WebAssembly::RETURN_VOID_S;
704 case WebAssembly::RETURN_v16i8: return WebAssembly::RETURN_v16i8_S;
705 case WebAssembly::RETURN_v4f32: return WebAssembly::RETURN_v4f32_S;
706 case WebAssembly::RETURN_v4i32: return WebAssembly::RETURN_v4i32_S;
707 case WebAssembly::RETURN_v8i16: return WebAssembly::RETURN_v8i16_S;
708 case WebAssembly::ROTL_I32: return WebAssembly::ROTL_I32_S;
709 case WebAssembly::ROTL_I64: return WebAssembly::ROTL_I64_S;
710 case WebAssembly::ROTR_I32: return WebAssembly::ROTR_I32_S;
711 case WebAssembly::ROTR_I64: return WebAssembly::ROTR_I64_S;
712 case WebAssembly::SELECT_EXCEPT_REF: return WebAssembly::SELECT_EXCEPT_REF_S;
713 case WebAssembly::SELECT_F32: return WebAssembly::SELECT_F32_S;
714 case WebAssembly::SELECT_F64: return WebAssembly::SELECT_F64_S;
715 case WebAssembly::SELECT_I32: return WebAssembly::SELECT_I32_S;
716 case WebAssembly::SELECT_I64: return WebAssembly::SELECT_I64_S;
717 case WebAssembly::SET_GLOBAL_EXCEPT_REF: return WebAssembly::SET_GLOBAL_EXCEPT_REF_S;
718 case WebAssembly::SET_GLOBAL_F32: return WebAssembly::SET_GLOBAL_F32_S;
719 case WebAssembly::SET_GLOBAL_F64: return WebAssembly::SET_GLOBAL_F64_S;
720 case WebAssembly::SET_GLOBAL_I32: return WebAssembly::SET_GLOBAL_I32_S;
721 case WebAssembly::SET_GLOBAL_I64: return WebAssembly::SET_GLOBAL_I64_S;
722 case WebAssembly::SET_GLOBAL_V128: return WebAssembly::SET_GLOBAL_V128_S;
723 case WebAssembly::SET_LOCAL_EXCEPT_REF: return WebAssembly::SET_LOCAL_EXCEPT_REF_S;
724 case WebAssembly::SET_LOCAL_F32: return WebAssembly::SET_LOCAL_F32_S;
725 case WebAssembly::SET_LOCAL_F64: return WebAssembly::SET_LOCAL_F64_S;
726 case WebAssembly::SET_LOCAL_I32: return WebAssembly::SET_LOCAL_I32_S;
727 case WebAssembly::SET_LOCAL_I64: return WebAssembly::SET_LOCAL_I64_S;
728 case WebAssembly::SET_LOCAL_V128: return WebAssembly::SET_LOCAL_V128_S;
729 case WebAssembly::SHL_I32: return WebAssembly::SHL_I32_S;
730 case WebAssembly::SHL_I64: return WebAssembly::SHL_I64_S;
731 case WebAssembly::SHR_S_I32: return WebAssembly::SHR_S_I32_S;
732 case WebAssembly::SHR_S_I64: return WebAssembly::SHR_S_I64_S;
733 case WebAssembly::SHR_U_I32: return WebAssembly::SHR_U_I32_S;
734 case WebAssembly::SHR_U_I64: return WebAssembly::SHR_U_I64_S;
735 case WebAssembly::SQRT_F32: return WebAssembly::SQRT_F32_S;
736 case WebAssembly::SQRT_F64: return WebAssembly::SQRT_F64_S;
737 case WebAssembly::STORE16_I32: return WebAssembly::STORE16_I32_S;
738 case WebAssembly::STORE16_I64: return WebAssembly::STORE16_I64_S;
739 case WebAssembly::STORE32_I64: return WebAssembly::STORE32_I64_S;
740 case WebAssembly::STORE8_I32: return WebAssembly::STORE8_I32_S;
741 case WebAssembly::STORE8_I64: return WebAssembly::STORE8_I64_S;
742 case WebAssembly::STORE_F32: return WebAssembly::STORE_F32_S;
743 case WebAssembly::STORE_F64: return WebAssembly::STORE_F64_S;
744 case WebAssembly::STORE_I32: return WebAssembly::STORE_I32_S;
745 case WebAssembly::STORE_I64: return WebAssembly::STORE_I64_S;
746 case WebAssembly::SUB_F32: return WebAssembly::SUB_F32_S;
747 case WebAssembly::SUB_F32x4: return WebAssembly::SUB_F32x4_S;
748 case WebAssembly::SUB_F64: return WebAssembly::SUB_F64_S;
749 case WebAssembly::SUB_I16x8: return WebAssembly::SUB_I16x8_S;
750 case WebAssembly::SUB_I32: return WebAssembly::SUB_I32_S;
751 case WebAssembly::SUB_I32x4: return WebAssembly::SUB_I32x4_S;
752 case WebAssembly::SUB_I64: return WebAssembly::SUB_I64_S;
753 case WebAssembly::SUB_I8x16: return WebAssembly::SUB_I8x16_S;
754 case WebAssembly::TEE_EXCEPT_REF: return WebAssembly::TEE_EXCEPT_REF_S;
755 case WebAssembly::TEE_F32: return WebAssembly::TEE_F32_S;
756 case WebAssembly::TEE_F64: return WebAssembly::TEE_F64_S;
757 case WebAssembly::TEE_I32: return WebAssembly::TEE_I32_S;
758 case WebAssembly::TEE_I64: return WebAssembly::TEE_I64_S;
759 case WebAssembly::TEE_LOCAL_EXCEPT_REF: return WebAssembly::TEE_LOCAL_EXCEPT_REF_S;
760 case WebAssembly::TEE_LOCAL_F32: return WebAssembly::TEE_LOCAL_F32_S;
761 case WebAssembly::TEE_LOCAL_F64: return WebAssembly::TEE_LOCAL_F64_S;
762 case WebAssembly::TEE_LOCAL_I32: return WebAssembly::TEE_LOCAL_I32_S;
763 case WebAssembly::TEE_LOCAL_I64: return WebAssembly::TEE_LOCAL_I64_S;
764 case WebAssembly::TEE_LOCAL_V128: return WebAssembly::TEE_LOCAL_V128_S;
765 case WebAssembly::TEE_V128: return WebAssembly::TEE_V128_S;
766 case WebAssembly::THROW_I32: return WebAssembly::THROW_I32_S;
767 case WebAssembly::THROW_I64: return WebAssembly::THROW_I64_S;
768 case WebAssembly::TRUNC_F32: return WebAssembly::TRUNC_F32_S;
769 case WebAssembly::TRUNC_F64: return WebAssembly::TRUNC_F64_S;
770 case WebAssembly::TRY: return WebAssembly::TRY_S;
771 case WebAssembly::UNREACHABLE: return WebAssembly::UNREACHABLE_S;
772 case WebAssembly::XOR_I32: return WebAssembly::XOR_I32_S;
773 case WebAssembly::XOR_I64: return WebAssembly::XOR_I64_S;
387774 }
388 #endif
389
390 return Changed;
391 }
775 }
5656
5757 // Defines atomic and non-atomic loads, regular and extending.
5858 multiclass WebAssemblyLoad {
59 let mayLoad = 1 in
5960 defm "": I<(outs rc:$dst),
6061 (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
6162 (outs), (ins P2Align:$p2align, offset32_op:$off),
6263 [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
63 !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
64 !strconcat(Name, "\t${off}${p2align}"), Opcode>;
6465 }
6566
6667 // Basic load.
306307
307308 // Defines atomic and non-atomic stores, regular and truncating
308309 multiclass WebAssemblyStore {
310 let mayStore = 1 in
309311 defm "" : I<(outs),
310312 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
311313 (outs),
312314 (ins P2Align:$p2align, offset32_op:$off), [],
313315 !strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
314 !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
316 !strconcat(Name, "\t${off}${p2align}"), Opcode>;
315317 }
316318 // Basic store.
317319 // Note: WebAssembly inverts SelectionDAG's usual operand order.
469471
470472 // Grow memory.
471473 defm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
472 (outs), (ins i32imm:$flags, I32:$delta),
474 (outs), (ins i32imm:$flags),
473475 [(set I32:$dst,
474476 (int_wasm_memory_grow (i32 imm:$flags),
475477 I32:$delta))],
476478 "memory.grow\t$dst, $flags, $delta",
477 "memory.grow\t$flags, $delta", 0x3f>,
479 "memory.grow\t$flags", 0x3f>,
478480 Requires<[HasAddr32]>;
479481 defm MEM_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
480482 (outs), (ins i32imm:$flags),
316316 // converted into a local.
317317 addPass(createWebAssemblyFixIrreducibleControlFlow());
318318
319 // Insert explicit get_local and set_local operators.
320 addPass(createWebAssemblyExplicitLocals());
321
322319 // Do various transformations for exception handling
323320 addPass(createWebAssemblyLateEHPrepare());
324321
336333 if (getOptLevel() != CodeGenOpt::None)
337334 addPass(createWebAssemblyPeephole());
338335
336 // Insert explicit get_local and set_local operators.
337 addPass(createWebAssemblyExplicitLocals());
338
339339 // Create a mapping from LLVM CodeGen virtual registers to wasm registers.
340340 addPass(createWebAssemblyRegNumbering());
341341 }
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test folding constant offsets and symbols into load and store addresses under
33 ; a variety of circumstances.
None ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+atomics,+sign-ext | FileCheck %s
0 ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -mattr=+atomics,+sign-ext | FileCheck %s
22
33 ; Test atomic RMW (read-modify-write) instructions are assembled properly.
44
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -verify-machineinstrs | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -verify-machineinstrs -fast-isel | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -verify-machineinstrs | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -verify-machineinstrs -fast-isel | FileCheck %s
22
33 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
44 target triple = "wasm32-unknown-unknown"
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-temporary-workarounds=false | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -fast-isel -fast-isel-abort=1 -wasm-temporary-workarounds=false | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -wasm-temporary-workarounds=false | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -fast-isel -fast-isel-abort=1 -wasm-temporary-workarounds=false | FileCheck %s
22
33 ; Test that basic call operations assemble as expected.
44
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -tail-dup-placement=0 -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 | FileCheck -check-prefix=OPT %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -tail-dup-placement=0 -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 | FileCheck -check-prefix=OPT %s
22
33 ; Test the CFG stackifier pass.
44
None ; RUN: opt -S -lowertypetests < %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: opt -S -lowertypetests < %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Tests that we correctly assign indexes for control flow integrity.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that basic 32-bit floating-point comparison operations assemble as
33 ; expected.
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that basic 64-bit floating-point comparison operations assemble as
33 ; expected.
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -fast-isel -fast-isel-abort=1 | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -fast-isel -fast-isel-abort=1 | FileCheck %s
22
33 ; Test that basic 32-bit integer comparison operations assemble as expected.
44
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -fast-isel -fast-isel-abort=1 | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -fast-isel -fast-isel-abort=1 | FileCheck %s
22
33 ; Test that basic 64-bit integer comparison operations assemble as expected.
44
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=-nontrapping-fptoint | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -mattr=-nontrapping-fptoint | FileCheck %s
11
22 ; Test that basic conversion operations assemble as expected using
33 ; the trapping opcodes and explicit code to suppress the trapping.
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+nontrapping-fptoint | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -mattr=+nontrapping-fptoint | FileCheck %s
11
22 ; Test that basic conversion operations assemble as expected.
33
None ; RUN: llc < %s -asm-verbose=false | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; DAGCombiner oddly folds casts into the rhs of copysign. Test that they get
33 ; unfolded.
None ; RUN: llc < %s -asm-verbose=false | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that integer div and rem by constant are optimized appropriately.
33
None ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -exception-model=wasm
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -exception-model=wasm -mattr=+exception-handling | FileCheck -allow-deprecated-dag-overlap %s
0 ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -exception-model=wasm
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -exception-model=wasm -mattr=+exception-handling | FileCheck -allow-deprecated-dag-overlap %s
22
33 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
44 target triple = "wasm32-unknown-unknown"
None # RUN: llc -mtriple=wasm32-unknown-unknown -run-pass wasm-explicit-locals %s -o - | FileCheck %s
0 # RUN: llc -mtriple=wasm32-unknown-unknown -run-pass wasm-explicit-locals -wasm-explicit-locals-codegen-test-mode %s -o - | FileCheck %s
11
22 # When a drop instruction is inserted to drop a dead register operand, the
33 # original operand should be marked not dead anymore because it is now used by
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -fast-isel | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -fast-isel | FileCheck %s
22
33 ; Test that f16 is expanded.
44
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that basic 32-bit floating-point operations assemble as expected.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that basic 64-bit floating-point operations assemble as expected.
33
None ; RUN: llc < %s -fast-isel -asm-verbose=false | FileCheck %s
0 ; RUN: llc < %s -fast-isel -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
33 target triple = "wasm32-unknown-unknown"
None ; RUN: llc < %s -O0
0 ; RUN: llc < %s -O0 -wasm-explicit-locals-codegen-test-mode
11 ; PR36564
22 ; PR37546
33
None ; RUN: llc < %s -O0
0 ; RUN: llc < %s -O0 -wasm-explicit-locals-codegen-test-mode
11 ; PR36564
22 ; PR37546
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -verify-machineinstrs | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -fast-isel -verify-machineinstrs | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -verify-machineinstrs | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode -fast-isel -verify-machineinstrs | FileCheck %s
22
33 ; Test that FastISel does not generate instructions with NoReg
44
0 ; RUN: llc < %s -asm-verbose=false \
11 ; RUN: -fast-isel -fast-isel-abort=1 -verify-machineinstrs \
2 ; RUN: -disable-wasm-explicit-locals \
2 ; RUN: -wasm-register-codegen-test-mode \
33 ; RUN: | FileCheck %s
44
55 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test that the frem instruction works.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test that basic functions assemble as expected.
33
None ; RUN: llc < %s -asm-verbose=false -wasm-temporary-workarounds=false | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-temporary-workarounds=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that function pointer casts casting away varargs are replaced with
33 ; wrappers.
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals -enable-emscripten-cxx-exceptions -wasm-temporary-workarounds=false | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode -enable-emscripten-cxx-exceptions -wasm-temporary-workarounds=false | FileCheck %s
11
22 ; Test that function pointer casts are replaced with wrappers.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test that globals assemble as expected.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that basic 128-bit integer operations assemble as expected.
33
None ; RUN: llc < %s -mattr=+atomics -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -mattr=+atomics -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test loads and stores with custom alignment values.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that basic 32-bit integer operations assemble as expected.
33
None ; RUN: llc < %s -mattr=+atomics -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -mattr=+atomics -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test loads and stores with custom alignment values.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that basic 64-bit integer operations assemble as expected.
33
None ; RUN: llc < %s -asm-verbose=false | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test llvm.ident.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that basic immediates assemble as expected.
33
None ; RUN: llc -o - %s -asm-verbose=false | FileCheck %s
0 ; RUN: llc -o - %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
22 target triple = "wasm32-unknown-unknown"
33
None ; RUN: llc < %s -asm-verbose=false | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
33 target triple = "wasm32-unknown-unknown"
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -verify-machineinstrs | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -verify-machineinstrs -fast-isel | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -verify-machineinstrs | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -verify-machineinstrs -fast-isel | FileCheck %s
22
33 ; ModuleID = 'test/dot_s/indirect-import.c'
44 source_filename = "test/dot_s/indirect-import.c"
None ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -no-integrated-as
0 ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -no-integrated-as
11
22 ; Test basic inline assembly "m" operands, which are unsupported. Pass
33 ; -no-integrated-as since these aren't actually valid assembly syntax.
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -no-integrated-as | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -no-integrated-as | FileCheck %s
11
22 ; Test basic inline assembly. Pass -no-integrated-as since these aren't
33 ; actually valid assembly syntax.
None ; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-block-placement -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-block-placement -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test irreducible CFG handling.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test various types and operators that need to be legalized.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test a subset of compiler-rt/libm libcalls expected to be emitted by the wasm backend
33
None ; RUN: llc < %s -mattr=+atomics,+sign-ext -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -mattr=+atomics,+sign-ext -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test that extending loads are assembled properly.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test that extending loads are assembled properly.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test that i1 extending loads and truncating stores are assembled properly.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -fast-isel -fast-isel-abort=1 | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -fast-isel -fast-isel-abort=1 | FileCheck %s
22
33 ; Test that basic loads are assembled properly.
44
3838 %arraydecay1 = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
3939 call void @longjmp(%struct.__jmp_buf_tag* %arraydecay1, i32 1) #1
4040 unreachable
41 ; SJLJ: i32.call ${{[a-zA-Z0-9]+}}=, saveSetjmp@FUNCTION
42 ; SJLJ: i32.call ${{[a-zA-Z0-9]+}}=, testSetjmp@FUNCTION
43 ; NONE: i32.call ${{[a-zA-Z0-9]+}}=, setjmp@FUNCTION
41 ; SJLJ: i32.call saveSetjmp@FUNCTION
42 ; SJLJ: i32.call testSetjmp@FUNCTION
43 ; NONE: i32.call setjmp@FUNCTION
4444 ; NONE: call longjmp@FUNCTION
4545 }
4646
None ; RUN: llc < %s -asm-verbose=false | FileCheck --check-prefix=CHECK --check-prefix=FINI --check-prefix=NULL %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck --check-prefix=CHECK --check-prefix=FINI --check-prefix=NULL %s
11
22 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
33 target triple = "wasm32-unknown-unknown"
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -tail-dup-placement=0 | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -tail-dup-placement=0 | FileCheck %s
11
22 ; Test memcpy, memmove, and memset intrinsics.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test that basic memory operations assemble as expected with 32-bit addresses.
33
None ; RUN: llc -asm-verbose=false < %s | FileCheck %s
0 ; RUN: llc -asm-verbose=false < %s -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that 128-bit smul.with.overflow assembles as expected.
33
None ; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
33 target triple = "wasm32-unknown-unknown"
0 ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+atomics,+sign-ext | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -mattr=+atomics,+sign-ext | FileCheck %s
22
33 ; Test that atomic loads are assembled properly.
44
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals -fast-isel -fast-isel-abort=1 | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode -fast-isel -fast-isel-abort=1 | FileCheck %s
11
22 ; TODO: Merge this with offset.ll when fast-isel matches better.
33
None ; RUN: llc < %s -asm-verbose=false | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that constant offsets can be folded into global addresses.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode -disable-wasm-fallthrough-return-opt | FileCheck %s
11
22 ; Test constant load and store address offsets.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -verify-machineinstrs | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -verify-machineinstrs | FileCheck %s
11
22 ; Test that phis are lowered.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -verify-machineinstrs | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -verify-machineinstrs | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -verify-machineinstrs | FileCheck %s --check-prefix=NOREGS
12
23 ; Test the register stackifier pass.
4
5 ; We have two sets of tests, one with registers and implicit locals, and
6 ; a stack / explicit locals based version (NOREGS).
37
48 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
59 target triple = "wasm32-unknown-unknown"
812
913 ; CHECK-LABEL: no0:
1014 ; CHECK: return $1{{$}}
15 ; NOREGS-LABEL: no0:
16 ; NOREGS: return{{$}}
1117 define i32 @no0(i32* %p, i32* %q) {
1218 %t = load i32, i32* %q
1319 store i32 0, i32* %p
1824
1925 ; CHECK-LABEL: no1:
2026 ; CHECK: return $1{{$}}
27 ; NOREGS-LABEL: no1:
28 ; NOREGS: return{{$}}
2129 define i32 @no1(i32* %p, i32* dereferenceable(4) %q) {
2230 %t = load volatile i32, i32* %q, !invariant.load !0
2331 store volatile i32 0, i32* %p
2836
2937 ; CHECK-LABEL: yes0:
3038 ; CHECK: return $pop{{[0-9]+}}{{$}}
39 ; NOREGS-LABEL: yes0:
40 ; NOREGS: return{{$}}
3141 define i32 @yes0(i32* %p, i32* dereferenceable(4) %q) {
3242 %t = load i32, i32* %q, !invariant.load !0
3343 store i32 0, i32* %p
3848
3949 ; CHECK-LABEL: yes1:
4050 ; CHECK: return $pop0{{$}}
51 ; NOREGS-LABEL: yes1:
52 ; NOREGS: return{{$}}
4153 define i32 @yes1(i32* %q) {
4254 %t = load volatile i32, i32* %q
4355 ret i32 %t
4759
4860 ; CHECK-LABEL: sink_trap:
4961 ; CHECK: return $pop{{[0-9]+}}{{$}}
62 ; NOREGS-LABEL: sink_trap:
63 ; NOREGS: return{{$}}
5064 define i32 @sink_trap(i32 %x, i32 %y, i32* %p) {
5165 %t = sdiv i32 %x, %y
5266 store volatile i32 0, i32* %p
5771
5872 ; CHECK-LABEL: sink_readnone_call:
5973 ; CHECK: return $pop0{{$}}
74 ; NOREGS-LABEL: sink_readnone_call:
75 ; NOREGS: return{{$}}
6076 declare i32 @readnone_callee() readnone nounwind
6177 define i32 @sink_readnone_call(i32 %x, i32 %y, i32* %p) {
6278 %t = call i32 @readnone_callee()
6884
6985 ; CHECK-LABEL: no_sink_readonly_call:
7086 ; CHECK: return ${{[0-9]+}}{{$}}
87 ; NOREGS-LABEL: no_sink_readonly_call:
88 ; NOREGS: return{{$}}
7189 declare i32 @readonly_callee() readonly nounwind
7290 define i32 @no_sink_readonly_call(i32 %x, i32 %y, i32* %p) {
7391 %t = call i32 @readonly_callee()
104122 ; CHECK-NEXT: end_block{{$}}
105123 ; CHECK-NEXT: i32.const $push14=, 1{{$}}
106124 ; CHECK-NEXT: return $pop14{{$}}
125 ; NOREGS-LABEL: stack_uses:
126 ; NOREGS: .param i32, i32, i32, i32{{$}}
127 ; NOREGS-NEXT: .result i32{{$}}
128 ; NOREGS-NEXT: block {{$}}
129 ; NOREGS-NEXT: get_local 0{{$}}
130 ; NOREGS-NEXT: i32.const 1{{$}}
131 ; NOREGS-NEXT: i32.lt_s
132 ; NOREGS-NEXT: get_local 1{{$}}
133 ; NOREGS-NEXT: i32.const 2{{$}}
134 ; NOREGS-NEXT: i32.lt_s
135 ; NOREGS-NEXT: i32.xor {{$}}
136 ; NOREGS-NEXT: get_local 2{{$}}
137 ; NOREGS-NEXT: i32.const 1{{$}}
138 ; NOREGS-NEXT: i32.lt_s
139 ; NOREGS-NEXT: get_local 3{{$}}
140 ; NOREGS-NEXT: i32.const 2{{$}}
141 ; NOREGS-NEXT: i32.lt_s
142 ; NOREGS-NEXT: i32.xor {{$}}
143 ; NOREGS-NEXT: i32.xor {{$}}
144 ; NOREGS-NEXT: i32.const 1{{$}}
145 ; NOREGS-NEXT: i32.ne {{$}}
146 ; NOREGS-NEXT: br_if 0{{$}}
147 ; NOREGS-NEXT: i32.const 0{{$}}
148 ; NOREGS-NEXT: return{{$}}
149 ; NOREGS-NEXT: .LBB7_2:
150 ; NOREGS-NEXT: end_block{{$}}
151 ; NOREGS-NEXT: i32.const 1{{$}}
152 ; NOREGS-NEXT: return{{$}}
107153 define i32 @stack_uses(i32 %x, i32 %y, i32 %z, i32 %w) {
108154 entry:
109155 %c = icmp sle i32 %x, 0
136182 ; CHECK-NEXT: .LBB8_3:
137183 ; CHECK-NEXT: end_block{{$}}
138184 ; CHECK-NEXT: return{{$}}
185 ; NOREGS-LABEL: multiple_uses:
186 ; NOREGS: .param i32, i32, i32{{$}}
187 ; NOREGS: .local i32{{$}}
188 ; NOREGS-NEXT: block {{$}}
189 ; NOREGS-NEXT: get_local 2{{$}}
190 ; NOREGS-NEXT: i32.load 0{{$}}
191 ; NOREGS-NEXT: tee_local 3{{$}}
192 ; NOREGS-NEXT: get_local 1{{$}}
193 ; NOREGS-NEXT: i32.ge_u
194 ; NOREGS-NEXT: br_if 0{{$}}
195 ; NOREGS-NEXT: get_local 3{{$}}
196 ; NOREGS-NEXT: get_local 0{{$}}
197 ; NOREGS-NEXT: i32.lt_u
198 ; NOREGS-NEXT: br_if 0{{$}}
199 ; NOREGS-NEXT: get_local 2{{$}}
200 ; NOREGS-NEXT: get_local 3{{$}}
201 ; NOREGS-NEXT: i32.store 0{{$}}
202 ; NOREGS-NEXT: .LBB8_3:
203 ; NOREGS-NEXT: end_block{{$}}
204 ; NOREGS-NEXT: return{{$}}
139205 define void @multiple_uses(i32* %arg0, i32* %arg1, i32* %arg2) nounwind {
140206 bb:
141207 br label %loop
166232 ; CHECK-NEXT: call
167233 ; CHECK: store
168234 ; CHECK-NEXT: call
235 ; NOREGS: side_effects:
236 ; NOREGS: store
237 ; NOREGS-NEXT: call
238 ; NOREGS: store
239 ; NOREGS-NEXT: call
169240 declare void @evoke_side_effects()
170241 define hidden void @stackify_store_across_side_effects(double* nocapture %d) {
171242 entry:
199270 ; CHECK-NEXT: i32.div_s $push[[L13:[0-9]+]]=, $pop[[L9]], $pop[[L12]]{{$}}
200271 ; CHECK-NEXT: i32.div_s $push[[L14:[0-9]+]]=, $pop[[L6]], $pop[[L13]]{{$}}
201272 ; CHECK-NEXT: return $pop[[L14]]{{$}}
273 ; NOREGS-LABEL: div_tree:
274 ; NOREGS: .param i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32{{$}}
275 ; NOREGS-NEXT: .result i32{{$}}
276 ; NOREGS-NEXT: get_local 0{{$}}
277 ; NOREGS-NEXT: get_local 1{{$}}
278 ; NOREGS-NEXT: i32.div_s{{$}}
279 ; NOREGS-NEXT: get_local 2{{$}}
280 ; NOREGS-NEXT: get_local 3{{$}}
281 ; NOREGS-NEXT: i32.div_s{{$}}
282 ; NOREGS-NEXT: i32.div_s{{$}}
283 ; NOREGS-NEXT: get_local 4{{$}}
284 ; NOREGS-NEXT: get_local 5{{$}}
285 ; NOREGS-NEXT: i32.div_s{{$}}
286 ; NOREGS-NEXT: get_local 6{{$}}
287 ; NOREGS-NEXT: get_local 7{{$}}
288 ; NOREGS-NEXT: i32.div_s{{$}}
289 ; NOREGS-NEXT: i32.div_s{{$}}
290 ; NOREGS-NEXT: i32.div_s{{$}}
291 ; NOREGS-NEXT: get_local 8{{$}}
292 ; NOREGS-NEXT: get_local 9{{$}}
293 ; NOREGS-NEXT: i32.div_s{{$}}
294 ; NOREGS-NEXT: get_local 10{{$}}
295 ; NOREGS-NEXT: get_local 11{{$}}
296 ; NOREGS-NEXT: i32.div_s{{$}}
297 ; NOREGS-NEXT: i32.div_s{{$}}
298 ; NOREGS-NEXT: get_local 12{{$}}
299 ; NOREGS-NEXT: get_local 13{{$}}
300 ; NOREGS-NEXT: i32.div_s{{$}}
301 ; NOREGS-NEXT: get_local 14{{$}}
302 ; NOREGS-NEXT: get_local 15{{$}}
303 ; NOREGS-NEXT: i32.div_s{{$}}
304 ; NOREGS-NEXT: i32.div_s{{$}}
305 ; NOREGS-NEXT: i32.div_s{{$}}
306 ; NOREGS-NEXT: i32.div_s{{$}}
307 ; NOREGS-NEXT: return{{$}}
202308 define i32 @div_tree(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n, i32 %o, i32 %p) {
203309 entry:
204310 %div = sdiv i32 %a, %b
228334 ; CHECK-NEXT: call use_a@FUNCTION, $pop[[NUM1]]{{$}}
229335 ; CHECK-NEXT: call use_b@FUNCTION, $[[NUM2]]{{$}}
230336 ; CHECK-NEXT: return{{$}}
337 ; NOREGS-LABEL: simple_multiple_use:
338 ; NOREGS: .param i32, i32{{$}}
339 ; NOREGS-NEXT: get_local 1{{$}}
340 ; NOREGS-NEXT: get_local 0{{$}}
341 ; NOREGS-NEXT: i32.mul
342 ; NOREGS-NEXT: tee_local 1{{$}}
343 ; NOREGS-NEXT: call use_a@FUNCTION{{$}}
344 ; NOREGS-NEXT: get_local 1{{$}}
345 ; NOREGS-NEXT: call use_b@FUNCTION{{$}}
346 ; NOREGS-NEXT: return{{$}}
231347 declare void @use_a(i32)
232348 declare void @use_b(i32)
233349 define void @simple_multiple_use(i32 %x, i32 %y) {
245361 ; CHECK-NEXT: tee_local $push[[NUM1:[0-9]+]]=, $[[NUM2:[0-9]+]]=, $pop[[NUM0]]{{$}}
246362 ; CHECK-NEXT: call use_2@FUNCTION, $pop[[NUM1]], $[[NUM2]]{{$}}
247363 ; CHECK-NEXT: return{{$}}
364 ; NOREGS-LABEL: multiple_uses_in_same_insn:
365 ; NOREGS: .param i32, i32{{$}}
366 ; NOREGS-NEXT: get_local 1{{$}}
367 ; NOREGS-NEXT: get_local 0{{$}}
368 ; NOREGS-NEXT: i32.mul
369 ; NOREGS-NEXT: tee_local 1{{$}}
370 ; NOREGS-NEXT: get_local 1{{$}}
371 ; NOREGS-NEXT: call use_2@FUNCTION{{$}}
372 ; NOREGS-NEXT: return{{$}}
248373 declare void @use_2(i32, i32)
249374 define void @multiple_uses_in_same_insn(i32 %x, i32 %y) {
250375 %mul = mul i32 %y, %x
263388 ; CHECK-NEXT: i32.call $push3=, blue@FUNCTION{{$}}
264389 ; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
265390 ; CHECK-NEXT: return $pop4{{$}}
391 ; NOREGS-LABEL: commute:
392 ; NOREGS-NOT: param
393 ; NOREGS: .result i32{{$}}
394 ; NOREGS-NEXT: i32.call red@FUNCTION{{$}}
395 ; NOREGS-NEXT: i32.call green@FUNCTION{{$}}
396 ; NOREGS-NEXT: i32.add {{$}}
397 ; NOREGS-NEXT: i32.call blue@FUNCTION{{$}}
398 ; NOREGS-NEXT: i32.add {{$}}
399 ; NOREGS-NEXT: return{{$}}
266400 declare i32 @red()
267401 declare i32 @green()
268402 declare i32 @blue()
286420 ; CHECK-NEXT: i32.sub $push3=, $pop2, $1
287421 ; CHECK-NEXT: i32.div_s $push4=, $pop3, $1
288422 ; CHECK-NEXT: return $pop4
423 ; NOREGS-LABEL: no_stackify_past_use:
424 ; NOREGS: get_local 0{{$}}
425 ; NOREGS-NEXT: i32.call callee@FUNCTION
426 ; NOREGS-NEXT: set_local 1{{$}}
427 ; NOREGS-NEXT: get_local 0{{$}}
428 ; NOREGS-NEXT: i32.const 1
429 ; NOREGS-NEXT: i32.add
430 ; NOREGS-NEXT: i32.call callee@FUNCTION
431 ; NOREGS-NEXT: get_local 1{{$}}
432 ; NOREGS-NEXT: i32.sub
433 ; NOREGS-NEXT: get_local 1{{$}}
434 ; NOREGS-NEXT: i32.div_s
435 ; NOREGS-NEXT: return
289436 declare i32 @callee(i32)
290437 define i32 @no_stackify_past_use(i32 %arg) {
291438 %tmp1 = call i32 @callee(i32 %arg)
308455 ; CHECK: i32.add $push3=, $1, $pop2
309456 ; CHECK: i32.mul $push4=, $pop[[L1]], $pop3
310457 ; CHECK: return $pop4
458 ; NOREGS-LABEL: commute_to_fix_ordering:
459 ; NOREGS: get_local 0{{$}}
460 ; NOREGS: i32.call callee@FUNCTION
461 ; NOREGS: tee_local 1
462 ; NOREGS: get_local 1{{$}}
463 ; NOREGS: get_local 0{{$}}
464 ; NOREGS: i32.const 1
465 ; NOREGS: i32.add
466 ; NOREGS: i32.call callee@FUNCTION
467 ; NOREGS: i32.add
468 ; NOREGS: i32.mul
469 ; NOREGS: return
311470 define i32 @commute_to_fix_ordering(i32 %arg) {
312471 %tmp1 = call i32 @callee(i32 %arg)
313472 %tmp2 = add i32 %arg, 1
324483 ; CHECK-NEXT: tee_local $push[[NUM1:[0-9]+]]=, $[[NUM2:[0-9]+]]=, $pop[[NUM0]]{{$}}
325484 ; CHECK-NEXT: f64.select $push{{[0-9]+}}=, $pop{{[0-9]+}}, $pop[[NUM1]], ${{[0-9]+}}{{$}}
326485 ; CHECK: $[[NUM2]]=,
486 ; NOREGS-LABEL: multiple_defs:
487 ; NOREGS: f64.add
488 ; NOREGS: tee_local
489 ; NOREGS: f64.select
327490 define void @multiple_defs(i32 %arg, i32 %arg1, i1 %arg2, i1 %arg3, i1 %arg4) {
328491 bb:
329492 br label %bb5
366529 ; CHECK: i32.call $0=, red
367530 ; CHECK: i32.const $push0=, 0
368531 ; CHECK: i32.load $1=, count($pop0)
532 ; NOREGS-LABEL: no_stackify_call_past_load:
533 ; NOREGS: i32.call red
534 ; NOREGS: i32.const 0
535 ; NOREGS: i32.load count
369536 @count = hidden global i32 0, align 4
370537 define i32 @no_stackify_call_past_load() {
371538 %a = call i32 @red()
380547 ; CHECK: i32.store 0($1), $0
381548 ; CHECK: i32.load {{.*}}, 0($2)
382549 ; CHECK: i32.call {{.*}}, callee@FUNCTION, $0{{$}}
550 ; NOREGS-LABEL: no_stackify_store_past_load
551 ; NOREGS: i32.store 0
552 ; NOREGS: i32.load 0
553 ; NOREGS: i32.call callee@FUNCTION{{$}}
383554 define i32 @no_stackify_store_past_load(i32 %a, i32* %p1, i32* %p2) {
384555 store i32 %a, i32* %p1
385556 %b = load i32, i32* %p2, align 4
393564 ; CHECK: i32.call {{.*}}, callee@FUNCTION, $0
394565 ; CHECK: i32.load $push{{.*}}, 0($2)
395566 ; CHECK: return $pop
567 ; NOREGS-LABEL: store_past_invar_load
568 ; NOREGS: i32.store 0
569 ; NOREGS: i32.call callee@FUNCTION
570 ; NOREGS: i32.load 0
571 ; NOREGS: return
396572 define i32 @store_past_invar_load(i32 %a, i32* %p1, i32* dereferenceable(4) %p2) {
397573 store i32 %a, i32* %p1
398574 %b = load i32, i32* %p2, !invariant.load !0
403579 ; CHECK-LABEL: ignore_dbg_value:
404580 ; CHECK-NEXT: .Lfunc_begin
405581 ; CHECK-NEXT: unreachable
582 ; NOREGS-LABEL: ignore_dbg_value:
583 ; NOREGS-NEXT: .Lfunc_begin
584 ; NOREGS-NEXT: unreachable
406585 declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
407586 define void @ignore_dbg_value() {
408587 call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !7, metadata !9), !dbg !10
414593
415594 ; CHECK-LABEL: no_stackify_past_epilogue:
416595 ; CHECK: return ${{[0-9]+}}{{$}}
596 ; NOREGS-LABEL: no_stackify_past_epilogue:
597 ; NOREGS: return{{$}}
417598 declare i32 @use_memory(i32*)
418599 define i32 @no_stackify_past_epilogue() {
419600 %x = alloca i32
428609 ; CHECK-NEXT: i32.add $push[[L4:.+]]=, $[[R0:.+]], $pop[[L5]]{{$}}
429610 ; CHECK-NEXT: tee_local $push[[L3:.+]]=, $[[R0]]=, $pop[[L4]]{{$}}
430611 ; CHECK-NEXT: i32.ne $push[[L2:.+]]=, $0, $pop[[L3]]{{$}}
612 ; NOREGS-LABEL: stackify_indvar:
613 ; NOREGS: i32.const 1{{$}}
614 ; NOREGS-NEXT: i32.add
615 ; NOREGS-NEXT: tee_local 2{{$}}
616 ; NOREGS-NEXT: i32.ne
431617 define void @stackify_indvar(i32 %tmp, i32* %v) #0 {
432618 bb:
433619 br label %bb3
450636 ; CHECK-LABEL: stackpointer_dependency:
451637 ; CHECK: call {{.+}}, stackpointer_callee@FUNCTION,
452638 ; CHECK-NEXT: set_global __stack_pointer,
639 ; NOREGS-LABEL: stackpointer_dependency:
640 ; NOREGS: call stackpointer_callee@FUNCTION
641 ; NOREGS: set_global __stack_pointer
453642 declare i32 @stackpointer_callee(i8* readnone, i8* readnone)
454643 declare i8* @llvm.frameaddress(i32)
455644 define i32 @stackpointer_dependency(i8* readnone) {
466655 ; CHECK-NEXT: i32.load $push[[L0:.+]]=, 0($0)
467656 ; CHECK-NEXT: i32.load $push[[L1:.+]]=, 0($pop[[L0]])
468657 ; CHECK-NEXT: i32.call_indirect $push{{.+}}=, $pop[[L3]], $1, $pop[[L1]]
658 ; NOREGS-LABEL: call_indirect_stackify:
659 ; NOREGS: i32.load 0
660 ; NOREGS-NEXT: tee_local 0
661 ; NOREGS: i32.load 0
662 ; NOREGS-NEXT: i32.load 0
663 ; NOREGS-NEXT: i32.call_indirect
469664 %class.call_indirect = type { i32 (...)** }
470665 define i32 @call_indirect_stackify(%class.call_indirect** %objptr, i32 %arg) {
471666 %obj = load %class.call_indirect*, %class.call_indirect** %objptr
490685 !8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
491686 !9 = !DIExpression()
492687 !10 = !DILocation(line: 15, column: 6, scope: !5)
688
None ; RUN: llc < %s -asm-verbose=false | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -fast-isel -fast-isel-abort=1 | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode -fast-isel -fast-isel-abort=1 | FileCheck %s
22
33 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
44 target triple = "wasm32-unknown-unknown"
2525
2626 true:
2727 store i32 0, i32* null
28 ret i32 1
28 ret i32 1
2929
3030 false:
3131 store i32 2, i32* null
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test that the "returned" attribute is optimized effectively.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -fast-isel -fast-isel-abort=1 | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -fast-isel -fast-isel-abort=1 | FileCheck %s
22
33 ; Test that wasm select instruction is selected from LLVM select instruction.
44
0 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode | FileCheck %s
22
33 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
44 target triple = "wasm32-unknown-unknown"
None ; RUN: llc < %s -mattr=+sign-ext -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s --check-prefix=NOSIGNEXT
0 ; RUN: llc < %s -mattr=+sign-ext -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s --check-prefix=NOSIGNEXT
22
33 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
44 target triple = "wasm32-unknown-unknown"
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test zeroext and signext ABI keywords
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+simd128 | FileCheck %s --check-prefixes CHECK,SIMD128
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+simd128 -fast-isel | FileCheck %s --check-prefixes CHECK,SIMD128
2 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=-simd128 | FileCheck %s --check-prefixes CHECK,NO-SIMD128
3 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=-simd128 -fast-isel | FileCheck %s --check-prefixes CHECK,NO-SIMD128
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -mattr=+simd128 | FileCheck %s --check-prefixes CHECK,SIMD128
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -mattr=+simd128 -fast-isel | FileCheck %s --check-prefixes CHECK,SIMD128
2 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -mattr=-simd128 | FileCheck %s --check-prefixes CHECK,NO-SIMD128
3 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -mattr=-simd128 -fast-isel | FileCheck %s --check-prefixes CHECK,NO-SIMD128
44
55 ; Test that basic SIMD128 arithmetic operations assemble as expected.
66
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
33 target triple = "wasm32-unknown-unknown"
None ; RUN: llc < %s -mattr=+atomics,+sign-ext -asm-verbose=false -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -mattr=+atomics,+sign-ext -asm-verbose=false -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test that truncating stores are assembled properly.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Test that truncating stores are assembled properly.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -fast-isel -fast-isel-abort=1 | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode -fast-isel -fast-isel-abort=1 | FileCheck %s
22
33 ; Test that basic stores are assembled properly.
44
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -disable-block-placement -verify-machineinstrs | FileCheck %s
11
22 ; Test switch instructions. Block placement is disabled because it reorders
33 ; the blocks in a way that isn't interesting here.
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -thread-model=single | FileCheck --check-prefix=SINGLE %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -thread-model=single | FileCheck --check-prefix=SINGLE %s
11 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
22 target triple = "wasm32-unknown-unknown"
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode | FileCheck %s
11 ; Test that UMULO works correctly on 64-bit operands.
22 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
33 target triple = "wasm32-unknown-unknown"
None ; RUN: llc < %s -asm-verbose=false | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 ; Test that function pointer casts that require conversions are not converted
33 ; to wrappers. In theory some conversions could be supported, but currently no
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
11
22 ; Make sure that argument offsets are correct even if some arguments are unused.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
11
22 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
33 target triple = "wasm32-unknown-unknown"
137137 ; Target independent codegen bumps the stack pointer.
138138 ; CHECK: i32.sub
139139 ; Check that SP is written back to memory after decrement
140 ; CHECK: set_global __stack_pointer,
140 ; CHECK: set_global __stack_pointer,
141141 %r = alloca i32, i32 %alloc
142142 ; Target-independent codegen also calculates the store addr
143143 ; CHECK: call ext_func_i32@FUNCTION
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -verify-machineinstrs | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -verify-machineinstrs | FileCheck %s
11
22 ; Test varargs constructs.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals | FileCheck %s --check-prefix=TYPEINFONAME
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals | FileCheck %s --check-prefix=VTABLE
2 ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals | FileCheck %s --check-prefix=TYPEINFO
0 ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode | FileCheck %s --check-prefix=TYPEINFONAME
1 ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode | FileCheck %s --check-prefix=VTABLE
2 ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode | FileCheck %s --check-prefix=TYPEINFO
33
44 ; Test that simple vtables assemble as expected.
55 ;
1010 # CHECK: i64.const -1
1111 0x42 0x7F
1212
13 # CHECK: i64.load32_u 16, :p2align=1
14 # FIXME: fix p2align output in WebAssemblyInstPrinter
13 # CHECK: i64.load32_u 16:p2align=1
1514 0x35 0x01 0x10
1615
1716 # CHECK: block
66 .param i32, i64
77 .local f32, f64 #, i8x16, i16x8, i32x4, f32x4
88 # Explicit getlocal/setlocal:
9 get_local $push0=, 2
10 set_local 2, $pop0=
11 # Implicit locals & immediates:
12 i32.const $0=, -1
13 f64.const $3=, 0x1.999999999999ap1
9 get_local 2
10 set_local 2
11 # Immediates:
12 i32.const -1
13 f64.const 0x1.999999999999ap1
1414 # Indirect addressing:
15 get_local $push1=, 0
16 f64.store 0($pop1), $3
15 get_local 0
16 f64.store 0
1717 # Loops, conditionals, binary ops, calls etc:
1818 block
19 i32.const $push2=, 1
20 get_local $push7=, 0
21 i32.ge_s $push0=, $pop2, $pop7
22 br_if 0, $pop0 # 0: down to label0
19 i32.const 1
20 get_local 0
21 i32.ge_s
22 br_if 0 # 0: down to label0
2323 .LBB0_1:
2424 loop # label1:
25 call $drop=, something1@FUNCTION
26 i64.const $push10=, 1234
27 i32.call $push8=, something2@FUNCTION, $pop10
28 i32.const $push11=, 0
29 call_indirect $pop11
30 i32.const $push5=, 1
31 i32.add $push4=, $pop8, $pop5
32 tee_local $push3=, 0, $pop4
33 get_local $push9=, 0
34 i32.lt_s $push1=, $pop3, $pop9
35 br_if 0, $pop1 # 0: up to label1
25 call something1@FUNCTION
26 i64.const 1234
27 i32.call something2@FUNCTION
28 i32.const 0
29 call_indirect
30 i32.const 1
31 i32.add
32 tee_local 0
33 get_local 0
34 i32.lt_s
35 br_if 0 # 0: up to label1
3636 .LBB0_2:
3737 end_loop
3838 end_block # label0:
4343 # CHECK-LABEL: test0:
4444 # CHECK-NEXT: .param i32, i64
4545 # CHECK-NEXT: .local f32, f64
46 # CHECK-NEXT: get_local $push0=, 2
47 # CHECK-NEXT: set_local 2, $pop0
48 # CHECK-NEXT: i32.const $0=, -1
49 # CHECK-NEXT: f64.const $3=, 0x1.999999999999ap1
50 # CHECK-NEXT: get_local $push1=, 0
51 # CHECK-NEXT: f64.store 0($pop1):p2align=0, $3
46 # CHECK-NEXT: get_local 2
47 # CHECK-NEXT: set_local 2
48 # CHECK-NEXT: i32.const -1
49 # CHECK-NEXT: f64.const 0x1.999999999999ap1
50 # CHECK-NEXT: get_local 0
51 # CHECK-NEXT: f64.store 0:p2align=0
5252 # CHECK-NEXT: block
53 # CHECK-NEXT: i32.const $push2=, 1
54 # CHECK-NEXT: get_local $push7=, 0
55 # CHECK-NEXT: i32.ge_s $push0=, $pop2, $pop7
56 # CHECK-NEXT: br_if 0, $pop0 # 0: down to label0
53 # CHECK-NEXT: i32.const 1
54 # CHECK-NEXT: get_local 0
55 # CHECK-NEXT: i32.ge_s
56 # CHECK-NEXT: br_if 0 # 0: down to label0
5757 # CHECK-NEXT: .LBB0_1:
5858 # CHECK-NEXT: loop # label1:
5959 # CHECK-NEXT: call something1@FUNCTION
60 # CHECK-NEXT: i64.const $push10=, 1234
61 # CHECK-NEXT: i32.call $push8=, something2@FUNCTION
62 # CHECK-NEXT: i32.const $push11=, 0
60 # CHECK-NEXT: i64.const 1234
61 # CHECK-NEXT: i32.call something2@FUNCTION
62 # CHECK-NEXT: i32.const 0
6363 # CHECK-NEXT: call_indirect
64 # CHECK-NEXT: i32.const $push5=, 1
65 # CHECK-NEXT: i32.add $push4=, $pop8, $pop5
66 # CHECK-NEXT: tee_local $push3=, 0, $pop4
67 # CHECK-NEXT: get_local $push9=, 0
68 # CHECK-NEXT: i32.lt_s $push1=, $pop3, $pop9
69 # CHECK-NEXT: br_if 0, $pop1 # 0: up to label1
64 # CHECK-NEXT: i32.const 1
65 # CHECK-NEXT: i32.add
66 # CHECK-NEXT: tee_local 0
67 # CHECK-NEXT: get_local 0
68 # CHECK-NEXT: i32.lt_s
69 # CHECK-NEXT: br_if 0 # 0: up to label1
7070 # CHECK-NEXT: .LBB0_2:
7171 # CHECK-NEXT: end_loop
7272 # CHECK-NEXT: end_block # label0:
None ; RUN: llc -filetype=obj %s -o - | llvm-readobj -r -expand-relocs | FileCheck %s
0 ; RUN: llc -filetype=obj -wasm-explicit-locals-codegen-test-mode %s -o - | llvm-readobj -r -expand-relocs | FileCheck %s
11
22 target triple = "wasm32-unknown-unknown"
33
None ; RUN: llc -filetype=obj %s -o %t.o
0 ; RUN: llc -filetype=obj -wasm-explicit-locals-codegen-test-mode %s -o %t.o
11 ; RUN: obj2yaml %t.o | FileCheck %s
22 ; RUN: llvm-objdump -t %t.o | FileCheck --check-prefix=CHECK-SYMS %s
33
4646 }
4747
4848 ; CHECK: - Type: TYPE
49 ; CHECK-NEXT: Signatures:
49 ; CHECK-NEXT: Signatures:
5050 ; CHECK-NEXT: - Index: 0
5151 ; CHECK-NEXT: ReturnType: I32
52 ; CHECK-NEXT: ParamTypes:
52 ; CHECK-NEXT: ParamTypes:
5353 ; CHECK-NEXT: - Type: IMPORT
5454 ; CHECK-NEXT: Imports:
5555 ; CHECK-NEXT: - Module: env
6767 ; CHECK-NEXT: - Type: FUNCTION
6868 ; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0 ]
6969 ; CHECK-NEXT: - Type: ELEM
70 ; CHECK-NEXT: Segments:
71 ; CHECK-NEXT: - Offset:
70 ; CHECK-NEXT: Segments:
71 ; CHECK-NEXT: - Offset:
7272 ; CHECK-NEXT: Opcode: I32_CONST
7373 ; CHECK-NEXT: Value: 1
7474 ; CHECK-NEXT: Functions: [ 0 ]
7575 ; CHECK-NEXT: - Type: CODE
76 ; CHECK-NEXT: Relocations:
76 ; CHECK-NEXT: Relocations:
7777 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
7878 ; CHECK-NEXT: Index: 0
7979 ; CHECK-NEXT: Offset: 0x00000009
9292 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TYPE_INDEX_LEB
9393 ; CHECK-NEXT: Index: 0
9494 ; CHECK-NEXT: Offset: 0x00000037
95 ; CHECK-NEXT: Functions:
96 ; CHECK-NEXT: - Index: 0
97 ; CHECK-NEXT: Locals:
95 ; CHECK-NEXT: Functions:
96 ; CHECK-NEXT: - Index: 0
97 ; CHECK-NEXT: Locals:
9898 ; CHECK-NEXT: Body: 41000B
9999 ; CHECK-NEXT: - Index: 1
100 ; CHECK-NEXT: Locals:
100 ; CHECK-NEXT: Locals:
101101 ; CHECK-NEXT: Body: 1080808080000B
102102 ; CHECK-NEXT: - Index: 2
103 ; CHECK-NEXT: Locals:
103 ; CHECK-NEXT: Locals:
104104 ; CHECK-NEXT: Body: 1080808080000B
105105 ; CHECK-NEXT: - Index: 3
106 ; CHECK-NEXT: Locals:
106 ; CHECK-NEXT: Locals:
107107 ; CHECK-NEXT: Body: 410028028880808000118080808000000B
108108 ; CHECK-NEXT: - Index: 4
109 ; CHECK-NEXT: Locals:
109 ; CHECK-NEXT: Locals:
110110 ; CHECK-NEXT: Body: 410028029080808000118080808000000B
111111 ; CHECK-NEXT: - Type: DATA
112 ; CHECK-NEXT: Relocations:
112 ; CHECK-NEXT: Relocations:
113113 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
114114 ; CHECK-NEXT: Index: 0
115115 ; CHECK-NEXT: Offset: 0x0000000F
116116 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32
117117 ; CHECK-NEXT: Index: 3
118118 ; CHECK-NEXT: Offset: 0x00000018
119 ; CHECK-NEXT: Segments:
119 ; CHECK-NEXT: Segments:
120120 ; CHECK-NEXT: - SectionOffset: 6
121121 ; CHECK-NEXT: MemoryIndex: 0
122 ; CHECK-NEXT: Offset:
122 ; CHECK-NEXT: Offset:
123123 ; CHECK-NEXT: Opcode: I32_CONST
124124 ; CHECK-NEXT: Value: 0
125125 ; CHECK-NEXT: Content: '07000000'
126126 ; CHECK-NEXT: - SectionOffset: 15
127127 ; CHECK-NEXT: MemoryIndex: 0
128 ; CHECK-NEXT: Offset:
128 ; CHECK-NEXT: Offset:
129129 ; CHECK-NEXT: Opcode: I32_CONST
130130 ; CHECK-NEXT: Value: 8
131131 ; CHECK-NEXT: Content: '01000000'
138138 ; CHECK-NEXT: - Type: CUSTOM
139139 ; CHECK-NEXT: Name: linking
140140 ; CHECK-NEXT: Version: 1
141 ; CHECK-NEXT: SymbolTable:
141 ; CHECK-NEXT: SymbolTable:
142142 ; CHECK-NEXT: - Index: 0
143143 ; CHECK-NEXT: Kind: FUNCTION
144144 ; CHECK-NEXT: Name: foo
193193 ; CHECK-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN ]
194194 ; CHECK-NEXT: Segment: 0
195195 ; CHECK-NEXT: Size: 4
196 ; CHECK-NEXT: SegmentInfo:
196 ; CHECK-NEXT: SegmentInfo:
197197 ; CHECK-NEXT: - Index: 0
198198 ; CHECK-NEXT: Name: .data.bar
199199 ; CHECK-NEXT: Alignment: 8
100100 InstSize = LLVMDisasmInstruction(DCR, BytesP, NumBytes, PC, OutString,
101101 OutStringSize);
102102 EXPECT_EQ(InstSize, 3U);
103 EXPECT_EQ(StringRef(OutString), "\ti64.load32_u\t16, :p2align=1");
103 EXPECT_EQ(StringRef(OutString), "\ti64.load32_u\t16:p2align=1");
104104
105105 LLVMDisasmDispose(DCR);
106106 }