1dd58ef01SDimitry Andric // WebAssemblyMCInstLower.cpp - Convert WebAssembly MachineInstr to an MCInst //
2dd58ef01SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6dd58ef01SDimitry Andric //
7dd58ef01SDimitry Andric //===----------------------------------------------------------------------===//
8dd58ef01SDimitry Andric ///
9dd58ef01SDimitry Andric /// \file
10eb11fae6SDimitry Andric /// This file contains code to lower WebAssembly MachineInstrs to their
11dd58ef01SDimitry Andric /// corresponding MCInst records.
12dd58ef01SDimitry Andric ///
13dd58ef01SDimitry Andric //===----------------------------------------------------------------------===//
14dd58ef01SDimitry Andric
15dd58ef01SDimitry Andric #include "WebAssemblyMCInstLower.h"
16cfca06d7SDimitry Andric #include "TargetInfo/WebAssemblyTargetInfo.h"
17344a3780SDimitry Andric #include "Utils/WebAssemblyTypeUtilities.h"
1871d5a254SDimitry Andric #include "WebAssemblyAsmPrinter.h"
19c0981da4SDimitry Andric #include "WebAssemblyISelLowering.h"
20dd58ef01SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
21b1c73532SDimitry Andric #include "WebAssemblyUtilities.h"
22dd58ef01SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
23dd58ef01SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
24dd58ef01SDimitry Andric #include "llvm/IR/Constants.h"
25dd58ef01SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
26dd58ef01SDimitry Andric #include "llvm/MC/MCContext.h"
27dd58ef01SDimitry Andric #include "llvm/MC/MCExpr.h"
28dd58ef01SDimitry Andric #include "llvm/MC/MCInst.h"
2971d5a254SDimitry Andric #include "llvm/MC/MCSymbolWasm.h"
30dd58ef01SDimitry Andric #include "llvm/Support/ErrorHandling.h"
31dd58ef01SDimitry Andric #include "llvm/Support/raw_ostream.h"
32c0981da4SDimitry Andric
33dd58ef01SDimitry Andric using namespace llvm;
34dd58ef01SDimitry Andric
35d8e91e46SDimitry Andric // This disables the removal of registers when lowering into MC, as required
36d8e91e46SDimitry Andric // by some current tests.
37e6d15924SDimitry Andric cl::opt<bool>
38d8e91e46SDimitry Andric WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
39d8e91e46SDimitry Andric cl::desc("WebAssembly: output stack registers in"
40d8e91e46SDimitry Andric " instruction output for test purposes only."),
41d8e91e46SDimitry Andric cl::init(false));
42d8e91e46SDimitry Andric
43d8e91e46SDimitry Andric static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
44d8e91e46SDimitry Andric
45dd58ef01SDimitry Andric MCSymbol *
GetGlobalAddressSymbol(const MachineOperand & MO) const46dd58ef01SDimitry Andric WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
4771d5a254SDimitry Andric const GlobalValue *Global = MO.getGlobal();
48344a3780SDimitry Andric if (!isa<Function>(Global)) {
49344a3780SDimitry Andric auto *WasmSym = cast<MCSymbolWasm>(Printer.getSymbol(Global));
50344a3780SDimitry Andric // If the symbol doesn't have an explicit WasmSymbolType yet and the
51344a3780SDimitry Andric // GlobalValue is actually a WebAssembly global, then ensure the symbol is a
52344a3780SDimitry Andric // WASM_SYMBOL_TYPE_GLOBAL.
53344a3780SDimitry Andric if (WebAssembly::isWasmVarAddressSpace(Global->getAddressSpace()) &&
54344a3780SDimitry Andric !WasmSym->getType()) {
55344a3780SDimitry Andric const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
56344a3780SDimitry Andric const TargetMachine &TM = MF.getTarget();
57344a3780SDimitry Andric const Function &CurrentFunc = MF.getFunction();
58c0981da4SDimitry Andric Type *GlobalVT = Global->getValueType();
59344a3780SDimitry Andric SmallVector<MVT, 1> VTs;
60c0981da4SDimitry Andric computeLegalValueVTs(CurrentFunc, TM, GlobalVT, VTs);
61c0981da4SDimitry Andric
62ecbca9f5SDimitry Andric WebAssembly::wasmSymbolSetType(WasmSym, GlobalVT, VTs);
6377fc4c14SDimitry Andric }
64344a3780SDimitry Andric return WasmSym;
65344a3780SDimitry Andric }
6671d5a254SDimitry Andric
67b60736ecSDimitry Andric const auto *FuncTy = cast<FunctionType>(Global->getValueType());
6871d5a254SDimitry Andric const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
6971d5a254SDimitry Andric const TargetMachine &TM = MF.getTarget();
70044eb2f6SDimitry Andric const Function &CurrentFunc = MF.getFunction();
7171d5a254SDimitry Andric
72d8e91e46SDimitry Andric SmallVector<MVT, 1> ResultMVTs;
7371d5a254SDimitry Andric SmallVector<MVT, 4> ParamMVTs;
74cfca06d7SDimitry Andric const auto *const F = dyn_cast<Function>(Global);
75cfca06d7SDimitry Andric computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs);
76ac9a064cSDimitry Andric auto Signature = signatureFromMVTs(Ctx, ResultMVTs, ParamMVTs);
77b60736ecSDimitry Andric
78b60736ecSDimitry Andric bool InvokeDetected = false;
79b60736ecSDimitry Andric auto *WasmSym = Printer.getMCSymbolForFunction(
8077fc4c14SDimitry Andric F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj,
81ac9a064cSDimitry Andric Signature, InvokeDetected);
82ac9a064cSDimitry Andric WasmSym->setSignature(Signature);
83eb11fae6SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
8471d5a254SDimitry Andric return WasmSym;
85dd58ef01SDimitry Andric }
86dd58ef01SDimitry Andric
GetExternalSymbolSymbol(const MachineOperand & MO) const87dd58ef01SDimitry Andric MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
88dd58ef01SDimitry Andric const MachineOperand &MO) const {
89344a3780SDimitry Andric return Printer.getOrCreateWasmSymbol(MO.getSymbolName());
90dd58ef01SDimitry Andric }
91dd58ef01SDimitry Andric
lowerSymbolOperand(const MachineOperand & MO,MCSymbol * Sym) const92e6d15924SDimitry Andric MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
93e6d15924SDimitry Andric MCSymbol *Sym) const {
94e6d15924SDimitry Andric MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None;
95e6d15924SDimitry Andric unsigned TargetFlags = MO.getTargetFlags();
9671d5a254SDimitry Andric
97e6d15924SDimitry Andric switch (TargetFlags) {
98e6d15924SDimitry Andric case WebAssemblyII::MO_NO_FLAG:
99e6d15924SDimitry Andric break;
100c0981da4SDimitry Andric case WebAssemblyII::MO_GOT_TLS:
101c0981da4SDimitry Andric Kind = MCSymbolRefExpr::VK_WASM_GOT_TLS;
102c0981da4SDimitry Andric break;
103e6d15924SDimitry Andric case WebAssemblyII::MO_GOT:
104e6d15924SDimitry Andric Kind = MCSymbolRefExpr::VK_GOT;
105e6d15924SDimitry Andric break;
106e6d15924SDimitry Andric case WebAssemblyII::MO_MEMORY_BASE_REL:
107e6d15924SDimitry Andric Kind = MCSymbolRefExpr::VK_WASM_MBREL;
108e6d15924SDimitry Andric break;
109b60736ecSDimitry Andric case WebAssemblyII::MO_TLS_BASE_REL:
110b60736ecSDimitry Andric Kind = MCSymbolRefExpr::VK_WASM_TLSREL;
111b60736ecSDimitry Andric break;
112e6d15924SDimitry Andric case WebAssemblyII::MO_TABLE_BASE_REL:
113e6d15924SDimitry Andric Kind = MCSymbolRefExpr::VK_WASM_TBREL;
114e6d15924SDimitry Andric break;
115e6d15924SDimitry Andric default:
116e6d15924SDimitry Andric llvm_unreachable("Unknown target flag on GV operand");
117e6d15924SDimitry Andric }
118dd58ef01SDimitry Andric
119e6d15924SDimitry Andric const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx);
120e6d15924SDimitry Andric
121e6d15924SDimitry Andric if (MO.getOffset() != 0) {
122e6d15924SDimitry Andric const auto *WasmSym = cast<MCSymbolWasm>(Sym);
123e6d15924SDimitry Andric if (TargetFlags == WebAssemblyII::MO_GOT)
124e6d15924SDimitry Andric report_fatal_error("GOT symbol references do not support offsets");
125e6d15924SDimitry Andric if (WasmSym->isFunction())
126050e163aSDimitry Andric report_fatal_error("Function addresses with offsets not supported");
127e6d15924SDimitry Andric if (WasmSym->isGlobal())
128d8e91e46SDimitry Andric report_fatal_error("Global indexes with offsets not supported");
129344a3780SDimitry Andric if (WasmSym->isTag())
130344a3780SDimitry Andric report_fatal_error("Tag indexes with offsets not supported");
131344a3780SDimitry Andric if (WasmSym->isTable())
132344a3780SDimitry Andric report_fatal_error("Table indexes with offsets not supported");
133e6d15924SDimitry Andric
134e6d15924SDimitry Andric Expr = MCBinaryExpr::createAdd(
135e6d15924SDimitry Andric Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
136dd58ef01SDimitry Andric }
137dd58ef01SDimitry Andric
138dd58ef01SDimitry Andric return MCOperand::createExpr(Expr);
139dd58ef01SDimitry Andric }
140dd58ef01SDimitry Andric
lowerTypeIndexOperand(SmallVectorImpl<wasm::ValType> && Returns,SmallVectorImpl<wasm::ValType> && Params) const1411d5ae102SDimitry Andric MCOperand WebAssemblyMCInstLower::lowerTypeIndexOperand(
1427fa27ce4SDimitry Andric SmallVectorImpl<wasm::ValType> &&Returns,
1437fa27ce4SDimitry Andric SmallVectorImpl<wasm::ValType> &&Params) const {
144ac9a064cSDimitry Andric auto Signature = Ctx.createWasmSignature();
145ac9a064cSDimitry Andric Signature->Returns = std::move(Returns);
146ac9a064cSDimitry Andric Signature->Params = std::move(Params);
1471d5ae102SDimitry Andric MCSymbol *Sym = Printer.createTempSymbol("typeindex");
1481d5ae102SDimitry Andric auto *WasmSym = cast<MCSymbolWasm>(Sym);
149ac9a064cSDimitry Andric WasmSym->setSignature(Signature);
1501d5ae102SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
1511d5ae102SDimitry Andric const MCExpr *Expr =
1521d5ae102SDimitry Andric MCSymbolRefExpr::create(WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
1531d5ae102SDimitry Andric return MCOperand::createExpr(Expr);
1541d5ae102SDimitry Andric }
1551d5ae102SDimitry Andric
getFunctionReturns(const MachineInstr * MI,SmallVectorImpl<wasm::ValType> & Returns)1561d5ae102SDimitry Andric static void getFunctionReturns(const MachineInstr *MI,
1571d5ae102SDimitry Andric SmallVectorImpl<wasm::ValType> &Returns) {
1581d5ae102SDimitry Andric const Function &F = MI->getMF()->getFunction();
1591d5ae102SDimitry Andric const TargetMachine &TM = MI->getMF()->getTarget();
1601d5ae102SDimitry Andric Type *RetTy = F.getReturnType();
1611d5ae102SDimitry Andric SmallVector<MVT, 4> CallerRetTys;
1621d5ae102SDimitry Andric computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
1631d5ae102SDimitry Andric valTypesFromMVTs(CallerRetTys, Returns);
1641d5ae102SDimitry Andric }
1651d5ae102SDimitry Andric
lower(const MachineInstr * MI,MCInst & OutMI) const166e6d15924SDimitry Andric void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
167dd58ef01SDimitry Andric MCInst &OutMI) const {
168dd58ef01SDimitry Andric OutMI.setOpcode(MI->getOpcode());
169dd58ef01SDimitry Andric
17071d5a254SDimitry Andric const MCInstrDesc &Desc = MI->getDesc();
171cfca06d7SDimitry Andric unsigned NumVariadicDefs = MI->getNumExplicitDefs() - Desc.getNumDefs();
172e6d15924SDimitry Andric for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
173e6d15924SDimitry Andric const MachineOperand &MO = MI->getOperand(I);
174dd58ef01SDimitry Andric
175dd58ef01SDimitry Andric MCOperand MCOp;
176dd58ef01SDimitry Andric switch (MO.getType()) {
177dd58ef01SDimitry Andric default:
17871d5a254SDimitry Andric MI->print(errs());
179dd58ef01SDimitry Andric llvm_unreachable("unknown operand type");
180050e163aSDimitry Andric case MachineOperand::MO_MachineBasicBlock:
18171d5a254SDimitry Andric MI->print(errs());
182050e163aSDimitry Andric llvm_unreachable("MachineBasicBlock operand should have been rewritten");
183dd58ef01SDimitry Andric case MachineOperand::MO_Register: {
184dd58ef01SDimitry Andric // Ignore all implicit register operands.
185dd58ef01SDimitry Andric if (MO.isImplicit())
186dd58ef01SDimitry Andric continue;
187dd58ef01SDimitry Andric const WebAssemblyFunctionInfo &MFI =
188dd58ef01SDimitry Andric *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
189dd58ef01SDimitry Andric unsigned WAReg = MFI.getWAReg(MO.getReg());
190dd58ef01SDimitry Andric MCOp = MCOperand::createReg(WAReg);
191dd58ef01SDimitry Andric break;
192dd58ef01SDimitry Andric }
193cfca06d7SDimitry Andric case MachineOperand::MO_Immediate: {
194cfca06d7SDimitry Andric unsigned DescIndex = I - NumVariadicDefs;
195cfca06d7SDimitry Andric if (DescIndex < Desc.NumOperands) {
196e3b55780SDimitry Andric const MCOperandInfo &Info = Desc.operands()[DescIndex];
19771d5a254SDimitry Andric if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
19871d5a254SDimitry Andric SmallVector<wasm::ValType, 4> Returns;
19971d5a254SDimitry Andric SmallVector<wasm::ValType, 4> Params;
20071d5a254SDimitry Andric
20171d5a254SDimitry Andric const MachineRegisterInfo &MRI =
20271d5a254SDimitry Andric MI->getParent()->getParent()->getRegInfo();
20371d5a254SDimitry Andric for (const MachineOperand &MO : MI->defs())
204b1c73532SDimitry Andric Returns.push_back(WebAssembly::regClassToValType(
205b1c73532SDimitry Andric MRI.getRegClass(MO.getReg())->getID()));
20671d5a254SDimitry Andric for (const MachineOperand &MO : MI->explicit_uses())
20771d5a254SDimitry Andric if (MO.isReg())
208b1c73532SDimitry Andric Params.push_back(WebAssembly::regClassToValType(
209b1c73532SDimitry Andric MRI.getRegClass(MO.getReg())->getID()));
21071d5a254SDimitry Andric
21171d5a254SDimitry Andric // call_indirect instructions have a callee operand at the end which
21271d5a254SDimitry Andric // doesn't count as a param.
213e6d15924SDimitry Andric if (WebAssembly::isCallIndirect(MI->getOpcode()))
21471d5a254SDimitry Andric Params.pop_back();
21571d5a254SDimitry Andric
2161d5ae102SDimitry Andric // return_call_indirect instructions have the return type of the
2171d5ae102SDimitry Andric // caller
2181d5ae102SDimitry Andric if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT)
2191d5ae102SDimitry Andric getFunctionReturns(MI, Returns);
22071d5a254SDimitry Andric
2211d5ae102SDimitry Andric MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));
22271d5a254SDimitry Andric break;
2231d5ae102SDimitry Andric } else if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
2241d5ae102SDimitry Andric auto BT = static_cast<WebAssembly::BlockType>(MO.getImm());
2251d5ae102SDimitry Andric assert(BT != WebAssembly::BlockType::Invalid);
2261d5ae102SDimitry Andric if (BT == WebAssembly::BlockType::Multivalue) {
2271d5ae102SDimitry Andric SmallVector<wasm::ValType, 1> Returns;
2281d5ae102SDimitry Andric getFunctionReturns(MI, Returns);
2291d5ae102SDimitry Andric MCOp = lowerTypeIndexOperand(std::move(Returns),
2301d5ae102SDimitry Andric SmallVector<wasm::ValType, 4>());
2311d5ae102SDimitry Andric break;
2321d5ae102SDimitry Andric }
23371d5a254SDimitry Andric }
23471d5a254SDimitry Andric }
235dd58ef01SDimitry Andric MCOp = MCOperand::createImm(MO.getImm());
236dd58ef01SDimitry Andric break;
237cfca06d7SDimitry Andric }
238dd58ef01SDimitry Andric case MachineOperand::MO_FPImmediate: {
239dd58ef01SDimitry Andric const ConstantFP *Imm = MO.getFPImm();
240344a3780SDimitry Andric const uint64_t BitPattern =
241344a3780SDimitry Andric Imm->getValueAPF().bitcastToAPInt().getZExtValue();
242dd58ef01SDimitry Andric if (Imm->getType()->isFloatTy())
243344a3780SDimitry Andric MCOp = MCOperand::createSFPImm(static_cast<uint32_t>(BitPattern));
244dd58ef01SDimitry Andric else if (Imm->getType()->isDoubleTy())
245344a3780SDimitry Andric MCOp = MCOperand::createDFPImm(BitPattern);
246dd58ef01SDimitry Andric else
247dd58ef01SDimitry Andric llvm_unreachable("unknown floating point immediate type");
248dd58ef01SDimitry Andric break;
249dd58ef01SDimitry Andric }
250dd58ef01SDimitry Andric case MachineOperand::MO_GlobalAddress:
251e6d15924SDimitry Andric MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
252dd58ef01SDimitry Andric break;
253dd58ef01SDimitry Andric case MachineOperand::MO_ExternalSymbol:
254e6d15924SDimitry Andric MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
255d8e91e46SDimitry Andric break;
256d8e91e46SDimitry Andric case MachineOperand::MO_MCSymbol:
257d8e91e46SDimitry Andric assert(MO.getTargetFlags() == 0 &&
258d8e91e46SDimitry Andric "WebAssembly does not use target flags on MCSymbol");
259e6d15924SDimitry Andric MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
260dd58ef01SDimitry Andric break;
261dd58ef01SDimitry Andric }
262dd58ef01SDimitry Andric
263dd58ef01SDimitry Andric OutMI.addOperand(MCOp);
264dd58ef01SDimitry Andric }
265d8e91e46SDimitry Andric
266d8e91e46SDimitry Andric if (!WasmKeepRegisters)
267d8e91e46SDimitry Andric removeRegisterOperands(MI, OutMI);
268cfca06d7SDimitry Andric else if (Desc.variadicOpsAreDefs())
269cfca06d7SDimitry Andric OutMI.insert(OutMI.begin(), MCOperand::createImm(MI->getNumExplicitDefs()));
270d8e91e46SDimitry Andric }
271d8e91e46SDimitry Andric
removeRegisterOperands(const MachineInstr * MI,MCInst & OutMI)272d8e91e46SDimitry Andric static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
273d8e91e46SDimitry Andric // Remove all uses of stackified registers to bring the instruction format
274d8e91e46SDimitry Andric // into its final stack form used thruout MC, and transition opcodes to
275d8e91e46SDimitry Andric // their _S variant.
276cfca06d7SDimitry Andric // We do this separate from the above code that still may need these
277d8e91e46SDimitry Andric // registers for e.g. call_indirect signatures.
278d8e91e46SDimitry Andric // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
279d8e91e46SDimitry Andric // details.
280d8e91e46SDimitry Andric // TODO: the code above creates new registers which are then removed here.
281d8e91e46SDimitry Andric // That code could be slightly simplified by not doing that, though maybe
282d8e91e46SDimitry Andric // it is simpler conceptually to keep the code above in "register mode"
283d8e91e46SDimitry Andric // until this transition point.
284d8e91e46SDimitry Andric // FIXME: we are not processing inline assembly, which contains register
285d8e91e46SDimitry Andric // operands, because it is used by later target generic code.
286d8e91e46SDimitry Andric if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
287d8e91e46SDimitry Andric return;
288d8e91e46SDimitry Andric
289d8e91e46SDimitry Andric // Transform to _S instruction.
290d8e91e46SDimitry Andric auto RegOpcode = OutMI.getOpcode();
291d8e91e46SDimitry Andric auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
292d8e91e46SDimitry Andric assert(StackOpcode != -1 && "Failed to stackify instruction");
293d8e91e46SDimitry Andric OutMI.setOpcode(StackOpcode);
294d8e91e46SDimitry Andric
295d8e91e46SDimitry Andric // Remove register operands.
296d8e91e46SDimitry Andric for (auto I = OutMI.getNumOperands(); I; --I) {
297d8e91e46SDimitry Andric auto &MO = OutMI.getOperand(I - 1);
298d8e91e46SDimitry Andric if (MO.isReg()) {
299d8e91e46SDimitry Andric OutMI.erase(&MO);
300d8e91e46SDimitry Andric }
301d8e91e46SDimitry Andric }
302dd58ef01SDimitry Andric }
303