llvm.org GIT mirror llvm / a297d96
Revert "[WebAssembly] Added default stack-only instruction mode for MC." This reverts commit 917a99b71ce21c975be7bfbf66f4040f965d9f3c. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@339630 91177308-0d34-0410-b5e6-96231b3b80d8 Wouter van Oortmerssen 2 years ago
92 changed file(s) with 427 addition(s) and 853 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
3653 /// WebAssemblyOperand - Instances of this class represent the operands in a
3754 /// parsed WASM machine instruction.
3855 struct WebAssemblyOperand : public MCParsedAsmOperand {
39 enum KindTy { Token, Integer, Float, Symbol } Kind;
56 enum KindTy { Token, Local, Stack, Integer, Float, Symbol } Kind;
4057
4158 SMLoc StartLoc, EndLoc;
4259
4461 StringRef Tok;
4562 };
4663
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
4777 struct IntOp {
4878 int64_t Val;
4979 };
5888
5989 union {
6090 struct TokOp Tok;
91 struct RegOp Reg;
6192 struct IntOp Int;
6293 struct FltOp Flt;
6394 struct SymOp Sym;
6596
6697 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T)
6798 : 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) {}
68101 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)
69102 : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}
70103 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F)
76109 bool isImm() const override { return Kind == Integer ||
77110 Kind == Float ||
78111 Kind == Symbol; }
112 bool isReg() const override { return Kind == Local || Kind == Stack; }
79113 bool isMem() const override { return false; }
80 bool isReg() const override { return false; }
81114
82115 unsigned getReg() const override {
83 llvm_unreachable("Assembly inspects a register operand");
84 return 0;
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);
85120 }
86121
87122 StringRef getToken() const {
92127 SMLoc getStartLoc() const override { return StartLoc; }
93128 SMLoc getEndLoc() const override { return EndLoc; }
94129
95 void addRegOperands(MCInst &, unsigned) const {
96 // Required by the assembly matcher.
97 llvm_unreachable("Assembly matcher creates register operands");
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));
98143 }
99144
100145 void addImmOperands(MCInst &Inst, unsigned N) const {
114159 case Token:
115160 OS << "Tok:" << Tok.Tok;
116161 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;
117168 case Integer:
118169 OS << "Int:" << Int.Val;
119170 break;
130181 class WebAssemblyAsmParser final : public MCTargetAsmParser {
131182 MCAsmParser &Parser;
132183 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;
133189 MCSymbol *LastLabel;
134190
135191 public:
179235 .Default(MVT::INVALID_SIMPLE_VALUE_TYPE);
180236 }
181237
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
182300 void ParseSingleInteger(bool IsNegative, OperandVector &Operands) {
183301 auto &Int = Lexer.getTok();
184302 int64_t Val = Int.getIntVal();
191309
192310 bool ParseOperandStartingWithInteger(bool IsNegative,
193311 OperandVector &Operands,
194 StringRef InstName) {
312 StringRef InstType) {
195313 ParseSingleInteger(IsNegative, Operands);
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)) {
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)) {
205335 ParseSingleInteger(false, Operands);
206336 } else {
207337 // Alignment not specified.
208338 // 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.
211339 Operands.push_back(make_unique(
212 WebAssemblyOperand::Integer, Offset.getLoc(),
213 Offset.getEndLoc(), WebAssemblyOperand::IntOp{0}));
340 WebAssemblyOperand::Integer, RParen.getLoc(),
341 RParen.getEndLoc(), WebAssemblyOperand::IntOp{0}));
214342 }
215343 }
216344 return false;
231359 while (Lexer.isNot(AsmToken::EndOfStatement)) {
232360 auto &Tok = Lexer.getTok();
233361 switch (Tok.getKind()) {
362 case AsmToken::Dollar: {
363 Parser.Lex();
364 if (ParseReg(Operands, NamePair.first)) return true;
365 break;
366 }
234367 case AsmToken::Identifier: {
235368 auto &Id = Lexer.getTok();
236369 const MCExpr *Val;
246379 Parser.Lex();
247380 if (Lexer.isNot(AsmToken::Integer))
248381 return Error("Expected integer instead got: ", Lexer.getTok());
249 if (ParseOperandStartingWithInteger(true, Operands, NamePair.second))
382 if (ParseOperandStartingWithInteger(true, Operands, NamePair.first))
250383 return true;
251384 break;
252385 case AsmToken::Integer:
253 if (ParseOperandStartingWithInteger(false, Operands, NamePair.second))
386 if (ParseOperandStartingWithInteger(false, Operands, NamePair.first))
254387 return true;
255388 break;
256389 case AsmToken::Real: {
271404 }
272405 }
273406 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 }
274436 // Block instructions require a signature index, but these are missing in
275437 // assembly, so we add a dummy one explicitly (since we have no control
276438 // over signature tables here, we assume these will be regenerated when
279441 Operands.push_back(make_unique(
280442 WebAssemblyOperand::Integer, NameLoc,
281443 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 }
282455 }
283456 return false;
284457 }
303476 IsNext(AsmToken::At) &&
304477 Lexer.is(AsmToken::Identifier)))
305478 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 }
306484 Parser.Lex();
307485 //Out.EmitSymbolAttribute(??, MCSA_ELF_TypeFunction);
308486 } else if (DirectiveID.getString() == ".param" ||
315493 while (Lexer.is(AsmToken::Identifier)) {
316494 auto RegType = ParseRegType(Lexer.getTok().getString());
317495 if (RegType == MVT::INVALID_SIMPLE_VALUE_TYPE) return true;
496 LocalTypes.push_back(RegType);
318497 if (DirectiveID.getString() == ".param") {
319498 Params.push_back(RegType);
320499 } else {
168168
169169 switch (MI->getOpcode()) {
170170 case WebAssembly::ARGUMENT_I32:
171 case WebAssembly::ARGUMENT_I32_S:
172171 case WebAssembly::ARGUMENT_I64:
173 case WebAssembly::ARGUMENT_I64_S:
174172 case WebAssembly::ARGUMENT_F32:
175 case WebAssembly::ARGUMENT_F32_S:
176173 case WebAssembly::ARGUMENT_F64:
177 case WebAssembly::ARGUMENT_F64_S:
178174 case WebAssembly::ARGUMENT_v16i8:
179 case WebAssembly::ARGUMENT_v16i8_S:
180175 case WebAssembly::ARGUMENT_v8i16:
181 case WebAssembly::ARGUMENT_v8i16_S:
182176 case WebAssembly::ARGUMENT_v4i32:
183 case WebAssembly::ARGUMENT_v4i32_S:
184177 case WebAssembly::ARGUMENT_v2i64:
185 case WebAssembly::ARGUMENT_v2i64_S:
186178 case WebAssembly::ARGUMENT_v4f32:
187 case WebAssembly::ARGUMENT_v4f32_S:
188179 case WebAssembly::ARGUMENT_v2f64:
189 case WebAssembly::ARGUMENT_v2f64_S:
190180 // These represent values which are live into the function entry, so there's
191181 // no instruction to emit.
192182 break;
193183 case WebAssembly::FALLTHROUGH_RETURN_I32:
194 case WebAssembly::FALLTHROUGH_RETURN_I32_S:
195184 case WebAssembly::FALLTHROUGH_RETURN_I64:
196 case WebAssembly::FALLTHROUGH_RETURN_I64_S:
197185 case WebAssembly::FALLTHROUGH_RETURN_F32:
198 case WebAssembly::FALLTHROUGH_RETURN_F32_S:
199186 case WebAssembly::FALLTHROUGH_RETURN_F64:
200 case WebAssembly::FALLTHROUGH_RETURN_F64_S:
201187 case WebAssembly::FALLTHROUGH_RETURN_v16i8:
202 case WebAssembly::FALLTHROUGH_RETURN_v16i8_S:
203188 case WebAssembly::FALLTHROUGH_RETURN_v8i16:
204 case WebAssembly::FALLTHROUGH_RETURN_v8i16_S:
205189 case WebAssembly::FALLTHROUGH_RETURN_v4i32:
206 case WebAssembly::FALLTHROUGH_RETURN_v4i32_S:
207190 case WebAssembly::FALLTHROUGH_RETURN_v2i64:
208 case WebAssembly::FALLTHROUGH_RETURN_v2i64_S:
209191 case WebAssembly::FALLTHROUGH_RETURN_v4f32:
210 case WebAssembly::FALLTHROUGH_RETURN_v4f32_S:
211 case WebAssembly::FALLTHROUGH_RETURN_v2f64:
212 case WebAssembly::FALLTHROUGH_RETURN_v2f64_S: {
192 case WebAssembly::FALLTHROUGH_RETURN_v2f64: {
213193 // These instructions represent the implicit return at the end of a
214 // function body. Always pops one value off the stack.
194 // function body. The operand is always a pop.
195 assert(MFI->isVRegStackified(MI->getOperand(0).getReg()));
196
215197 if (isVerbose()) {
216 OutStreamer->AddComment("fallthrough-return-value");
198 OutStreamer->AddComment("fallthrough-return: $pop" +
199 Twine(MFI->getWARegStackId(
200 MFI->getWAReg(MI->getOperand(0).getReg()))));
217201 OutStreamer->AddBlankLine();
218202 }
219203 break;
220204 }
221205 case WebAssembly::FALLTHROUGH_RETURN_VOID:
222 case WebAssembly::FALLTHROUGH_RETURN_VOID_S:
223206 // This instruction represents the implicit return at the end of a
224207 // function body with no return value.
225208 if (isVerbose()) {
226 OutStreamer->AddComment("fallthrough-return-void");
209 OutStreamer->AddComment("fallthrough-return");
227210 OutStreamer->AddBlankLine();
228211 }
229212 break;
264247 OS << MO.getImm();
265248 return false;
266249 case MachineOperand::MO_Register:
267 // FIXME: only opcode that still contains registers, as required by
268 // MachineInstr::getDebugVariable().
269 assert(MI->getOpcode() == WebAssembly::INLINEASM);
270250 OS << regToString(MO);
271251 return false;
272252 case MachineOperand::MO_GlobalAddress:
3030
3131 #define DEBUG_TYPE "wasm-explicit-locals"
3232
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."),
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."),
4839 cl::init(false));
4940
5041 namespace {
6657 WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
6758 };
6859 } // end anonymous namespace
69
70 unsigned regInstructionToStackInstruction(unsigned OpCode);
7160
7261 char WebAssemblyExplicitLocals::ID = 0;
7362 INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE,
172161
173162 /// Given a MachineOperand of a stackified vreg, return the instruction at the
174163 /// start of the expression tree.
175 static MachineInstr *findStartOfTree(MachineOperand &MO,
164 static MachineInstr *FindStartOfTree(MachineOperand &MO,
176165 MachineRegisterInfo &MRI,
177166 WebAssemblyFunctionInfo &MFI) {
178167 unsigned Reg = MO.getReg();
183172 for (MachineOperand &DefMO : Def->explicit_uses()) {
184173 if (!DefMO.isReg())
185174 continue;
186 return findStartOfTree(DefMO, MRI, MFI);
175 return FindStartOfTree(DefMO, MRI, MFI);
187176 }
188177
189178 // If there were no stackified uses, we've reached the start.
196185 << MF.getName() << '\n');
197186
198187 // Disable this pass if directed to do so.
199 if (RegisterCodeGenTestMode)
188 if (DisableWebAssemblyExplicitLocals)
200189 return false;
201190
202191 bool Changed = false;
216205 break;
217206 unsigned Reg = MI.getOperand(0).getReg();
218207 assert(!MFI.isVRegStackified(Reg));
219 Reg2Local[Reg] = static_cast(MI.getOperand(1).getImm());
208 Reg2Local[Reg] = MI.getOperand(1).getImm();
220209 MI.eraseFromParent();
221210 Changed = true;
222211 }
223212
224213 // Start assigning local numbers after the last parameter.
225 unsigned CurLocal = static_cast(MFI.getParams().size());
214 unsigned CurLocal = MFI.getParams().size();
226215
227216 // Precompute the set of registers that are unused, so that we can insert
228217 // drops to their defs.
229218 BitVector UseEmpty(MRI.getNumVirtRegs());
230 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I)
231 UseEmpty[I] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(I));
219 for (unsigned i = 0, e = MRI.getNumVirtRegs(); i < e; ++i)
220 UseEmpty[i] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(i));
232221
233222 // Visit each instruction in the function.
234223 for (MachineBasicBlock &MBB : MF) {
332321 // If we see a stackified register, prepare to insert subsequent
333322 // get_locals before the start of its tree.
334323 if (MFI.isVRegStackified(OldReg)) {
335 InsertPt = findStartOfTree(MO, MRI, MFI);
324 InsertPt = FindStartOfTree(MO, MRI, MFI);
336325 continue;
337326 }
338327
366355 Changed = true;
367356 }
368357 }
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 }
403358 }
404359
405360 // Define the locals.
406361 // TODO: Sort the locals for better compression.
407362 MFI.setNumLocals(CurLocal - 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())
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())
412367 continue;
413368
414 MFI.setLocal(RL->second - MFI.getParams().size(),
369 MFI.setLocal(I->second - MFI.getParams().size(),
415370 typeForRegClass(MRI.getRegClass(Reg)));
416371 Changed = true;
417372 }
418373
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 }
387 }
388 #endif
389
419390 return Changed;
420391 }
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::ARGUMENT_v2f64: return WebAssembly::ARGUMENT_v2f64_S;
458 case WebAssembly::ARGUMENT_v2i64: return WebAssembly::ARGUMENT_v2i64_S;
459 case WebAssembly::ATOMIC_LOAD16_U_I32: return WebAssembly::ATOMIC_LOAD16_U_I32_S;
460 case WebAssembly::ATOMIC_LOAD16_U_I64: return WebAssembly::ATOMIC_LOAD16_U_I64_S;
461 case WebAssembly::ATOMIC_LOAD32_U_I64: return WebAssembly::ATOMIC_LOAD32_U_I64_S;
462 case WebAssembly::ATOMIC_LOAD8_U_I32: return WebAssembly::ATOMIC_LOAD8_U_I32_S;
463 case WebAssembly::ATOMIC_LOAD8_U_I64: return WebAssembly::ATOMIC_LOAD8_U_I64_S;
464 case WebAssembly::ATOMIC_LOAD_I32: return WebAssembly::ATOMIC_LOAD_I32_S;
465 case WebAssembly::ATOMIC_LOAD_I64: return WebAssembly::ATOMIC_LOAD_I64_S;
466 case WebAssembly::ATOMIC_STORE16_I32: return WebAssembly::ATOMIC_STORE16_I32_S;
467 case WebAssembly::ATOMIC_STORE16_I64: return WebAssembly::ATOMIC_STORE16_I64_S;
468 case WebAssembly::ATOMIC_STORE32_I64: return WebAssembly::ATOMIC_STORE32_I64_S;
469 case WebAssembly::ATOMIC_STORE8_I32: return WebAssembly::ATOMIC_STORE8_I32_S;
470 case WebAssembly::ATOMIC_STORE8_I64: return WebAssembly::ATOMIC_STORE8_I64_S;
471 case WebAssembly::ATOMIC_STORE_I32: return WebAssembly::ATOMIC_STORE_I32_S;
472 case WebAssembly::ATOMIC_STORE_I64: return WebAssembly::ATOMIC_STORE_I64_S;
473 case WebAssembly::BLOCK: return WebAssembly::BLOCK_S;
474 case WebAssembly::BR: return WebAssembly::BR_S;
475 case WebAssembly::BR_IF: return WebAssembly::BR_IF_S;
476 case WebAssembly::BR_TABLE_I32: return WebAssembly::BR_TABLE_I32_S;
477 case WebAssembly::BR_TABLE_I64: return WebAssembly::BR_TABLE_I64_S;
478 case WebAssembly::BR_UNLESS: return WebAssembly::BR_UNLESS_S;
479 case WebAssembly::CALL_EXCEPT_REF: return WebAssembly::CALL_EXCEPT_REF_S;
480 case WebAssembly::CALL_F32: return WebAssembly::CALL_F32_S;
481 case WebAssembly::CALL_F64: return WebAssembly::CALL_F64_S;
482 case WebAssembly::CALL_I32: return WebAssembly::CALL_I32_S;
483 case WebAssembly::CALL_I64: return WebAssembly::CALL_I64_S;
484 case WebAssembly::CALL_INDIRECT_EXCEPT_REF: return WebAssembly::CALL_INDIRECT_EXCEPT_REF_S;
485 case WebAssembly::CALL_INDIRECT_F32: return WebAssembly::CALL_INDIRECT_F32_S;
486 case WebAssembly::CALL_INDIRECT_F64: return WebAssembly::CALL_INDIRECT_F64_S;
487 case WebAssembly::CALL_INDIRECT_I32: return WebAssembly::CALL_INDIRECT_I32_S;
488 case WebAssembly::CALL_INDIRECT_I64: return WebAssembly::CALL_INDIRECT_I64_S;
489 case WebAssembly::CALL_INDIRECT_VOID: return WebAssembly::CALL_INDIRECT_VOID_S;
490 case WebAssembly::CALL_INDIRECT_v16i8: return WebAssembly::CALL_INDIRECT_v16i8_S;
491 case WebAssembly::CALL_INDIRECT_v4f32: return WebAssembly::CALL_INDIRECT_v4f32_S;
492 case WebAssembly::CALL_INDIRECT_v4i32: return WebAssembly::CALL_INDIRECT_v4i32_S;
493 case WebAssembly::CALL_INDIRECT_v8i16: return WebAssembly::CALL_INDIRECT_v8i16_S;
494 case WebAssembly::CALL_VOID: return WebAssembly::CALL_VOID_S;
495 case WebAssembly::CALL_v16i8: return WebAssembly::CALL_v16i8_S;
496 case WebAssembly::CALL_v4f32: return WebAssembly::CALL_v4f32_S;
497 case WebAssembly::CALL_v4i32: return WebAssembly::CALL_v4i32_S;
498 case WebAssembly::CALL_v8i16: return WebAssembly::CALL_v8i16_S;
499 case WebAssembly::CATCHRET: return WebAssembly::CATCHRET_S;
500 case WebAssembly::CATCH_ALL: return WebAssembly::CATCH_ALL_S;
501 case WebAssembly::CATCH_I32: return WebAssembly::CATCH_I32_S;
502 case WebAssembly::CATCH_I64: return WebAssembly::CATCH_I64_S;
503 case WebAssembly::CEIL_F32: return WebAssembly::CEIL_F32_S;
504 case WebAssembly::CEIL_F64: return WebAssembly::CEIL_F64_S;
505 case WebAssembly::CLEANUPRET: return WebAssembly::CLEANUPRET_S;
506 case WebAssembly::CLZ_I32: return WebAssembly::CLZ_I32_S;
507 case WebAssembly::CLZ_I64: return WebAssembly::CLZ_I64_S;
508 case WebAssembly::CONST_F32: return WebAssembly::CONST_F32_S;
509 case WebAssembly::CONST_F64: return WebAssembly::CONST_F64_S;
510 case WebAssembly::CONST_I32: return WebAssembly::CONST_I32_S;
511 case WebAssembly::CONST_I64: return WebAssembly::CONST_I64_S;
512 case WebAssembly::COPYSIGN_F32: return WebAssembly::COPYSIGN_F32_S;
513 case WebAssembly::COPYSIGN_F64: return WebAssembly::COPYSIGN_F64_S;
514 case WebAssembly::COPY_EXCEPT_REF: return WebAssembly::COPY_EXCEPT_REF_S;
515 case WebAssembly::COPY_F32: return WebAssembly::COPY_F32_S;
516 case WebAssembly::COPY_F64: return WebAssembly::COPY_F64_S;
517 case WebAssembly::COPY_I32: return WebAssembly::COPY_I32_S;
518 case WebAssembly::COPY_I64: return WebAssembly::COPY_I64_S;
519 case WebAssembly::COPY_V128: return WebAssembly::COPY_V128_S;
520 case WebAssembly::CTZ_I32: return WebAssembly::CTZ_I32_S;
521 case WebAssembly::CTZ_I64: return WebAssembly::CTZ_I64_S;
522 case WebAssembly::CURRENT_MEMORY_I32: return WebAssembly::CURRENT_MEMORY_I32_S;
523 case WebAssembly::DIV_F32: return WebAssembly::DIV_F32_S;
524 case WebAssembly::DIV_F64: return WebAssembly::DIV_F64_S;
525 case WebAssembly::DIV_S_I32: return WebAssembly::DIV_S_I32_S;
526 case WebAssembly::DIV_S_I64: return WebAssembly::DIV_S_I64_S;
527 case WebAssembly::DIV_U_I32: return WebAssembly::DIV_U_I32_S;
528 case WebAssembly::DIV_U_I64: return WebAssembly::DIV_U_I64_S;
529 case WebAssembly::DROP_EXCEPT_REF: return WebAssembly::DROP_EXCEPT_REF_S;
530 case WebAssembly::DROP_F32: return WebAssembly::DROP_F32_S;
531 case WebAssembly::DROP_F64: return WebAssembly::DROP_F64_S;
532 case WebAssembly::DROP_I32: return WebAssembly::DROP_I32_S;
533 case WebAssembly::DROP_I64: return WebAssembly::DROP_I64_S;
534 case WebAssembly::DROP_V128: return WebAssembly::DROP_V128_S;
535 case WebAssembly::END_BLOCK: return WebAssembly::END_BLOCK_S;
536 case WebAssembly::END_FUNCTION: return WebAssembly::END_FUNCTION_S;
537 case WebAssembly::END_LOOP: return WebAssembly::END_LOOP_S;
538 case WebAssembly::END_TRY: return WebAssembly::END_TRY_S;
539 case WebAssembly::EQZ_I32: return WebAssembly::EQZ_I32_S;
540 case WebAssembly::EQZ_I64: return WebAssembly::EQZ_I64_S;
541 case WebAssembly::EQ_F32: return WebAssembly::EQ_F32_S;
542 case WebAssembly::EQ_F64: return WebAssembly::EQ_F64_S;
543 case WebAssembly::EQ_I32: return WebAssembly::EQ_I32_S;
544 case WebAssembly::EQ_I64: return WebAssembly::EQ_I64_S;
545 case WebAssembly::F32_CONVERT_S_I32: return WebAssembly::F32_CONVERT_S_I32_S;
546 case WebAssembly::F32_CONVERT_S_I64: return WebAssembly::F32_CONVERT_S_I64_S;
547 case WebAssembly::F32_CONVERT_U_I32: return WebAssembly::F32_CONVERT_U_I32_S;
548 case WebAssembly::F32_CONVERT_U_I64: return WebAssembly::F32_CONVERT_U_I64_S;
549 case WebAssembly::F32_DEMOTE_F64: return WebAssembly::F32_DEMOTE_F64_S;
550 case WebAssembly::F32_REINTERPRET_I32: return WebAssembly::F32_REINTERPRET_I32_S;
551 case WebAssembly::F64_CONVERT_S_I32: return WebAssembly::F64_CONVERT_S_I32_S;
552 case WebAssembly::F64_CONVERT_S_I64: return WebAssembly::F64_CONVERT_S_I64_S;
553 case WebAssembly::F64_CONVERT_U_I32: return WebAssembly::F64_CONVERT_U_I32_S;
554 case WebAssembly::F64_CONVERT_U_I64: return WebAssembly::F64_CONVERT_U_I64_S;
555 case WebAssembly::F64_PROMOTE_F32: return WebAssembly::F64_PROMOTE_F32_S;
556 case WebAssembly::F64_REINTERPRET_I64: return WebAssembly::F64_REINTERPRET_I64_S;
557 case WebAssembly::FALLTHROUGH_RETURN_EXCEPT_REF: return WebAssembly::FALLTHROUGH_RETURN_EXCEPT_REF_S;
558 case WebAssembly::FALLTHROUGH_RETURN_F32: return WebAssembly::FALLTHROUGH_RETURN_F32_S;
559 case WebAssembly::FALLTHROUGH_RETURN_F64: return WebAssembly::FALLTHROUGH_RETURN_F64_S;
560 case WebAssembly::FALLTHROUGH_RETURN_I32: return WebAssembly::FALLTHROUGH_RETURN_I32_S;
561 case WebAssembly::FALLTHROUGH_RETURN_I64: return WebAssembly::FALLTHROUGH_RETURN_I64_S;
562 case WebAssembly::FALLTHROUGH_RETURN_VOID: return WebAssembly::FALLTHROUGH_RETURN_VOID_S;
563 case WebAssembly::FALLTHROUGH_RETURN_v16i8: return WebAssembly::FALLTHROUGH_RETURN_v16i8_S;
564 case WebAssembly::FALLTHROUGH_RETURN_v4f32: return WebAssembly::FALLTHROUGH_RETURN_v4f32_S;
565 case WebAssembly::FALLTHROUGH_RETURN_v4i32: return WebAssembly::FALLTHROUGH_RETURN_v4i32_S;
566 case WebAssembly::FALLTHROUGH_RETURN_v8i16: return WebAssembly::FALLTHROUGH_RETURN_v8i16_S;
567 case WebAssembly::FALLTHROUGH_RETURN_v2f64: return WebAssembly::FALLTHROUGH_RETURN_v2f64_S;
568 case WebAssembly::FALLTHROUGH_RETURN_v2i64: return WebAssembly::FALLTHROUGH_RETURN_v2i64_S;
569 case WebAssembly::FLOOR_F32: return WebAssembly::FLOOR_F32_S;
570 case WebAssembly::FLOOR_F64: return WebAssembly::FLOOR_F64_S;
571 case WebAssembly::FP_TO_SINT_I32_F32: return WebAssembly::FP_TO_SINT_I32_F32_S;
572 case WebAssembly::FP_TO_SINT_I32_F64: return WebAssembly::FP_TO_SINT_I32_F64_S;
573 case WebAssembly::FP_TO_SINT_I64_F32: return WebAssembly::FP_TO_SINT_I64_F32_S;
574 case WebAssembly::FP_TO_SINT_I64_F64: return WebAssembly::FP_TO_SINT_I64_F64_S;
575 case WebAssembly::FP_TO_UINT_I32_F32: return WebAssembly::FP_TO_UINT_I32_F32_S;
576 case WebAssembly::FP_TO_UINT_I32_F64: return WebAssembly::FP_TO_UINT_I32_F64_S;
577 case WebAssembly::FP_TO_UINT_I64_F32: return WebAssembly::FP_TO_UINT_I64_F32_S;
578 case WebAssembly::FP_TO_UINT_I64_F64: return WebAssembly::FP_TO_UINT_I64_F64_S;
579 case WebAssembly::GET_GLOBAL_EXCEPT_REF: return WebAssembly::GET_GLOBAL_EXCEPT_REF_S;
580 case WebAssembly::GET_GLOBAL_F32: return WebAssembly::GET_GLOBAL_F32_S;
581 case WebAssembly::GET_GLOBAL_F64: return WebAssembly::GET_GLOBAL_F64_S;
582 case WebAssembly::GET_GLOBAL_I32: return WebAssembly::GET_GLOBAL_I32_S;
583 case WebAssembly::GET_GLOBAL_I64: return WebAssembly::GET_GLOBAL_I64_S;
584 case WebAssembly::GET_GLOBAL_V128: return WebAssembly::GET_GLOBAL_V128_S;
585 case WebAssembly::GET_LOCAL_EXCEPT_REF: return WebAssembly::GET_LOCAL_EXCEPT_REF_S;
586 case WebAssembly::GET_LOCAL_F32: return WebAssembly::GET_LOCAL_F32_S;
587 case WebAssembly::GET_LOCAL_F64: return WebAssembly::GET_LOCAL_F64_S;
588 case WebAssembly::GET_LOCAL_I32: return WebAssembly::GET_LOCAL_I32_S;
589 case WebAssembly::GET_LOCAL_I64: return WebAssembly::GET_LOCAL_I64_S;
590 case WebAssembly::GET_LOCAL_V128: return WebAssembly::GET_LOCAL_V128_S;
591 case WebAssembly::GE_F32: return WebAssembly::GE_F32_S;
592 case WebAssembly::GE_F64: return WebAssembly::GE_F64_S;
593 case WebAssembly::GE_S_I32: return WebAssembly::GE_S_I32_S;
594 case WebAssembly::GE_S_I64: return WebAssembly::GE_S_I64_S;
595 case WebAssembly::GE_U_I32: return WebAssembly::GE_U_I32_S;
596 case WebAssembly::GE_U_I64: return WebAssembly::GE_U_I64_S;
597 case WebAssembly::GROW_MEMORY_I32: return WebAssembly::GROW_MEMORY_I32_S;
598 case WebAssembly::GT_F32: return WebAssembly::GT_F32_S;
599 case WebAssembly::GT_F64: return WebAssembly::GT_F64_S;
600 case WebAssembly::GT_S_I32: return WebAssembly::GT_S_I32_S;
601 case WebAssembly::GT_S_I64: return WebAssembly::GT_S_I64_S;
602 case WebAssembly::GT_U_I32: return WebAssembly::GT_U_I32_S;
603 case WebAssembly::GT_U_I64: return WebAssembly::GT_U_I64_S;
604 case WebAssembly::I32_EXTEND16_S_I32: return WebAssembly::I32_EXTEND16_S_I32_S;
605 case WebAssembly::I32_EXTEND8_S_I32: return WebAssembly::I32_EXTEND8_S_I32_S;
606 case WebAssembly::I32_REINTERPRET_F32: return WebAssembly::I32_REINTERPRET_F32_S;
607 case WebAssembly::I32_TRUNC_S_F32: return WebAssembly::I32_TRUNC_S_F32_S;
608 case WebAssembly::I32_TRUNC_S_F64: return WebAssembly::I32_TRUNC_S_F64_S;
609 case WebAssembly::I32_TRUNC_S_SAT_F32: return WebAssembly::I32_TRUNC_S_SAT_F32_S;
610 case WebAssembly::I32_TRUNC_S_SAT_F64: return WebAssembly::I32_TRUNC_S_SAT_F64_S;
611 case WebAssembly::I32_TRUNC_U_F32: return WebAssembly::I32_TRUNC_U_F32_S;
612 case WebAssembly::I32_TRUNC_U_F64: return WebAssembly::I32_TRUNC_U_F64_S;
613 case WebAssembly::I32_TRUNC_U_SAT_F32: return WebAssembly::I32_TRUNC_U_SAT_F32_S;
614 case WebAssembly::I32_TRUNC_U_SAT_F64: return WebAssembly::I32_TRUNC_U_SAT_F64_S;
615 case WebAssembly::I32_WRAP_I64: return WebAssembly::I32_WRAP_I64_S;
616 case WebAssembly::I64_EXTEND16_S_I64: return WebAssembly::I64_EXTEND16_S_I64_S;
617 case WebAssembly::I64_EXTEND32_S_I64: return WebAssembly::I64_EXTEND32_S_I64_S;
618 case WebAssembly::I64_EXTEND8_S_I64: return WebAssembly::I64_EXTEND8_S_I64_S;
619 case WebAssembly::I64_EXTEND_S_I32: return WebAssembly::I64_EXTEND_S_I32_S;
620 case WebAssembly::I64_EXTEND_U_I32: return WebAssembly::I64_EXTEND_U_I32_S;
621 case WebAssembly::I64_REINTERPRET_F64: return WebAssembly::I64_REINTERPRET_F64_S;
622 case WebAssembly::I64_TRUNC_S_F32: return WebAssembly::I64_TRUNC_S_F32_S;
623 case WebAssembly::I64_TRUNC_S_F64: return WebAssembly::I64_TRUNC_S_F64_S;
624 case WebAssembly::I64_TRUNC_S_SAT_F32: return WebAssembly::I64_TRUNC_S_SAT_F32_S;
625 case WebAssembly::I64_TRUNC_S_SAT_F64: return WebAssembly::I64_TRUNC_S_SAT_F64_S;
626 case WebAssembly::I64_TRUNC_U_F32: return WebAssembly::I64_TRUNC_U_F32_S;
627 case WebAssembly::I64_TRUNC_U_F64: return WebAssembly::I64_TRUNC_U_F64_S;
628 case WebAssembly::I64_TRUNC_U_SAT_F32: return WebAssembly::I64_TRUNC_U_SAT_F32_S;
629 case WebAssembly::I64_TRUNC_U_SAT_F64: return WebAssembly::I64_TRUNC_U_SAT_F64_S;
630 case WebAssembly::LE_F32: return WebAssembly::LE_F32_S;
631 case WebAssembly::LE_F64: return WebAssembly::LE_F64_S;
632 case WebAssembly::LE_S_I32: return WebAssembly::LE_S_I32_S;
633 case WebAssembly::LE_S_I64: return WebAssembly::LE_S_I64_S;
634 case WebAssembly::LE_U_I32: return WebAssembly::LE_U_I32_S;
635 case WebAssembly::LE_U_I64: return WebAssembly::LE_U_I64_S;
636 case WebAssembly::LOAD16_S_I32: return WebAssembly::LOAD16_S_I32_S;
637 case WebAssembly::LOAD16_S_I64: return WebAssembly::LOAD16_S_I64_S;
638 case WebAssembly::LOAD16_U_I32: return WebAssembly::LOAD16_U_I32_S;
639 case WebAssembly::LOAD16_U_I64: return WebAssembly::LOAD16_U_I64_S;
640 case WebAssembly::LOAD32_S_I64: return WebAssembly::LOAD32_S_I64_S;
641 case WebAssembly::LOAD32_U_I64: return WebAssembly::LOAD32_U_I64_S;
642 case WebAssembly::LOAD8_S_I32: return WebAssembly::LOAD8_S_I32_S;
643 case WebAssembly::LOAD8_S_I64: return WebAssembly::LOAD8_S_I64_S;
644 case WebAssembly::LOAD8_U_I32: return WebAssembly::LOAD8_U_I32_S;
645 case WebAssembly::LOAD8_U_I64: return WebAssembly::LOAD8_U_I64_S;
646 case WebAssembly::LOAD_F32: return WebAssembly::LOAD_F32_S;
647 case WebAssembly::LOAD_F64: return WebAssembly::LOAD_F64_S;
648 case WebAssembly::LOAD_I32: return WebAssembly::LOAD_I32_S;
649 case WebAssembly::LOAD_I64: return WebAssembly::LOAD_I64_S;
650 case WebAssembly::LOOP: return WebAssembly::LOOP_S;
651 case WebAssembly::LT_F32: return WebAssembly::LT_F32_S;
652 case WebAssembly::LT_F64: return WebAssembly::LT_F64_S;
653 case WebAssembly::LT_S_I32: return WebAssembly::LT_S_I32_S;
654 case WebAssembly::LT_S_I64: return WebAssembly::LT_S_I64_S;
655 case WebAssembly::LT_U_I32: return WebAssembly::LT_U_I32_S;
656 case WebAssembly::LT_U_I64: return WebAssembly::LT_U_I64_S;
657 case WebAssembly::MAX_F32: return WebAssembly::MAX_F32_S;
658 case WebAssembly::MAX_F64: return WebAssembly::MAX_F64_S;
659 case WebAssembly::MEMORY_GROW_I32: return WebAssembly::MEMORY_GROW_I32_S;
660 case WebAssembly::MEMORY_SIZE_I32: return WebAssembly::MEMORY_SIZE_I32_S;
661 case WebAssembly::MEM_GROW_I32: return WebAssembly::MEM_GROW_I32_S;
662 case WebAssembly::MEM_SIZE_I32: return WebAssembly::MEM_SIZE_I32_S;
663 case WebAssembly::MIN_F32: return WebAssembly::MIN_F32_S;
664 case WebAssembly::MIN_F64: return WebAssembly::MIN_F64_S;
665 case WebAssembly::MUL_F32: return WebAssembly::MUL_F32_S;
666 case WebAssembly::MUL_F32x4: return WebAssembly::MUL_F32x4_S;
667 case WebAssembly::MUL_F64: return WebAssembly::MUL_F64_S;
668 case WebAssembly::MUL_I16x8: return WebAssembly::MUL_I16x8_S;
669 case WebAssembly::MUL_I32: return WebAssembly::MUL_I32_S;
670 case WebAssembly::MUL_I32x4: return WebAssembly::MUL_I32x4_S;
671 case WebAssembly::MUL_I64: return WebAssembly::MUL_I64_S;
672 case WebAssembly::MUL_I8x16: return WebAssembly::MUL_I8x16_S;
673 case WebAssembly::NEAREST_F32: return WebAssembly::NEAREST_F32_S;
674 case WebAssembly::NEAREST_F64: return WebAssembly::NEAREST_F64_S;
675 case WebAssembly::NEG_F32: return WebAssembly::NEG_F32_S;
676 case WebAssembly::NEG_F64: return WebAssembly::NEG_F64_S;
677 case WebAssembly::NE_F32: return WebAssembly::NE_F32_S;
678 case WebAssembly::NE_F64: return WebAssembly::NE_F64_S;
679 case WebAssembly::NE_I32: return WebAssembly::NE_I32_S;
680 case WebAssembly::NE_I64: return WebAssembly::NE_I64_S;
681 case WebAssembly::NOP: return WebAssembly::NOP_S;
682 case WebAssembly::OR_I32: return WebAssembly::OR_I32_S;
683 case WebAssembly::OR_I64: return WebAssembly::OR_I64_S;
684 case WebAssembly::PCALL_INDIRECT_EXCEPT_REF: return WebAssembly::PCALL_INDIRECT_EXCEPT_REF_S;
685 case WebAssembly::PCALL_INDIRECT_F32: return WebAssembly::PCALL_INDIRECT_F32_S;
686 case WebAssembly::PCALL_INDIRECT_F64: return WebAssembly::PCALL_INDIRECT_F64_S;
687 case WebAssembly::PCALL_INDIRECT_I32: return WebAssembly::PCALL_INDIRECT_I32_S;
688 case WebAssembly::PCALL_INDIRECT_I64: return WebAssembly::PCALL_INDIRECT_I64_S;
689 case WebAssembly::PCALL_INDIRECT_VOID: return WebAssembly::PCALL_INDIRECT_VOID_S;
690 case WebAssembly::PCALL_INDIRECT_v16i8: return WebAssembly::PCALL_INDIRECT_v16i8_S;
691 case WebAssembly::PCALL_INDIRECT_v4f32: return WebAssembly::PCALL_INDIRECT_v4f32_S;
692 case WebAssembly::PCALL_INDIRECT_v4i32: return WebAssembly::PCALL_INDIRECT_v4i32_S;
693 case WebAssembly::PCALL_INDIRECT_v8i16: return WebAssembly::PCALL_INDIRECT_v8i16_S;
694 case WebAssembly::POPCNT_I32: return WebAssembly::POPCNT_I32_S;
695 case WebAssembly::POPCNT_I64: return WebAssembly::POPCNT_I64_S;
696 case WebAssembly::REM_S_I32: return WebAssembly::REM_S_I32_S;
697 case WebAssembly::REM_S_I64: return WebAssembly::REM_S_I64_S;
698 case WebAssembly::REM_U_I32: return WebAssembly::REM_U_I32_S;
699 case WebAssembly::REM_U_I64: return WebAssembly::REM_U_I64_S;
700 case WebAssembly::RETHROW: return WebAssembly::RETHROW_S;
701 case WebAssembly::RETHROW_TO_CALLER: return WebAssembly::RETHROW_TO_CALLER_S;
702 case WebAssembly::RETURN_EXCEPT_REF: return WebAssembly::RETURN_EXCEPT_REF_S;
703 case WebAssembly::RETURN_F32: return WebAssembly::RETURN_F32_S;
704 case WebAssembly::RETURN_F64: return WebAssembly::RETURN_F64_S;
705 case WebAssembly::RETURN_I32: return WebAssembly::RETURN_I32_S;
706 case WebAssembly::RETURN_I64: return WebAssembly::RETURN_I64_S;
707 case WebAssembly::RETURN_VOID: return WebAssembly::RETURN_VOID_S;
708 case WebAssembly::RETURN_v16i8: return WebAssembly::RETURN_v16i8_S;
709 case WebAssembly::RETURN_v4f32: return WebAssembly::RETURN_v4f32_S;
710 case WebAssembly::RETURN_v4i32: return WebAssembly::RETURN_v4i32_S;
711 case WebAssembly::RETURN_v8i16: return WebAssembly::RETURN_v8i16_S;
712 case WebAssembly::ROTL_I32: return WebAssembly::ROTL_I32_S;
713 case WebAssembly::ROTL_I64: return WebAssembly::ROTL_I64_S;
714 case WebAssembly::ROTR_I32: return WebAssembly::ROTR_I32_S;
715 case WebAssembly::ROTR_I64: return WebAssembly::ROTR_I64_S;
716 case WebAssembly::SELECT_EXCEPT_REF: return WebAssembly::SELECT_EXCEPT_REF_S;
717 case WebAssembly::SELECT_F32: return WebAssembly::SELECT_F32_S;
718 case WebAssembly::SELECT_F64: return WebAssembly::SELECT_F64_S;
719 case WebAssembly::SELECT_I32: return WebAssembly::SELECT_I32_S;
720 case WebAssembly::SELECT_I64: return WebAssembly::SELECT_I64_S;
721 case WebAssembly::SET_GLOBAL_EXCEPT_REF: return WebAssembly::SET_GLOBAL_EXCEPT_REF_S;
722 case WebAssembly::SET_GLOBAL_F32: return WebAssembly::SET_GLOBAL_F32_S;
723 case WebAssembly::SET_GLOBAL_F64: return WebAssembly::SET_GLOBAL_F64_S;
724 case WebAssembly::SET_GLOBAL_I32: return WebAssembly::SET_GLOBAL_I32_S;
725 case WebAssembly::SET_GLOBAL_I64: return WebAssembly::SET_GLOBAL_I64_S;
726 case WebAssembly::SET_GLOBAL_V128: return WebAssembly::SET_GLOBAL_V128_S;
727 case WebAssembly::SET_LOCAL_EXCEPT_REF: return WebAssembly::SET_LOCAL_EXCEPT_REF_S;
728 case WebAssembly::SET_LOCAL_F32: return WebAssembly::SET_LOCAL_F32_S;
729 case WebAssembly::SET_LOCAL_F64: return WebAssembly::SET_LOCAL_F64_S;
730 case WebAssembly::SET_LOCAL_I32: return WebAssembly::SET_LOCAL_I32_S;
731 case WebAssembly::SET_LOCAL_I64: return WebAssembly::SET_LOCAL_I64_S;
732 case WebAssembly::SET_LOCAL_V128: return WebAssembly::SET_LOCAL_V128_S;
733 case WebAssembly::SHL_I32: return WebAssembly::SHL_I32_S;
734 case WebAssembly::SHL_I64: return WebAssembly::SHL_I64_S;
735 case WebAssembly::SHR_S_I32: return WebAssembly::SHR_S_I32_S;
736 case WebAssembly::SHR_S_I64: return WebAssembly::SHR_S_I64_S;
737 case WebAssembly::SHR_U_I32: return WebAssembly::SHR_U_I32_S;
738 case WebAssembly::SHR_U_I64: return WebAssembly::SHR_U_I64_S;
739 case WebAssembly::SQRT_F32: return WebAssembly::SQRT_F32_S;
740 case WebAssembly::SQRT_F64: return WebAssembly::SQRT_F64_S;
741 case WebAssembly::STORE16_I32: return WebAssembly::STORE16_I32_S;
742 case WebAssembly::STORE16_I64: return WebAssembly::STORE16_I64_S;
743 case WebAssembly::STORE32_I64: return WebAssembly::STORE32_I64_S;
744 case WebAssembly::STORE8_I32: return WebAssembly::STORE8_I32_S;
745 case WebAssembly::STORE8_I64: return WebAssembly::STORE8_I64_S;
746 case WebAssembly::STORE_F32: return WebAssembly::STORE_F32_S;
747 case WebAssembly::STORE_F64: return WebAssembly::STORE_F64_S;
748 case WebAssembly::STORE_I32: return WebAssembly::STORE_I32_S;
749 case WebAssembly::STORE_I64: return WebAssembly::STORE_I64_S;
750 case WebAssembly::SUB_F32: return WebAssembly::SUB_F32_S;
751 case WebAssembly::SUB_F32x4: return WebAssembly::SUB_F32x4_S;
752 case WebAssembly::SUB_F64: return WebAssembly::SUB_F64_S;
753 case WebAssembly::SUB_I16x8: return WebAssembly::SUB_I16x8_S;
754 case WebAssembly::SUB_I32: return WebAssembly::SUB_I32_S;
755 case WebAssembly::SUB_I32x4: return WebAssembly::SUB_I32x4_S;
756 case WebAssembly::SUB_I64: return WebAssembly::SUB_I64_S;
757 case WebAssembly::SUB_I8x16: return WebAssembly::SUB_I8x16_S;
758 case WebAssembly::TEE_EXCEPT_REF: return WebAssembly::TEE_EXCEPT_REF_S;
759 case WebAssembly::TEE_F32: return WebAssembly::TEE_F32_S;
760 case WebAssembly::TEE_F64: return WebAssembly::TEE_F64_S;
761 case WebAssembly::TEE_I32: return WebAssembly::TEE_I32_S;
762 case WebAssembly::TEE_I64: return WebAssembly::TEE_I64_S;
763 case WebAssembly::TEE_LOCAL_EXCEPT_REF: return WebAssembly::TEE_LOCAL_EXCEPT_REF_S;
764 case WebAssembly::TEE_LOCAL_F32: return WebAssembly::TEE_LOCAL_F32_S;
765 case WebAssembly::TEE_LOCAL_F64: return WebAssembly::TEE_LOCAL_F64_S;
766 case WebAssembly::TEE_LOCAL_I32: return WebAssembly::TEE_LOCAL_I32_S;
767 case WebAssembly::TEE_LOCAL_I64: return WebAssembly::TEE_LOCAL_I64_S;
768 case WebAssembly::TEE_LOCAL_V128: return WebAssembly::TEE_LOCAL_V128_S;
769 case WebAssembly::TEE_V128: return WebAssembly::TEE_V128_S;
770 case WebAssembly::THROW_I32: return WebAssembly::THROW_I32_S;
771 case WebAssembly::THROW_I64: return WebAssembly::THROW_I64_S;
772 case WebAssembly::TRUNC_F32: return WebAssembly::TRUNC_F32_S;
773 case WebAssembly::TRUNC_F64: return WebAssembly::TRUNC_F64_S;
774 case WebAssembly::TRY: return WebAssembly::TRY_S;
775 case WebAssembly::UNREACHABLE: return WebAssembly::UNREACHABLE_S;
776 case WebAssembly::XOR_I32: return WebAssembly::XOR_I32_S;
777 case WebAssembly::XOR_I64: return WebAssembly::XOR_I64_S;
778 }
779 }
5252 let TSFlags{0} = 1;
5353 let TSFlags{1} = 1;
5454 }
55 def BR_TABLE_I32_S : NI<(outs), (ins variable_ops),
55 def BR_TABLE_I32_S : NI<(outs), (ins I32:$index),
5656 [], 1,
57 "br_table", 0x0e> {
57 "br_table \t$index", 0x0e> {
5858 let TSFlags{0} = 1;
5959 let TSFlags{1} = 1;
6060 }
6464 let TSFlags{0} = 1;
6565 let TSFlags{1} = 1;
6666 }
67 def BR_TABLE_I64_S : NI<(outs), (ins variable_ops),
67 def BR_TABLE_I64_S : NI<(outs), (ins I64:$index),
6868 [], 1,
69 "br_table"> {
69 "br_table \t$index"> {
7070 let TSFlags{0} = 1;
7171 let TSFlags{1} = 1;
7272 }
5656
5757 // Defines atomic and non-atomic loads, regular and extending.
5858 multiclass WebAssemblyLoad {
59 let mayLoad = 1 in
6059 defm "": I<(outs rc:$dst),
6160 (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
6261 (outs), (ins P2Align:$p2align, offset32_op:$off),
6362 [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
64 !strconcat(Name, "\t${off}${p2align}"), Opcode>;
63 !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
6564 }
6665
6766 // Basic load.
307306
308307 // Defines atomic and non-atomic stores, regular and truncating
309308 multiclass WebAssemblyStore {
310 let mayStore = 1 in
311309 defm "" : I<(outs),
312310 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
313311 (outs),
314312 (ins P2Align:$p2align, offset32_op:$off), [],
315313 !strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
316 !strconcat(Name, "\t${off}${p2align}"), Opcode>;
314 !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
317315 }
318316 // Basic store.
319317 // Note: WebAssembly inverts SelectionDAG's usual operand order.
471469
472470 // Grow memory.
473471 defm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
474 (outs), (ins i32imm:$flags),
472 (outs), (ins i32imm:$flags, I32:$delta),
475473 [(set I32:$dst,
476474 (int_wasm_memory_grow (i32 imm:$flags),
477475 I32:$delta))],
478476 "memory.grow\t$dst, $flags, $delta",
479 "memory.grow\t$flags", 0x3f>,
477 "memory.grow\t$flags, $delta", 0x3f>,
480478 Requires<[HasAddr32]>;
481479 defm MEM_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
482480 (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
319322 // Do various transformations for exception handling
320323 addPass(createWebAssemblyLateEHPrepare());
321324
333336 if (getOptLevel() != CodeGenOpt::None)
334337 addPass(createWebAssemblyPeephole());
335338
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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test folding constant offsets and symbols into load and store addresses under
33 ; a variety of circumstances.
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 -wasm-register-codegen-test-mode -mattr=+atomics,+sign-ext | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+atomics,+sign-ext | FileCheck %s
22
33 ; Currently all wasm atomic memory access instructions are sequentially
44 ; consistent, so even if LLVM IR specifies weaker orderings than that, we
None ; 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
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
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 -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
0 ; 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
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-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
0 ; 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
22
33 ; Test that basic call operations assemble as expected.
44
None ; 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 -exception-model=wasm -mattr=+exception-handling | FileCheck %s
0 ; 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 -exception-model=wasm -mattr=+exception-handling | 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 -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
0 ; 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
22
33 ; Test the CFG stackifier pass.
44
None ; RUN: opt -S -lowertypetests < %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: opt -S -lowertypetests < %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | 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 -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
0 ; 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
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 -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
0 ; 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
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 -wasm-register-codegen-test-mode -mattr=-nontrapping-fptoint | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -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 -wasm-register-codegen-test-mode -mattr=+nontrapping-fptoint | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+nontrapping-fptoint | FileCheck %s
11
22 ; Test that basic conversion operations assemble as expected.
33
None ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false | 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 -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
0 ; 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
22
33 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
44 target triple = "wasm32-unknown-unknown"
5959 ; CHECK-LABEL: test_cleanup:
6060 ; CHECK: call foo@FUNCTION
6161 ; CHECK: catch_all
62 ; CHECK: i32.call $push{{.+}}=, _ZN7CleanupD1Ev@FUNCTION
62 ; CHECK: i32.call $push20=, _ZN7CleanupD1Ev@FUNCTION
6363 ; CHECK: rethrow
6464 define void @test_cleanup() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
6565 entry:
None # RUN: llc -mtriple=wasm32-unknown-unknown -run-pass wasm-explicit-locals -wasm-explicit-locals-codegen-test-mode %s -o - | FileCheck %s
0 # RUN: llc -mtriple=wasm32-unknown-unknown -run-pass wasm-explicit-locals %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 -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
0 ; 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
22
33 ; Test that f16 is expanded.
44
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -fast-isel -asm-verbose=false | 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 -wasm-explicit-locals-codegen-test-mode
0 ; RUN: llc < %s -O0
11 ; PR36564
22 ; PR37546
33
None ; RUN: llc < %s -O0 -wasm-explicit-locals-codegen-test-mode
0 ; RUN: llc < %s -O0
11 ; PR36564
22 ; PR37546
33
None ; 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
0 ; 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
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: -wasm-register-codegen-test-mode \
2 ; RUN: -disable-wasm-explicit-locals \
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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test that the frem instruction works.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test that basic functions assemble as expected.
33
None ; RUN: llc < %s -asm-verbose=false -wasm-temporary-workarounds=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -wasm-temporary-workarounds=false | FileCheck %s
11
22 ; Test that function pointer casts casting away varargs are replaced with
33 ; wrappers.
None ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode -enable-emscripten-cxx-exceptions -wasm-temporary-workarounds=false | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals -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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test that globals assemble as expected.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | 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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -mattr=+atomics -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | 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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -mattr=+atomics -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
11
22 ; Test that basic 64-bit integer operations assemble as expected.
33
None ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false | FileCheck %s
11
22 ; Test llvm.ident.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
11
22 ; Test that basic immediates assemble as expected.
33
None ; RUN: llc -o - %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc -o - %s -asm-verbose=false | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false | 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 -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
0 ; 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
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 -wasm-register-codegen-test-mode -no-integrated-as
0 ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -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 -wasm-explicit-locals-codegen-test-mode -no-integrated-as | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-block-placement -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test irreducible CFG handling.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | 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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -mattr=+atomics,+sign-ext -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test that extending loads are assembled properly.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test that extending loads are assembled properly.
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | 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 -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
0 ; 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
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 saveSetjmp@FUNCTION
42 ; SJLJ: i32.call testSetjmp@FUNCTION
43 ; NONE: i32.call setjmp@FUNCTION
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
4444 ; NONE: call longjmp@FUNCTION
4545 }
4646
None ; RUN: llc < %s -asm-verbose=false -wasm-explicit-locals-codegen-test-mode | FileCheck --check-prefix=CHECK --check-prefix=FINI --check-prefix=NULL %s
0 ; RUN: llc < %s -asm-verbose=false | 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 -wasm-register-codegen-test-mode -tail-dup-placement=0 | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test that basic memory operations assemble as expected with 32-bit addresses.
33
None ; RUN: llc -asm-verbose=false < %s -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc -asm-verbose=false < %s | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt | 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 -wasm-register-codegen-test-mode -mattr=+atomics,+sign-ext | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+atomics,+sign-ext | FileCheck %s
22
33 ; Test that atomic loads are assembled properly.
44
None ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode -fast-isel -fast-isel-abort=1 | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals -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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false | FileCheck %s
11
22 ; Test that constant offsets can be folded into global addresses.
33
None ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode -disable-wasm-fallthrough-return-opt | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals -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 -wasm-register-codegen-test-mode -verify-machineinstrs | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -verify-machineinstrs | FileCheck %s
11
22 ; Test that phis are lowered.
33
None ; 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
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -verify-machineinstrs | FileCheck %s
21
32 ; 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).
73
84 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
95 target triple = "wasm32-unknown-unknown"
128
139 ; CHECK-LABEL: no0:
1410 ; CHECK: return $1{{$}}
15 ; NOREGS-LABEL: no0:
16 ; NOREGS: return{{$}}
1711 define i32 @no0(i32* %p, i32* %q) {
1812 %t = load i32, i32* %q
1913 store i32 0, i32* %p
2418
2519 ; CHECK-LABEL: no1:
2620 ; CHECK: return $1{{$}}
27 ; NOREGS-LABEL: no1:
28 ; NOREGS: return{{$}}
2921 define i32 @no1(i32* %p, i32* dereferenceable(4) %q) {
3022 %t = load volatile i32, i32* %q, !invariant.load !0
3123 store volatile i32 0, i32* %p
3628
3729 ; CHECK-LABEL: yes0:
3830 ; CHECK: return $pop{{[0-9]+}}{{$}}
39 ; NOREGS-LABEL: yes0:
40 ; NOREGS: return{{$}}
4131 define i32 @yes0(i32* %p, i32* dereferenceable(4) %q) {
4232 %t = load i32, i32* %q, !invariant.load !0
4333 store i32 0, i32* %p
4838
4939 ; CHECK-LABEL: yes1:
5040 ; CHECK: return $pop0{{$}}
51 ; NOREGS-LABEL: yes1:
52 ; NOREGS: return{{$}}
5341 define i32 @yes1(i32* %q) {
5442 %t = load volatile i32, i32* %q
5543 ret i32 %t
5947
6048 ; CHECK-LABEL: sink_trap:
6149 ; CHECK: return $pop{{[0-9]+}}{{$}}
62 ; NOREGS-LABEL: sink_trap:
63 ; NOREGS: return{{$}}
6450 define i32 @sink_trap(i32 %x, i32 %y, i32* %p) {
6551 %t = sdiv i32 %x, %y
6652 store volatile i32 0, i32* %p
7157
7258 ; CHECK-LABEL: sink_readnone_call:
7359 ; CHECK: return $pop0{{$}}
74 ; NOREGS-LABEL: sink_readnone_call:
75 ; NOREGS: return{{$}}
7660 declare i32 @readnone_callee() readnone nounwind
7761 define i32 @sink_readnone_call(i32 %x, i32 %y, i32* %p) {
7862 %t = call i32 @readnone_callee()
8468
8569 ; CHECK-LABEL: no_sink_readonly_call:
8670 ; CHECK: return ${{[0-9]+}}{{$}}
87 ; NOREGS-LABEL: no_sink_readonly_call:
88 ; NOREGS: return{{$}}
8971 declare i32 @readonly_callee() readonly nounwind
9072 define i32 @no_sink_readonly_call(i32 %x, i32 %y, i32* %p) {
9173 %t = call i32 @readonly_callee()
122104 ; CHECK-NEXT: end_block{{$}}
123105 ; CHECK-NEXT: i32.const $push14=, 1{{$}}
124106 ; 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{{$}}
153107 define i32 @stack_uses(i32 %x, i32 %y, i32 %z, i32 %w) {
154108 entry:
155109 %c = icmp sle i32 %x, 0
182136 ; CHECK-NEXT: .LBB8_3:
183137 ; CHECK-NEXT: end_block{{$}}
184138 ; 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{{$}}
205139 define void @multiple_uses(i32* %arg0, i32* %arg1, i32* %arg2) nounwind {
206140 bb:
207141 br label %loop
232166 ; CHECK-NEXT: call
233167 ; CHECK: store
234168 ; CHECK-NEXT: call
235 ; NOREGS: side_effects:
236 ; NOREGS: store
237 ; NOREGS-NEXT: call
238 ; NOREGS: store
239 ; NOREGS-NEXT: call
240169 declare void @evoke_side_effects()
241170 define hidden void @stackify_store_across_side_effects(double* nocapture %d) {
242171 entry:
270199 ; CHECK-NEXT: i32.div_s $push[[L13:[0-9]+]]=, $pop[[L9]], $pop[[L12]]{{$}}
271200 ; CHECK-NEXT: i32.div_s $push[[L14:[0-9]+]]=, $pop[[L6]], $pop[[L13]]{{$}}
272201 ; 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{{$}}
308202 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) {
309203 entry:
310204 %div = sdiv i32 %a, %b
334228 ; CHECK-NEXT: call use_a@FUNCTION, $pop[[NUM1]]{{$}}
335229 ; CHECK-NEXT: call use_b@FUNCTION, $[[NUM2]]{{$}}
336230 ; 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{{$}}
347231 declare void @use_a(i32)
348232 declare void @use_b(i32)
349233 define void @simple_multiple_use(i32 %x, i32 %y) {
361245 ; CHECK-NEXT: tee_local $push[[NUM1:[0-9]+]]=, $[[NUM2:[0-9]+]]=, $pop[[NUM0]]{{$}}
362246 ; CHECK-NEXT: call use_2@FUNCTION, $pop[[NUM1]], $[[NUM2]]{{$}}
363247 ; 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{{$}}
373248 declare void @use_2(i32, i32)
374249 define void @multiple_uses_in_same_insn(i32 %x, i32 %y) {
375250 %mul = mul i32 %y, %x
388263 ; CHECK-NEXT: i32.call $push3=, blue@FUNCTION{{$}}
389264 ; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
390265 ; 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{{$}}
400266 declare i32 @red()
401267 declare i32 @green()
402268 declare i32 @blue()
420286 ; CHECK-NEXT: i32.sub $push3=, $pop2, $1
421287 ; CHECK-NEXT: i32.div_s $push4=, $pop3, $1
422288 ; 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
436289 declare i32 @callee(i32)
437290 define i32 @no_stackify_past_use(i32 %arg) {
438291 %tmp1 = call i32 @callee(i32 %arg)
455308 ; CHECK: i32.add $push3=, $1, $pop2
456309 ; CHECK: i32.mul $push4=, $pop[[L1]], $pop3
457310 ; 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
470311 define i32 @commute_to_fix_ordering(i32 %arg) {
471312 %tmp1 = call i32 @callee(i32 %arg)
472313 %tmp2 = add i32 %arg, 1
483324 ; CHECK-NEXT: tee_local $push[[NUM1:[0-9]+]]=, $[[NUM2:[0-9]+]]=, $pop[[NUM0]]{{$}}
484325 ; CHECK-NEXT: f64.select $push{{[0-9]+}}=, $pop{{[0-9]+}}, $pop[[NUM1]], ${{[0-9]+}}{{$}}
485326 ; CHECK: $[[NUM2]]=,
486 ; NOREGS-LABEL: multiple_defs:
487 ; NOREGS: f64.add
488 ; NOREGS: tee_local
489 ; NOREGS: f64.select
490327 define void @multiple_defs(i32 %arg, i32 %arg1, i1 %arg2, i1 %arg3, i1 %arg4) {
491328 bb:
492329 br label %bb5
529366 ; CHECK: i32.call $0=, red
530367 ; CHECK: i32.const $push0=, 0
531368 ; 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
536369 @count = hidden global i32 0, align 4
537370 define i32 @no_stackify_call_past_load() {
538371 %a = call i32 @red()
547380 ; CHECK: i32.store 0($1), $0
548381 ; CHECK: i32.load {{.*}}, 0($2)
549382 ; 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{{$}}
554383 define i32 @no_stackify_store_past_load(i32 %a, i32* %p1, i32* %p2) {
555384 store i32 %a, i32* %p1
556385 %b = load i32, i32* %p2, align 4
564393 ; CHECK: i32.call {{.*}}, callee@FUNCTION, $0
565394 ; CHECK: i32.load $push{{.*}}, 0($2)
566395 ; 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
572396 define i32 @store_past_invar_load(i32 %a, i32* %p1, i32* dereferenceable(4) %p2) {
573397 store i32 %a, i32* %p1
574398 %b = load i32, i32* %p2, !invariant.load !0
579403 ; CHECK-LABEL: ignore_dbg_value:
580404 ; CHECK-NEXT: .Lfunc_begin
581405 ; CHECK-NEXT: unreachable
582 ; NOREGS-LABEL: ignore_dbg_value:
583 ; NOREGS-NEXT: .Lfunc_begin
584 ; NOREGS-NEXT: unreachable
585406 declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
586407 define void @ignore_dbg_value() {
587408 call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !7, metadata !9), !dbg !10
593414
594415 ; CHECK-LABEL: no_stackify_past_epilogue:
595416 ; CHECK: return ${{[0-9]+}}{{$}}
596 ; NOREGS-LABEL: no_stackify_past_epilogue:
597 ; NOREGS: return{{$}}
598417 declare i32 @use_memory(i32*)
599418 define i32 @no_stackify_past_epilogue() {
600419 %x = alloca i32
609428 ; CHECK-NEXT: i32.add $push[[L4:.+]]=, $[[R0:.+]], $pop[[L5]]{{$}}
610429 ; CHECK-NEXT: tee_local $push[[L3:.+]]=, $[[R0]]=, $pop[[L4]]{{$}}
611430 ; 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
617431 define void @stackify_indvar(i32 %tmp, i32* %v) #0 {
618432 bb:
619433 br label %bb3
636450 ; CHECK-LABEL: stackpointer_dependency:
637451 ; CHECK: call {{.+}}, stackpointer_callee@FUNCTION,
638452 ; CHECK-NEXT: set_global __stack_pointer@GLOBAL,
639 ; NOREGS-LABEL: stackpointer_dependency:
640 ; NOREGS: call stackpointer_callee@FUNCTION
641 ; NOREGS: set_global __stack_pointer
642453 declare i32 @stackpointer_callee(i8* readnone, i8* readnone)
643454 declare i8* @llvm.frameaddress(i32)
644455 define i32 @stackpointer_dependency(i8* readnone) {
655466 ; CHECK-NEXT: i32.load $push[[L0:.+]]=, 0($0)
656467 ; CHECK-NEXT: i32.load $push[[L1:.+]]=, 0($pop[[L0]])
657468 ; 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
664469 %class.call_indirect = type { i32 (...)** }
665470 define i32 @call_indirect_stackify(%class.call_indirect** %objptr, i32 %arg) {
666471 %obj = load %class.call_indirect*, %class.call_indirect** %objptr
685490 !8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
686491 !9 = !DIExpression()
687492 !10 = !DILocation(line: 15, column: 6, scope: !5)
688
None ; 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
0 ; RUN: llc < %s -asm-verbose=false | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | 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 -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
0 ; 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
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 -wasm-register-codegen-test-mode | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals | 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 -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
0 ; 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
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-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test zeroext and signext ABI keywords
33
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -wasm-enable-unimplemented-simd -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 -wasm-enable-unimplemented-simd -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,SIMD128-VM
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,SIMD128-VM
4 ; 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
5 ; 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
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -wasm-enable-unimplemented-simd -mattr=+simd128 | FileCheck %s --check-prefixes CHECK,SIMD128
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -wasm-enable-unimplemented-simd -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,SIMD128-VM
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,SIMD128-VM
4 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=-simd128 | FileCheck %s --check-prefixes CHECK,NO-SIMD128
5 ; 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
66
77 ; Test that basic SIMD128 arithmetic operations assemble as expected.
88
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | 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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -mattr=+atomics,+sign-ext -asm-verbose=false -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test that truncating stores are assembled properly.
33
None ; RUN: llc < %s -asm-verbose=false -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals | FileCheck %s
11
22 ; Test that truncating stores are assembled properly.
33
None ; 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
0 ; 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
22
33 ; Test that basic stores are assembled properly.
44
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode -disable-block-placement -verify-machineinstrs | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -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 -wasm-register-codegen-test-mode -thread-model=single | FileCheck --check-prefix=SINGLE %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -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 -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-explicit-locals | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false | FileCheck %s
11
22 ; Test that function pointer casts that require conversions of arguments or
33 ; return types are converted to unreachable.
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-register-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | 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 -wasm-explicit-locals-codegen-test-mode | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | 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 -wasm-register-codegen-test-mode -verify-machineinstrs | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -verify-machineinstrs | FileCheck %s
11
22 ; Test varargs constructs.
33
None ; 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
0 ; 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
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
13 # CHECK: i64.load32_u 16, :p2align=1
14 # FIXME: fix p2align output in WebAssemblyInstPrinter
1415 0x35 0x01 0x10
1516
1617 # CHECK: block
66 .param i32, i64
77 .local f32, f64 #, i8x16, i16x8, i32x4, f32x4
88 # Explicit getlocal/setlocal:
9 get_local 2
10 set_local 2
11 # Immediates:
12 i32.const -1
13 f64.const 0x1.999999999999ap1
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
1414 # Indirect addressing:
15 get_local 0
16 f64.store 0
15 get_local $push1=, 0
16 f64.store 0($pop1), $3
1717 # Loops, conditionals, binary ops, calls etc:
1818 block
19 i32.const 1
20 get_local 0
21 i32.ge_s
22 br_if 0 # 0: down to label0
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
2323 .LBB0_1:
2424 loop # 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
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
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 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
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
5252 # CHECK-NEXT: block
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
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
5757 # CHECK-NEXT: .LBB0_1:
5858 # CHECK-NEXT: loop # label1:
5959 # CHECK-NEXT: call something1@FUNCTION
60 # CHECK-NEXT: i64.const 1234
61 # CHECK-NEXT: i32.call something2@FUNCTION
62 # CHECK-NEXT: i32.const 0
60 # CHECK-NEXT: i64.const $push10=, 1234
61 # CHECK-NEXT: i32.call $push8=, something2@FUNCTION
62 # CHECK-NEXT: i32.const $push11=, 0
6363 # CHECK-NEXT: call_indirect
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
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
7070 # CHECK-NEXT: .LBB0_2:
7171 # CHECK-NEXT: end_loop
7272 # CHECK-NEXT: end_block # label0:
None ; RUN: llc -filetype=obj -wasm-explicit-locals-codegen-test-mode %s -o - | llvm-readobj -r -expand-relocs | FileCheck %s
0 ; RUN: llc -filetype=obj %s -o - | llvm-readobj -r -expand-relocs | FileCheck %s
11
22 target triple = "wasm32-unknown-unknown"
33
None ; RUN: llc -filetype=obj -wasm-explicit-locals-codegen-test-mode %s -o %t.o
0 ; RUN: llc -filetype=obj %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 }