17d523365SDimitry Andric // WebAssemblyMCInstLower.cpp - Convert WebAssembly MachineInstr to an MCInst //
27d523365SDimitry Andric //
37d523365SDimitry Andric // The LLVM Compiler Infrastructure
47d523365SDimitry Andric //
57d523365SDimitry Andric // This file is distributed under the University of Illinois Open Source
67d523365SDimitry Andric // License. See LICENSE.TXT for details.
77d523365SDimitry Andric //
87d523365SDimitry Andric //===----------------------------------------------------------------------===//
97d523365SDimitry Andric ///
107d523365SDimitry Andric /// \file
114ba319b5SDimitry Andric /// This file contains code to lower WebAssembly MachineInstrs to their
127d523365SDimitry Andric /// corresponding MCInst records.
137d523365SDimitry Andric ///
147d523365SDimitry Andric //===----------------------------------------------------------------------===//
157d523365SDimitry Andric
167d523365SDimitry Andric #include "WebAssemblyMCInstLower.h"
177a7e6055SDimitry Andric #include "WebAssemblyAsmPrinter.h"
187d523365SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
197a7e6055SDimitry Andric #include "WebAssemblyRuntimeLibcallSignatures.h"
207a7e6055SDimitry Andric #include "WebAssemblyUtilities.h"
217d523365SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
227d523365SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
237d523365SDimitry Andric #include "llvm/IR/Constants.h"
247d523365SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
257d523365SDimitry Andric #include "llvm/MC/MCContext.h"
267d523365SDimitry Andric #include "llvm/MC/MCExpr.h"
277d523365SDimitry Andric #include "llvm/MC/MCInst.h"
287a7e6055SDimitry Andric #include "llvm/MC/MCSymbolWasm.h"
297d523365SDimitry Andric #include "llvm/Support/ErrorHandling.h"
307d523365SDimitry Andric #include "llvm/Support/raw_ostream.h"
317d523365SDimitry Andric using namespace llvm;
327d523365SDimitry Andric
33*b5893f02SDimitry Andric // Defines llvm::WebAssembly::getStackOpcode to convert register instructions to
34*b5893f02SDimitry Andric // stack instructions
35*b5893f02SDimitry Andric #define GET_INSTRMAP_INFO 1
36*b5893f02SDimitry Andric #include "WebAssemblyGenInstrInfo.inc"
37*b5893f02SDimitry Andric
38*b5893f02SDimitry Andric // This disables the removal of registers when lowering into MC, as required
39*b5893f02SDimitry Andric // by some current tests.
40*b5893f02SDimitry Andric static cl::opt<bool>
41*b5893f02SDimitry Andric WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
42*b5893f02SDimitry Andric cl::desc("WebAssembly: output stack registers in"
43*b5893f02SDimitry Andric " instruction output for test purposes only."),
44*b5893f02SDimitry Andric cl::init(false));
45*b5893f02SDimitry Andric
46*b5893f02SDimitry Andric static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
47*b5893f02SDimitry Andric
487d523365SDimitry Andric MCSymbol *
GetGlobalAddressSymbol(const MachineOperand & MO) const497d523365SDimitry Andric WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
507a7e6055SDimitry Andric const GlobalValue *Global = MO.getGlobal();
514ba319b5SDimitry Andric MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Printer.getSymbol(Global));
527a7e6055SDimitry Andric
537a7e6055SDimitry Andric if (const auto *FuncTy = dyn_cast<FunctionType>(Global->getValueType())) {
547a7e6055SDimitry Andric const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
557a7e6055SDimitry Andric const TargetMachine &TM = MF.getTarget();
562cab237bSDimitry Andric const Function &CurrentFunc = MF.getFunction();
577a7e6055SDimitry Andric
58*b5893f02SDimitry Andric SmallVector<MVT, 1> ResultMVTs;
597a7e6055SDimitry Andric SmallVector<MVT, 4> ParamMVTs;
60*b5893f02SDimitry Andric ComputeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs);
617a7e6055SDimitry Andric
62*b5893f02SDimitry Andric auto Signature = SignatureFromMVTs(ResultMVTs, ParamMVTs);
63*b5893f02SDimitry Andric WasmSym->setSignature(Signature.get());
64*b5893f02SDimitry Andric Printer.addSignature(std::move(Signature));
654ba319b5SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
667a7e6055SDimitry Andric }
677a7e6055SDimitry Andric
687a7e6055SDimitry Andric return WasmSym;
697d523365SDimitry Andric }
707d523365SDimitry Andric
GetExternalSymbolSymbol(const MachineOperand & MO) const717d523365SDimitry Andric MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
727d523365SDimitry Andric const MachineOperand &MO) const {
737a7e6055SDimitry Andric const char *Name = MO.getSymbolName();
744ba319b5SDimitry Andric MCSymbolWasm *WasmSym =
754ba319b5SDimitry Andric cast<MCSymbolWasm>(Printer.GetExternalSymbolSymbol(Name));
767a7e6055SDimitry Andric const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
777a7e6055SDimitry Andric
78*b5893f02SDimitry Andric // Except for the two exceptions (__stack_pointer and __cpp_exception), all
79*b5893f02SDimitry Andric // other external symbols used by CodeGen are functions. It's OK to hardcode
80*b5893f02SDimitry Andric // knowledge of specific symbols here; this method is precisely there for
81*b5893f02SDimitry Andric // fetching the signatures of known Clang-provided symbols.
824ba319b5SDimitry Andric if (strcmp(Name, "__stack_pointer") == 0) {
834ba319b5SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
844ba319b5SDimitry Andric WasmSym->setGlobalType(wasm::WasmGlobalType{
854ba319b5SDimitry Andric uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64
864ba319b5SDimitry Andric : wasm::WASM_TYPE_I32),
874ba319b5SDimitry Andric true});
887a7e6055SDimitry Andric return WasmSym;
894ba319b5SDimitry Andric }
907a7e6055SDimitry Andric
917a7e6055SDimitry Andric SmallVector<wasm::ValType, 4> Returns;
927a7e6055SDimitry Andric SmallVector<wasm::ValType, 4> Params;
93*b5893f02SDimitry Andric if (strcmp(Name, "__cpp_exception") == 0) {
94*b5893f02SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT);
95*b5893f02SDimitry Andric // We can't confirm its signature index for now because there can be
96*b5893f02SDimitry Andric // imported exceptions. Set it to be 0 for now.
97*b5893f02SDimitry Andric WasmSym->setEventType(
98*b5893f02SDimitry Andric {wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0});
99*b5893f02SDimitry Andric // We may have multiple C++ compilation units to be linked together, each of
100*b5893f02SDimitry Andric // which defines the exception symbol. To resolve them, we declare them as
101*b5893f02SDimitry Andric // weak.
102*b5893f02SDimitry Andric WasmSym->setWeak(true);
103*b5893f02SDimitry Andric WasmSym->setExternal(true);
1047a7e6055SDimitry Andric
105*b5893f02SDimitry Andric // All C++ exceptions are assumed to have a single i32 (for wasm32) or i64
106*b5893f02SDimitry Andric // (for wasm64) param type and void return type. The reaon is, all C++
107*b5893f02SDimitry Andric // exception values are pointers, and to share the type section with
108*b5893f02SDimitry Andric // functions, exceptions are assumed to have void return type.
109*b5893f02SDimitry Andric Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64
110*b5893f02SDimitry Andric : wasm::ValType::I32);
111*b5893f02SDimitry Andric } else { // Function symbols
1124ba319b5SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
113*b5893f02SDimitry Andric GetLibcallSignature(Subtarget, Name, Returns, Params);
114*b5893f02SDimitry Andric }
115*b5893f02SDimitry Andric auto Signature =
116*b5893f02SDimitry Andric make_unique<wasm::WasmSignature>(std::move(Returns), std::move(Params));
117*b5893f02SDimitry Andric WasmSym->setSignature(Signature.get());
118*b5893f02SDimitry Andric Printer.addSignature(std::move(Signature));
1197a7e6055SDimitry Andric
1207a7e6055SDimitry Andric return WasmSym;
1217d523365SDimitry Andric }
1227d523365SDimitry Andric
LowerSymbolOperand(MCSymbol * Sym,int64_t Offset,bool IsFunc,bool IsGlob,bool IsEvent) const123444ed5c5SDimitry Andric MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
124444ed5c5SDimitry Andric int64_t Offset,
125*b5893f02SDimitry Andric bool IsFunc, bool IsGlob,
126*b5893f02SDimitry Andric bool IsEvent) const {
127444ed5c5SDimitry Andric MCSymbolRefExpr::VariantKind VK =
128444ed5c5SDimitry Andric IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION
129*b5893f02SDimitry Andric : IsGlob ? MCSymbolRefExpr::VK_WebAssembly_GLOBAL
130*b5893f02SDimitry Andric : IsEvent ? MCSymbolRefExpr::VK_WebAssembly_EVENT
131444ed5c5SDimitry Andric : MCSymbolRefExpr::VK_None;
1327a7e6055SDimitry Andric
133444ed5c5SDimitry Andric const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx);
1347d523365SDimitry Andric
1357d523365SDimitry Andric if (Offset != 0) {
136444ed5c5SDimitry Andric if (IsFunc)
137444ed5c5SDimitry Andric report_fatal_error("Function addresses with offsets not supported");
138*b5893f02SDimitry Andric if (IsGlob)
139*b5893f02SDimitry Andric report_fatal_error("Global indexes with offsets not supported");
140*b5893f02SDimitry Andric if (IsEvent)
141*b5893f02SDimitry Andric report_fatal_error("Event indexes with offsets not supported");
1427d523365SDimitry Andric Expr =
1437d523365SDimitry Andric MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, Ctx), Ctx);
1447d523365SDimitry Andric }
1457d523365SDimitry Andric
1467d523365SDimitry Andric return MCOperand::createExpr(Expr);
1477d523365SDimitry Andric }
1487d523365SDimitry Andric
1497a7e6055SDimitry Andric // Return the WebAssembly type associated with the given register class.
getType(const TargetRegisterClass * RC)1507a7e6055SDimitry Andric static wasm::ValType getType(const TargetRegisterClass *RC) {
1517a7e6055SDimitry Andric if (RC == &WebAssembly::I32RegClass)
1527a7e6055SDimitry Andric return wasm::ValType::I32;
1537a7e6055SDimitry Andric if (RC == &WebAssembly::I64RegClass)
1547a7e6055SDimitry Andric return wasm::ValType::I64;
1557a7e6055SDimitry Andric if (RC == &WebAssembly::F32RegClass)
1567a7e6055SDimitry Andric return wasm::ValType::F32;
1577a7e6055SDimitry Andric if (RC == &WebAssembly::F64RegClass)
1587a7e6055SDimitry Andric return wasm::ValType::F64;
159*b5893f02SDimitry Andric if (RC == &WebAssembly::V128RegClass)
160*b5893f02SDimitry Andric return wasm::ValType::V128;
1617a7e6055SDimitry Andric llvm_unreachable("Unexpected register class");
1627a7e6055SDimitry Andric }
1637a7e6055SDimitry Andric
Lower(const MachineInstr * MI,MCInst & OutMI) const1647d523365SDimitry Andric void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
1657d523365SDimitry Andric MCInst &OutMI) const {
1667d523365SDimitry Andric OutMI.setOpcode(MI->getOpcode());
1677d523365SDimitry Andric
1687a7e6055SDimitry Andric const MCInstrDesc &Desc = MI->getDesc();
1697d523365SDimitry Andric for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
1707d523365SDimitry Andric const MachineOperand &MO = MI->getOperand(i);
1717d523365SDimitry Andric
1727d523365SDimitry Andric MCOperand MCOp;
1737d523365SDimitry Andric switch (MO.getType()) {
1747d523365SDimitry Andric default:
1757a7e6055SDimitry Andric MI->print(errs());
1767d523365SDimitry Andric llvm_unreachable("unknown operand type");
177444ed5c5SDimitry Andric case MachineOperand::MO_MachineBasicBlock:
1787a7e6055SDimitry Andric MI->print(errs());
179444ed5c5SDimitry Andric llvm_unreachable("MachineBasicBlock operand should have been rewritten");
1807d523365SDimitry Andric case MachineOperand::MO_Register: {
1817d523365SDimitry Andric // Ignore all implicit register operands.
1827d523365SDimitry Andric if (MO.isImplicit())
1837d523365SDimitry Andric continue;
1847d523365SDimitry Andric const WebAssemblyFunctionInfo &MFI =
1857d523365SDimitry Andric *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
1867d523365SDimitry Andric unsigned WAReg = MFI.getWAReg(MO.getReg());
1877d523365SDimitry Andric MCOp = MCOperand::createReg(WAReg);
1887d523365SDimitry Andric break;
1897d523365SDimitry Andric }
1907d523365SDimitry Andric case MachineOperand::MO_Immediate:
1917a7e6055SDimitry Andric if (i < Desc.NumOperands) {
1927a7e6055SDimitry Andric const MCOperandInfo &Info = Desc.OpInfo[i];
1937a7e6055SDimitry Andric if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
1947a7e6055SDimitry Andric MCSymbol *Sym = Printer.createTempSymbol("typeindex");
1954ba319b5SDimitry Andric
1967a7e6055SDimitry Andric SmallVector<wasm::ValType, 4> Returns;
1977a7e6055SDimitry Andric SmallVector<wasm::ValType, 4> Params;
1987a7e6055SDimitry Andric
1997a7e6055SDimitry Andric const MachineRegisterInfo &MRI =
2007a7e6055SDimitry Andric MI->getParent()->getParent()->getRegInfo();
2017a7e6055SDimitry Andric for (const MachineOperand &MO : MI->defs())
2027a7e6055SDimitry Andric Returns.push_back(getType(MRI.getRegClass(MO.getReg())));
2037a7e6055SDimitry Andric for (const MachineOperand &MO : MI->explicit_uses())
2047a7e6055SDimitry Andric if (MO.isReg())
2057a7e6055SDimitry Andric Params.push_back(getType(MRI.getRegClass(MO.getReg())));
2067a7e6055SDimitry Andric
2077a7e6055SDimitry Andric // call_indirect instructions have a callee operand at the end which
2087a7e6055SDimitry Andric // doesn't count as a param.
2097a7e6055SDimitry Andric if (WebAssembly::isCallIndirect(*MI))
2107a7e6055SDimitry Andric Params.pop_back();
2117a7e6055SDimitry Andric
2127a7e6055SDimitry Andric MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Sym);
213*b5893f02SDimitry Andric auto Signature = make_unique<wasm::WasmSignature>(std::move(Returns),
214*b5893f02SDimitry Andric std::move(Params));
215*b5893f02SDimitry Andric WasmSym->setSignature(Signature.get());
216*b5893f02SDimitry Andric Printer.addSignature(std::move(Signature));
2174ba319b5SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
2187a7e6055SDimitry Andric
2194ba319b5SDimitry Andric const MCExpr *Expr = MCSymbolRefExpr::create(
2204ba319b5SDimitry Andric WasmSym, MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX, Ctx);
2217a7e6055SDimitry Andric MCOp = MCOperand::createExpr(Expr);
2227a7e6055SDimitry Andric break;
2237a7e6055SDimitry Andric }
2247a7e6055SDimitry Andric }
2257d523365SDimitry Andric MCOp = MCOperand::createImm(MO.getImm());
2267d523365SDimitry Andric break;
2277d523365SDimitry Andric case MachineOperand::MO_FPImmediate: {
2287d523365SDimitry Andric // TODO: MC converts all floating point immediate operands to double.
2297d523365SDimitry Andric // This is fine for numeric values, but may cause NaNs to change bits.
2307d523365SDimitry Andric const ConstantFP *Imm = MO.getFPImm();
2317d523365SDimitry Andric if (Imm->getType()->isFloatTy())
2327d523365SDimitry Andric MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToFloat());
2337d523365SDimitry Andric else if (Imm->getType()->isDoubleTy())
2347d523365SDimitry Andric MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToDouble());
2357d523365SDimitry Andric else
2367d523365SDimitry Andric llvm_unreachable("unknown floating point immediate type");
2377d523365SDimitry Andric break;
2387d523365SDimitry Andric }
2397d523365SDimitry Andric case MachineOperand::MO_GlobalAddress:
240*b5893f02SDimitry Andric assert(MO.getTargetFlags() == WebAssemblyII::MO_NO_FLAG &&
241444ed5c5SDimitry Andric "WebAssembly does not use target flags on GlobalAddresses");
242444ed5c5SDimitry Andric MCOp = LowerSymbolOperand(GetGlobalAddressSymbol(MO), MO.getOffset(),
243*b5893f02SDimitry Andric MO.getGlobal()->getValueType()->isFunctionTy(),
244*b5893f02SDimitry Andric false, false);
2457d523365SDimitry Andric break;
2467d523365SDimitry Andric case MachineOperand::MO_ExternalSymbol:
247444ed5c5SDimitry Andric // The target flag indicates whether this is a symbol for a
248444ed5c5SDimitry Andric // variable or a function.
249*b5893f02SDimitry Andric assert((MO.getTargetFlags() & ~WebAssemblyII::MO_SYMBOL_MASK) == 0 &&
250*b5893f02SDimitry Andric "WebAssembly uses only symbol flags on ExternalSymbols");
251*b5893f02SDimitry Andric MCOp = LowerSymbolOperand(
252*b5893f02SDimitry Andric GetExternalSymbolSymbol(MO), /*Offset=*/0,
253*b5893f02SDimitry Andric (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_FUNCTION) != 0,
254*b5893f02SDimitry Andric (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_GLOBAL) != 0,
255*b5893f02SDimitry Andric (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_EVENT) != 0);
256*b5893f02SDimitry Andric break;
257*b5893f02SDimitry Andric case MachineOperand::MO_MCSymbol:
258*b5893f02SDimitry Andric // This is currently used only for LSDA symbols (GCC_except_table),
259*b5893f02SDimitry Andric // because global addresses or other external symbols are handled above.
260*b5893f02SDimitry Andric assert(MO.getTargetFlags() == 0 &&
261*b5893f02SDimitry Andric "WebAssembly does not use target flags on MCSymbol");
262*b5893f02SDimitry Andric MCOp = LowerSymbolOperand(MO.getMCSymbol(), /*Offset=*/0, false, false,
263*b5893f02SDimitry Andric false);
2647d523365SDimitry Andric break;
2657d523365SDimitry Andric }
2667d523365SDimitry Andric
2677d523365SDimitry Andric OutMI.addOperand(MCOp);
2687d523365SDimitry Andric }
269*b5893f02SDimitry Andric
270*b5893f02SDimitry Andric if (!WasmKeepRegisters)
271*b5893f02SDimitry Andric removeRegisterOperands(MI, OutMI);
272*b5893f02SDimitry Andric }
273*b5893f02SDimitry Andric
removeRegisterOperands(const MachineInstr * MI,MCInst & OutMI)274*b5893f02SDimitry Andric static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
275*b5893f02SDimitry Andric // Remove all uses of stackified registers to bring the instruction format
276*b5893f02SDimitry Andric // into its final stack form used thruout MC, and transition opcodes to
277*b5893f02SDimitry Andric // their _S variant.
278*b5893f02SDimitry Andric // We do this seperate from the above code that still may need these
279*b5893f02SDimitry Andric // registers for e.g. call_indirect signatures.
280*b5893f02SDimitry Andric // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
281*b5893f02SDimitry Andric // details.
282*b5893f02SDimitry Andric // TODO: the code above creates new registers which are then removed here.
283*b5893f02SDimitry Andric // That code could be slightly simplified by not doing that, though maybe
284*b5893f02SDimitry Andric // it is simpler conceptually to keep the code above in "register mode"
285*b5893f02SDimitry Andric // until this transition point.
286*b5893f02SDimitry Andric // FIXME: we are not processing inline assembly, which contains register
287*b5893f02SDimitry Andric // operands, because it is used by later target generic code.
288*b5893f02SDimitry Andric if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
289*b5893f02SDimitry Andric return;
290*b5893f02SDimitry Andric
291*b5893f02SDimitry Andric // Transform to _S instruction.
292*b5893f02SDimitry Andric auto RegOpcode = OutMI.getOpcode();
293*b5893f02SDimitry Andric auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
294*b5893f02SDimitry Andric assert(StackOpcode != -1 && "Failed to stackify instruction");
295*b5893f02SDimitry Andric OutMI.setOpcode(StackOpcode);
296*b5893f02SDimitry Andric
297*b5893f02SDimitry Andric // Remove register operands.
298*b5893f02SDimitry Andric for (auto I = OutMI.getNumOperands(); I; --I) {
299*b5893f02SDimitry Andric auto &MO = OutMI.getOperand(I - 1);
300*b5893f02SDimitry Andric if (MO.isReg()) {
301*b5893f02SDimitry Andric OutMI.erase(&MO);
302*b5893f02SDimitry Andric }
303*b5893f02SDimitry Andric }
3047d523365SDimitry Andric }
305