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