xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric // WebAssemblyMCInstLower.cpp - Convert WebAssembly MachineInstr to an MCInst //
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric ///
9*0b57cec5SDimitry Andric /// \file
10*0b57cec5SDimitry Andric /// This file contains code to lower WebAssembly MachineInstrs to their
11*0b57cec5SDimitry Andric /// corresponding MCInst records.
12*0b57cec5SDimitry Andric ///
13*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14*0b57cec5SDimitry Andric 
15*0b57cec5SDimitry Andric #include "WebAssemblyMCInstLower.h"
16*0b57cec5SDimitry Andric #include "WebAssemblyAsmPrinter.h"
17*0b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
18*0b57cec5SDimitry Andric #include "WebAssemblyRuntimeLibcallSignatures.h"
19*0b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
20*0b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
22*0b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
23*0b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
24*0b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
25*0b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
26*0b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
27*0b57cec5SDimitry Andric #include "llvm/MC/MCSymbolWasm.h"
28*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
29*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
30*0b57cec5SDimitry Andric using namespace llvm;
31*0b57cec5SDimitry Andric 
32*0b57cec5SDimitry Andric // Defines llvm::WebAssembly::getStackOpcode to convert register instructions to
33*0b57cec5SDimitry Andric // stack instructions
34*0b57cec5SDimitry Andric #define GET_INSTRMAP_INFO 1
35*0b57cec5SDimitry Andric #include "WebAssemblyGenInstrInfo.inc"
36*0b57cec5SDimitry Andric 
37*0b57cec5SDimitry Andric // This disables the removal of registers when lowering into MC, as required
38*0b57cec5SDimitry Andric // by some current tests.
39*0b57cec5SDimitry Andric cl::opt<bool>
40*0b57cec5SDimitry Andric     WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
41*0b57cec5SDimitry Andric                       cl::desc("WebAssembly: output stack registers in"
42*0b57cec5SDimitry Andric                                " instruction output for test purposes only."),
43*0b57cec5SDimitry Andric                       cl::init(false));
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric MCSymbol *
48*0b57cec5SDimitry Andric WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
49*0b57cec5SDimitry Andric   const GlobalValue *Global = MO.getGlobal();
50*0b57cec5SDimitry Andric   auto *WasmSym = cast<MCSymbolWasm>(Printer.getSymbol(Global));
51*0b57cec5SDimitry Andric 
52*0b57cec5SDimitry Andric   if (const auto *FuncTy = dyn_cast<FunctionType>(Global->getValueType())) {
53*0b57cec5SDimitry Andric     const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
54*0b57cec5SDimitry Andric     const TargetMachine &TM = MF.getTarget();
55*0b57cec5SDimitry Andric     const Function &CurrentFunc = MF.getFunction();
56*0b57cec5SDimitry Andric 
57*0b57cec5SDimitry Andric     SmallVector<MVT, 1> ResultMVTs;
58*0b57cec5SDimitry Andric     SmallVector<MVT, 4> ParamMVTs;
59*0b57cec5SDimitry Andric     computeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs);
60*0b57cec5SDimitry Andric 
61*0b57cec5SDimitry Andric     auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs);
62*0b57cec5SDimitry Andric     WasmSym->setSignature(Signature.get());
63*0b57cec5SDimitry Andric     Printer.addSignature(std::move(Signature));
64*0b57cec5SDimitry Andric     WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
65*0b57cec5SDimitry Andric   }
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric   return WasmSym;
68*0b57cec5SDimitry Andric }
69*0b57cec5SDimitry Andric 
70*0b57cec5SDimitry Andric MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
71*0b57cec5SDimitry Andric     const MachineOperand &MO) const {
72*0b57cec5SDimitry Andric   const char *Name = MO.getSymbolName();
73*0b57cec5SDimitry Andric   auto *WasmSym = cast<MCSymbolWasm>(Printer.GetExternalSymbolSymbol(Name));
74*0b57cec5SDimitry Andric   const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
75*0b57cec5SDimitry Andric 
76*0b57cec5SDimitry Andric   // Except for certain known symbols, all symbols used by CodeGen are
77*0b57cec5SDimitry Andric   // functions. It's OK to hardcode knowledge of specific symbols here; this
78*0b57cec5SDimitry Andric   // method is precisely there for fetching the signatures of known
79*0b57cec5SDimitry Andric   // Clang-provided symbols.
80*0b57cec5SDimitry Andric   if (strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0 ||
81*0b57cec5SDimitry Andric       strcmp(Name, "__memory_base") == 0 || strcmp(Name, "__table_base") == 0 ||
82*0b57cec5SDimitry Andric       strcmp(Name, "__tls_size") == 0) {
83*0b57cec5SDimitry Andric     bool Mutable =
84*0b57cec5SDimitry Andric         strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0;
85*0b57cec5SDimitry Andric     WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
86*0b57cec5SDimitry Andric     WasmSym->setGlobalType(wasm::WasmGlobalType{
87*0b57cec5SDimitry Andric         uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64
88*0b57cec5SDimitry Andric                                       : wasm::WASM_TYPE_I32),
89*0b57cec5SDimitry Andric         Mutable});
90*0b57cec5SDimitry Andric     return WasmSym;
91*0b57cec5SDimitry Andric   }
92*0b57cec5SDimitry Andric 
93*0b57cec5SDimitry Andric   SmallVector<wasm::ValType, 4> Returns;
94*0b57cec5SDimitry Andric   SmallVector<wasm::ValType, 4> Params;
95*0b57cec5SDimitry Andric   if (strcmp(Name, "__cpp_exception") == 0) {
96*0b57cec5SDimitry Andric     WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT);
97*0b57cec5SDimitry Andric     // We can't confirm its signature index for now because there can be
98*0b57cec5SDimitry Andric     // imported exceptions. Set it to be 0 for now.
99*0b57cec5SDimitry Andric     WasmSym->setEventType(
100*0b57cec5SDimitry Andric         {wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0});
101*0b57cec5SDimitry Andric     // We may have multiple C++ compilation units to be linked together, each of
102*0b57cec5SDimitry Andric     // which defines the exception symbol. To resolve them, we declare them as
103*0b57cec5SDimitry Andric     // weak.
104*0b57cec5SDimitry Andric     WasmSym->setWeak(true);
105*0b57cec5SDimitry Andric     WasmSym->setExternal(true);
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric     // All C++ exceptions are assumed to have a single i32 (for wasm32) or i64
108*0b57cec5SDimitry Andric     // (for wasm64) param type and void return type. The reaon is, all C++
109*0b57cec5SDimitry Andric     // exception values are pointers, and to share the type section with
110*0b57cec5SDimitry Andric     // functions, exceptions are assumed to have void return type.
111*0b57cec5SDimitry Andric     Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64
112*0b57cec5SDimitry Andric                                            : wasm::ValType::I32);
113*0b57cec5SDimitry Andric   } else { // Function symbols
114*0b57cec5SDimitry Andric     WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
115*0b57cec5SDimitry Andric     getLibcallSignature(Subtarget, Name, Returns, Params);
116*0b57cec5SDimitry Andric   }
117*0b57cec5SDimitry Andric   auto Signature =
118*0b57cec5SDimitry Andric       make_unique<wasm::WasmSignature>(std::move(Returns), std::move(Params));
119*0b57cec5SDimitry Andric   WasmSym->setSignature(Signature.get());
120*0b57cec5SDimitry Andric   Printer.addSignature(std::move(Signature));
121*0b57cec5SDimitry Andric 
122*0b57cec5SDimitry Andric   return WasmSym;
123*0b57cec5SDimitry Andric }
124*0b57cec5SDimitry Andric 
125*0b57cec5SDimitry Andric MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
126*0b57cec5SDimitry Andric                                                      MCSymbol *Sym) const {
127*0b57cec5SDimitry Andric   MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None;
128*0b57cec5SDimitry Andric   unsigned TargetFlags = MO.getTargetFlags();
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric   switch (TargetFlags) {
131*0b57cec5SDimitry Andric     case WebAssemblyII::MO_NO_FLAG:
132*0b57cec5SDimitry Andric       break;
133*0b57cec5SDimitry Andric     case WebAssemblyII::MO_GOT:
134*0b57cec5SDimitry Andric       Kind = MCSymbolRefExpr::VK_GOT;
135*0b57cec5SDimitry Andric       break;
136*0b57cec5SDimitry Andric     case WebAssemblyII::MO_MEMORY_BASE_REL:
137*0b57cec5SDimitry Andric       Kind = MCSymbolRefExpr::VK_WASM_MBREL;
138*0b57cec5SDimitry Andric       break;
139*0b57cec5SDimitry Andric     case WebAssemblyII::MO_TABLE_BASE_REL:
140*0b57cec5SDimitry Andric       Kind = MCSymbolRefExpr::VK_WASM_TBREL;
141*0b57cec5SDimitry Andric       break;
142*0b57cec5SDimitry Andric     default:
143*0b57cec5SDimitry Andric       llvm_unreachable("Unknown target flag on GV operand");
144*0b57cec5SDimitry Andric   }
145*0b57cec5SDimitry Andric 
146*0b57cec5SDimitry Andric   const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx);
147*0b57cec5SDimitry Andric 
148*0b57cec5SDimitry Andric   if (MO.getOffset() != 0) {
149*0b57cec5SDimitry Andric     const auto *WasmSym = cast<MCSymbolWasm>(Sym);
150*0b57cec5SDimitry Andric     if (TargetFlags == WebAssemblyII::MO_GOT)
151*0b57cec5SDimitry Andric       report_fatal_error("GOT symbol references do not support offsets");
152*0b57cec5SDimitry Andric     if (WasmSym->isFunction())
153*0b57cec5SDimitry Andric       report_fatal_error("Function addresses with offsets not supported");
154*0b57cec5SDimitry Andric     if (WasmSym->isGlobal())
155*0b57cec5SDimitry Andric       report_fatal_error("Global indexes with offsets not supported");
156*0b57cec5SDimitry Andric     if (WasmSym->isEvent())
157*0b57cec5SDimitry Andric       report_fatal_error("Event indexes with offsets not supported");
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric     Expr = MCBinaryExpr::createAdd(
160*0b57cec5SDimitry Andric         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
161*0b57cec5SDimitry Andric   }
162*0b57cec5SDimitry Andric 
163*0b57cec5SDimitry Andric   return MCOperand::createExpr(Expr);
164*0b57cec5SDimitry Andric }
165*0b57cec5SDimitry Andric 
166*0b57cec5SDimitry Andric // Return the WebAssembly type associated with the given register class.
167*0b57cec5SDimitry Andric static wasm::ValType getType(const TargetRegisterClass *RC) {
168*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
169*0b57cec5SDimitry Andric     return wasm::ValType::I32;
170*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
171*0b57cec5SDimitry Andric     return wasm::ValType::I64;
172*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
173*0b57cec5SDimitry Andric     return wasm::ValType::F32;
174*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
175*0b57cec5SDimitry Andric     return wasm::ValType::F64;
176*0b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
177*0b57cec5SDimitry Andric     return wasm::ValType::V128;
178*0b57cec5SDimitry Andric   llvm_unreachable("Unexpected register class");
179*0b57cec5SDimitry Andric }
180*0b57cec5SDimitry Andric 
181*0b57cec5SDimitry Andric void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
182*0b57cec5SDimitry Andric                                    MCInst &OutMI) const {
183*0b57cec5SDimitry Andric   OutMI.setOpcode(MI->getOpcode());
184*0b57cec5SDimitry Andric 
185*0b57cec5SDimitry Andric   const MCInstrDesc &Desc = MI->getDesc();
186*0b57cec5SDimitry Andric   for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
187*0b57cec5SDimitry Andric     const MachineOperand &MO = MI->getOperand(I);
188*0b57cec5SDimitry Andric 
189*0b57cec5SDimitry Andric     MCOperand MCOp;
190*0b57cec5SDimitry Andric     switch (MO.getType()) {
191*0b57cec5SDimitry Andric     default:
192*0b57cec5SDimitry Andric       MI->print(errs());
193*0b57cec5SDimitry Andric       llvm_unreachable("unknown operand type");
194*0b57cec5SDimitry Andric     case MachineOperand::MO_MachineBasicBlock:
195*0b57cec5SDimitry Andric       MI->print(errs());
196*0b57cec5SDimitry Andric       llvm_unreachable("MachineBasicBlock operand should have been rewritten");
197*0b57cec5SDimitry Andric     case MachineOperand::MO_Register: {
198*0b57cec5SDimitry Andric       // Ignore all implicit register operands.
199*0b57cec5SDimitry Andric       if (MO.isImplicit())
200*0b57cec5SDimitry Andric         continue;
201*0b57cec5SDimitry Andric       const WebAssemblyFunctionInfo &MFI =
202*0b57cec5SDimitry Andric           *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
203*0b57cec5SDimitry Andric       unsigned WAReg = MFI.getWAReg(MO.getReg());
204*0b57cec5SDimitry Andric       MCOp = MCOperand::createReg(WAReg);
205*0b57cec5SDimitry Andric       break;
206*0b57cec5SDimitry Andric     }
207*0b57cec5SDimitry Andric     case MachineOperand::MO_Immediate:
208*0b57cec5SDimitry Andric       if (I < Desc.NumOperands) {
209*0b57cec5SDimitry Andric         const MCOperandInfo &Info = Desc.OpInfo[I];
210*0b57cec5SDimitry Andric         if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
211*0b57cec5SDimitry Andric           MCSymbol *Sym = Printer.createTempSymbol("typeindex");
212*0b57cec5SDimitry Andric 
213*0b57cec5SDimitry Andric           SmallVector<wasm::ValType, 4> Returns;
214*0b57cec5SDimitry Andric           SmallVector<wasm::ValType, 4> Params;
215*0b57cec5SDimitry Andric 
216*0b57cec5SDimitry Andric           const MachineRegisterInfo &MRI =
217*0b57cec5SDimitry Andric               MI->getParent()->getParent()->getRegInfo();
218*0b57cec5SDimitry Andric           for (const MachineOperand &MO : MI->defs())
219*0b57cec5SDimitry Andric             Returns.push_back(getType(MRI.getRegClass(MO.getReg())));
220*0b57cec5SDimitry Andric           for (const MachineOperand &MO : MI->explicit_uses())
221*0b57cec5SDimitry Andric             if (MO.isReg())
222*0b57cec5SDimitry Andric               Params.push_back(getType(MRI.getRegClass(MO.getReg())));
223*0b57cec5SDimitry Andric 
224*0b57cec5SDimitry Andric           // call_indirect instructions have a callee operand at the end which
225*0b57cec5SDimitry Andric           // doesn't count as a param.
226*0b57cec5SDimitry Andric           if (WebAssembly::isCallIndirect(MI->getOpcode()))
227*0b57cec5SDimitry Andric             Params.pop_back();
228*0b57cec5SDimitry Andric 
229*0b57cec5SDimitry Andric           auto *WasmSym = cast<MCSymbolWasm>(Sym);
230*0b57cec5SDimitry Andric           auto Signature = make_unique<wasm::WasmSignature>(std::move(Returns),
231*0b57cec5SDimitry Andric                                                             std::move(Params));
232*0b57cec5SDimitry Andric           WasmSym->setSignature(Signature.get());
233*0b57cec5SDimitry Andric           Printer.addSignature(std::move(Signature));
234*0b57cec5SDimitry Andric           WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric           const MCExpr *Expr = MCSymbolRefExpr::create(
237*0b57cec5SDimitry Andric               WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
238*0b57cec5SDimitry Andric           MCOp = MCOperand::createExpr(Expr);
239*0b57cec5SDimitry Andric           break;
240*0b57cec5SDimitry Andric         }
241*0b57cec5SDimitry Andric       }
242*0b57cec5SDimitry Andric       MCOp = MCOperand::createImm(MO.getImm());
243*0b57cec5SDimitry Andric       break;
244*0b57cec5SDimitry Andric     case MachineOperand::MO_FPImmediate: {
245*0b57cec5SDimitry Andric       // TODO: MC converts all floating point immediate operands to double.
246*0b57cec5SDimitry Andric       // This is fine for numeric values, but may cause NaNs to change bits.
247*0b57cec5SDimitry Andric       const ConstantFP *Imm = MO.getFPImm();
248*0b57cec5SDimitry Andric       if (Imm->getType()->isFloatTy())
249*0b57cec5SDimitry Andric         MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToFloat());
250*0b57cec5SDimitry Andric       else if (Imm->getType()->isDoubleTy())
251*0b57cec5SDimitry Andric         MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToDouble());
252*0b57cec5SDimitry Andric       else
253*0b57cec5SDimitry Andric         llvm_unreachable("unknown floating point immediate type");
254*0b57cec5SDimitry Andric       break;
255*0b57cec5SDimitry Andric     }
256*0b57cec5SDimitry Andric     case MachineOperand::MO_GlobalAddress:
257*0b57cec5SDimitry Andric       MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
258*0b57cec5SDimitry Andric       break;
259*0b57cec5SDimitry Andric     case MachineOperand::MO_ExternalSymbol:
260*0b57cec5SDimitry Andric       // The target flag indicates whether this is a symbol for a
261*0b57cec5SDimitry Andric       // variable or a function.
262*0b57cec5SDimitry Andric       assert(MO.getTargetFlags() == 0 &&
263*0b57cec5SDimitry Andric              "WebAssembly uses only symbol flags on ExternalSymbols");
264*0b57cec5SDimitry Andric       MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
265*0b57cec5SDimitry Andric       break;
266*0b57cec5SDimitry Andric     case MachineOperand::MO_MCSymbol:
267*0b57cec5SDimitry Andric       // This is currently used only for LSDA symbols (GCC_except_table),
268*0b57cec5SDimitry Andric       // because global addresses or other external symbols are handled above.
269*0b57cec5SDimitry Andric       assert(MO.getTargetFlags() == 0 &&
270*0b57cec5SDimitry Andric              "WebAssembly does not use target flags on MCSymbol");
271*0b57cec5SDimitry Andric       MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
272*0b57cec5SDimitry Andric       break;
273*0b57cec5SDimitry Andric     }
274*0b57cec5SDimitry Andric 
275*0b57cec5SDimitry Andric     OutMI.addOperand(MCOp);
276*0b57cec5SDimitry Andric   }
277*0b57cec5SDimitry Andric 
278*0b57cec5SDimitry Andric   if (!WasmKeepRegisters)
279*0b57cec5SDimitry Andric     removeRegisterOperands(MI, OutMI);
280*0b57cec5SDimitry Andric }
281*0b57cec5SDimitry Andric 
282*0b57cec5SDimitry Andric static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
283*0b57cec5SDimitry Andric   // Remove all uses of stackified registers to bring the instruction format
284*0b57cec5SDimitry Andric   // into its final stack form used thruout MC, and transition opcodes to
285*0b57cec5SDimitry Andric   // their _S variant.
286*0b57cec5SDimitry Andric   // We do this seperate from the above code that still may need these
287*0b57cec5SDimitry Andric   // registers for e.g. call_indirect signatures.
288*0b57cec5SDimitry Andric   // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
289*0b57cec5SDimitry Andric   // details.
290*0b57cec5SDimitry Andric   // TODO: the code above creates new registers which are then removed here.
291*0b57cec5SDimitry Andric   // That code could be slightly simplified by not doing that, though maybe
292*0b57cec5SDimitry Andric   // it is simpler conceptually to keep the code above in "register mode"
293*0b57cec5SDimitry Andric   // until this transition point.
294*0b57cec5SDimitry Andric   // FIXME: we are not processing inline assembly, which contains register
295*0b57cec5SDimitry Andric   // operands, because it is used by later target generic code.
296*0b57cec5SDimitry Andric   if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
297*0b57cec5SDimitry Andric     return;
298*0b57cec5SDimitry Andric 
299*0b57cec5SDimitry Andric   // Transform to _S instruction.
300*0b57cec5SDimitry Andric   auto RegOpcode = OutMI.getOpcode();
301*0b57cec5SDimitry Andric   auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
302*0b57cec5SDimitry Andric   assert(StackOpcode != -1 && "Failed to stackify instruction");
303*0b57cec5SDimitry Andric   OutMI.setOpcode(StackOpcode);
304*0b57cec5SDimitry Andric 
305*0b57cec5SDimitry Andric   // Remove register operands.
306*0b57cec5SDimitry Andric   for (auto I = OutMI.getNumOperands(); I; --I) {
307*0b57cec5SDimitry Andric     auto &MO = OutMI.getOperand(I - 1);
308*0b57cec5SDimitry Andric     if (MO.isReg()) {
309*0b57cec5SDimitry Andric       OutMI.erase(&MO);
310*0b57cec5SDimitry Andric     }
311*0b57cec5SDimitry Andric   }
312*0b57cec5SDimitry Andric }
313