1e9361d58SDan Gohman // WebAssemblyMCInstLower.cpp - Convert WebAssembly MachineInstr to an MCInst //
2e9361d58SDan Gohman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e9361d58SDan Gohman //
7e9361d58SDan Gohman //===----------------------------------------------------------------------===//
8e9361d58SDan Gohman ///
9e9361d58SDan Gohman /// \file
105f8f34e4SAdrian Prantl /// This file contains code to lower WebAssembly MachineInstrs to their
11e9361d58SDan Gohman /// corresponding MCInst records.
12e9361d58SDan Gohman ///
13e9361d58SDan Gohman //===----------------------------------------------------------------------===//
14e9361d58SDan Gohman
15e9361d58SDan Gohman #include "WebAssemblyMCInstLower.h"
163b29376eSWouter van Oortmerssen #include "TargetInfo/WebAssemblyTargetInfo.h"
170b2bc69bSHeejin Ahn #include "Utils/WebAssemblyTypeUtilities.h"
18b2f21b14SAndy Wingo #include "Utils/WebAssemblyUtilities.h"
19d934cb88SDan Gohman #include "WebAssemblyAsmPrinter.h"
206d0c7bc1SPaulo Matos #include "WebAssemblyISelLowering.h"
21cf4748f1SDan Gohman #include "WebAssemblyMachineFunctionInfo.h"
22e9361d58SDan Gohman #include "llvm/CodeGen/AsmPrinter.h"
23cf4748f1SDan Gohman #include "llvm/CodeGen/MachineFunction.h"
24cf4748f1SDan Gohman #include "llvm/IR/Constants.h"
25e9361d58SDan Gohman #include "llvm/MC/MCAsmInfo.h"
26e9361d58SDan Gohman #include "llvm/MC/MCContext.h"
27e9361d58SDan Gohman #include "llvm/MC/MCExpr.h"
28e9361d58SDan Gohman #include "llvm/MC/MCInst.h"
29d934cb88SDan Gohman #include "llvm/MC/MCSymbolWasm.h"
30e9361d58SDan Gohman #include "llvm/Support/ErrorHandling.h"
31e9361d58SDan Gohman #include "llvm/Support/raw_ostream.h"
326d0c7bc1SPaulo Matos
33e9361d58SDan Gohman using namespace llvm;
34e9361d58SDan Gohman
358a9cb242SWouter van Oortmerssen // This disables the removal of registers when lowering into MC, as required
368a9cb242SWouter van Oortmerssen // by some current tests.
37d6f48786SHeejin Ahn cl::opt<bool>
38f208f631SHeejin Ahn WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
398a9cb242SWouter van Oortmerssen cl::desc("WebAssembly: output stack registers in"
408a9cb242SWouter van Oortmerssen " instruction output for test purposes only."),
418a9cb242SWouter van Oortmerssen cl::init(false));
428a9cb242SWouter van Oortmerssen
438a9cb242SWouter van Oortmerssen static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
448a9cb242SWouter van Oortmerssen
45e9361d58SDan Gohman MCSymbol *
GetGlobalAddressSymbol(const MachineOperand & MO) const46e9361d58SDan Gohman WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
47d934cb88SDan Gohman const GlobalValue *Global = MO.getGlobal();
48b2f21b14SAndy Wingo if (!isa<Function>(Global)) {
49b2f21b14SAndy Wingo auto *WasmSym = cast<MCSymbolWasm>(Printer.getSymbol(Global));
50b2f21b14SAndy Wingo // If the symbol doesn't have an explicit WasmSymbolType yet and the
51b2f21b14SAndy Wingo // GlobalValue is actually a WebAssembly global, then ensure the symbol is a
52b2f21b14SAndy Wingo // WASM_SYMBOL_TYPE_GLOBAL.
53b2f21b14SAndy Wingo if (WebAssembly::isWasmVarAddressSpace(Global->getAddressSpace()) &&
54b2f21b14SAndy Wingo !WasmSym->getType()) {
55b2f21b14SAndy Wingo const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
56b2f21b14SAndy Wingo const TargetMachine &TM = MF.getTarget();
57b2f21b14SAndy Wingo const Function &CurrentFunc = MF.getFunction();
586d0c7bc1SPaulo Matos Type *GlobalVT = Global->getValueType();
59b2f21b14SAndy Wingo SmallVector<MVT, 1> VTs;
606d0c7bc1SPaulo Matos computeLegalValueVTs(CurrentFunc, TM, GlobalVT, VTs);
616d0c7bc1SPaulo Matos
62864767abSPaulo Matos WebAssembly::wasmSymbolSetType(WasmSym, GlobalVT, VTs);
63b5b5f0acSPaulo Matos }
64b2f21b14SAndy Wingo return WasmSym;
65b2f21b14SAndy Wingo }
66d934cb88SDan Gohman
673bba91f6SHeejin Ahn const auto *FuncTy = cast<FunctionType>(Global->getValueType());
68d934cb88SDan Gohman const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
69d934cb88SDan Gohman const TargetMachine &TM = MF.getTarget();
7021109249SDavid Blaikie const Function &CurrentFunc = MF.getFunction();
71d934cb88SDan Gohman
7277a7a380SDerek Schuff SmallVector<MVT, 1> ResultMVTs;
73d934cb88SDan Gohman SmallVector<MVT, 4> ParamMVTs;
7408670d43SYuta Saito const auto *const F = dyn_cast<Function>(Global);
7508670d43SYuta Saito computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs);
7618c56a07SHeejin Ahn auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs);
773bba91f6SHeejin Ahn
783bba91f6SHeejin Ahn bool InvokeDetected = false;
793bba91f6SHeejin Ahn auto *WasmSym = Printer.getMCSymbolForFunction(
804625b848SHeejin Ahn F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj,
814625b848SHeejin Ahn Signature.get(), InvokeDetected);
8277a7a380SDerek Schuff WasmSym->setSignature(Signature.get());
8377a7a380SDerek Schuff Printer.addSignature(std::move(Signature));
846c899ba6SSam Clegg WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
85d934cb88SDan Gohman return WasmSym;
86e9361d58SDan Gohman }
87e9361d58SDan Gohman
GetExternalSymbolSymbol(const MachineOperand & MO) const887a6b9825SDan Gohman MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
897a6b9825SDan Gohman const MachineOperand &MO) const {
909647a6f7SWouter van Oortmerssen return Printer.getOrCreateWasmSymbol(MO.getSymbolName());
912c8fe6a4SDan Gohman }
922c8fe6a4SDan Gohman
lowerSymbolOperand(const MachineOperand & MO,MCSymbol * Sym) const93ef4c66c1SSam Clegg MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
94ef4c66c1SSam Clegg MCSymbol *Sym) const {
952a7cac93SSam Clegg MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None;
962a7cac93SSam Clegg unsigned TargetFlags = MO.getTargetFlags();
972a7cac93SSam Clegg
982a7cac93SSam Clegg switch (TargetFlags) {
992a7cac93SSam Clegg case WebAssemblyII::MO_NO_FLAG:
1002a7cac93SSam Clegg break;
101ef8c9135SSam Clegg case WebAssemblyII::MO_GOT_TLS:
102ef8c9135SSam Clegg Kind = MCSymbolRefExpr::VK_WASM_GOT_TLS;
103ef8c9135SSam Clegg break;
1042a7cac93SSam Clegg case WebAssemblyII::MO_GOT:
1052a7cac93SSam Clegg Kind = MCSymbolRefExpr::VK_GOT;
1062a7cac93SSam Clegg break;
1072a7cac93SSam Clegg case WebAssemblyII::MO_MEMORY_BASE_REL:
1082a7cac93SSam Clegg Kind = MCSymbolRefExpr::VK_WASM_MBREL;
1092a7cac93SSam Clegg break;
110a28a4662SSam Clegg case WebAssemblyII::MO_TLS_BASE_REL:
111a28a4662SSam Clegg Kind = MCSymbolRefExpr::VK_WASM_TLSREL;
112a28a4662SSam Clegg break;
1132a7cac93SSam Clegg case WebAssemblyII::MO_TABLE_BASE_REL:
1142a7cac93SSam Clegg Kind = MCSymbolRefExpr::VK_WASM_TBREL;
1152a7cac93SSam Clegg break;
1162a7cac93SSam Clegg default:
1172a7cac93SSam Clegg llvm_unreachable("Unknown target flag on GV operand");
1182a7cac93SSam Clegg }
1192a7cac93SSam Clegg
120492f7529SSam Clegg const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx);
121e9361d58SDan Gohman
122ef4c66c1SSam Clegg if (MO.getOffset() != 0) {
123ef4c66c1SSam Clegg const auto *WasmSym = cast<MCSymbolWasm>(Sym);
1242a7cac93SSam Clegg if (TargetFlags == WebAssemblyII::MO_GOT)
125492f7529SSam Clegg report_fatal_error("GOT symbol references do not support offsets");
126ef4c66c1SSam Clegg if (WasmSym->isFunction())
12726c6765bSDan Gohman report_fatal_error("Function addresses with offsets not supported");
128ef4c66c1SSam Clegg if (WasmSym->isGlobal())
129e408a89aSNicholas Wilson report_fatal_error("Global indexes with offsets not supported");
1301d891d44SHeejin Ahn if (WasmSym->isTag())
1311d891d44SHeejin Ahn report_fatal_error("Tag indexes with offsets not supported");
1322632ba6aSAndy Wingo if (WasmSym->isTable())
1332632ba6aSAndy Wingo report_fatal_error("Table indexes with offsets not supported");
134ef4c66c1SSam Clegg
135ef4c66c1SSam Clegg Expr = MCBinaryExpr::createAdd(
136ef4c66c1SSam Clegg Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
137a4b710a7SDan Gohman }
138e9361d58SDan Gohman
139e9361d58SDan Gohman return MCOperand::createExpr(Expr);
140e9361d58SDan Gohman }
141e9361d58SDan Gohman
lowerTypeIndexOperand(SmallVector<wasm::ValType,1> && Returns,SmallVector<wasm::ValType,4> && Params) const1422cb27072SThomas Lively MCOperand WebAssemblyMCInstLower::lowerTypeIndexOperand(
1432cb27072SThomas Lively SmallVector<wasm::ValType, 1> &&Returns,
1442cb27072SThomas Lively SmallVector<wasm::ValType, 4> &&Params) const {
1452cb27072SThomas Lively auto Signature = std::make_unique<wasm::WasmSignature>(std::move(Returns),
1462cb27072SThomas Lively std::move(Params));
1472cb27072SThomas Lively MCSymbol *Sym = Printer.createTempSymbol("typeindex");
1482cb27072SThomas Lively auto *WasmSym = cast<MCSymbolWasm>(Sym);
1492cb27072SThomas Lively WasmSym->setSignature(Signature.get());
1502cb27072SThomas Lively Printer.addSignature(std::move(Signature));
1512cb27072SThomas Lively WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
1522cb27072SThomas Lively const MCExpr *Expr =
1532cb27072SThomas Lively MCSymbolRefExpr::create(WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
1542cb27072SThomas Lively return MCOperand::createExpr(Expr);
1552cb27072SThomas Lively }
1562cb27072SThomas Lively
getFunctionReturns(const MachineInstr * MI,SmallVectorImpl<wasm::ValType> & Returns)1572cb27072SThomas Lively static void getFunctionReturns(const MachineInstr *MI,
1582cb27072SThomas Lively SmallVectorImpl<wasm::ValType> &Returns) {
1592cb27072SThomas Lively const Function &F = MI->getMF()->getFunction();
1602cb27072SThomas Lively const TargetMachine &TM = MI->getMF()->getTarget();
1612cb27072SThomas Lively Type *RetTy = F.getReturnType();
1622cb27072SThomas Lively SmallVector<MVT, 4> CallerRetTys;
1632cb27072SThomas Lively computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
1642cb27072SThomas Lively valTypesFromMVTs(CallerRetTys, Returns);
1652cb27072SThomas Lively }
1662cb27072SThomas Lively
lower(const MachineInstr * MI,MCInst & OutMI) const16718c56a07SHeejin Ahn void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
168e9361d58SDan Gohman MCInst &OutMI) const {
169e9361d58SDan Gohman OutMI.setOpcode(MI->getOpcode());
170e9361d58SDan Gohman
171d934cb88SDan Gohman const MCInstrDesc &Desc = MI->getDesc();
1729d37f5afSThomas Lively unsigned NumVariadicDefs = MI->getNumExplicitDefs() - Desc.getNumDefs();
17318c56a07SHeejin Ahn for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
17418c56a07SHeejin Ahn const MachineOperand &MO = MI->getOperand(I);
175e9361d58SDan Gohman
176e9361d58SDan Gohman MCOperand MCOp;
177e9361d58SDan Gohman switch (MO.getType()) {
178e9361d58SDan Gohman default:
1793de487b2SRichard Trieu MI->print(errs());
180e9361d58SDan Gohman llvm_unreachable("unknown operand type");
1811d68e80fSDan Gohman case MachineOperand::MO_MachineBasicBlock:
1823de487b2SRichard Trieu MI->print(errs());
1831d68e80fSDan Gohman llvm_unreachable("MachineBasicBlock operand should have been rewritten");
184cf4748f1SDan Gohman case MachineOperand::MO_Register: {
185e9361d58SDan Gohman // Ignore all implicit register operands.
186e9361d58SDan Gohman if (MO.isImplicit())
187e9361d58SDan Gohman continue;
188cf4748f1SDan Gohman const WebAssemblyFunctionInfo &MFI =
189cf4748f1SDan Gohman *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
190cf4748f1SDan Gohman unsigned WAReg = MFI.getWAReg(MO.getReg());
191cf4748f1SDan Gohman MCOp = MCOperand::createReg(WAReg);
192e9361d58SDan Gohman break;
193cf4748f1SDan Gohman }
1949d37f5afSThomas Lively case MachineOperand::MO_Immediate: {
1959d37f5afSThomas Lively unsigned DescIndex = I - NumVariadicDefs;
1969d37f5afSThomas Lively if (DescIndex < Desc.NumOperands) {
1979d37f5afSThomas Lively const MCOperandInfo &Info = Desc.OpInfo[DescIndex];
198d934cb88SDan Gohman if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
199e2688c43SDerek Schuff SmallVector<wasm::ValType, 4> Returns;
200e2688c43SDerek Schuff SmallVector<wasm::ValType, 4> Params;
201d934cb88SDan Gohman
202d934cb88SDan Gohman const MachineRegisterInfo &MRI =
203d934cb88SDan Gohman MI->getParent()->getParent()->getRegInfo();
204d934cb88SDan Gohman for (const MachineOperand &MO : MI->defs())
205*0a9eb870SAlex Bradbury Returns.push_back(
206*0a9eb870SAlex Bradbury WebAssembly::regClassToValType(MRI.getRegClass(MO.getReg())));
207d934cb88SDan Gohman for (const MachineOperand &MO : MI->explicit_uses())
208d934cb88SDan Gohman if (MO.isReg())
209*0a9eb870SAlex Bradbury Params.push_back(
210*0a9eb870SAlex Bradbury WebAssembly::regClassToValType(MRI.getRegClass(MO.getReg())));
211d934cb88SDan Gohman
212d934cb88SDan Gohman // call_indirect instructions have a callee operand at the end which
213d934cb88SDan Gohman // doesn't count as a param.
214d8ddf839SWouter van Oortmerssen if (WebAssembly::isCallIndirect(MI->getOpcode()))
215d934cb88SDan Gohman Params.pop_back();
216d934cb88SDan Gohman
217e0a9dce5SThomas Lively // return_call_indirect instructions have the return type of the
218e0a9dce5SThomas Lively // caller
21996ef4f30SSam Clegg if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT)
2202cb27072SThomas Lively getFunctionReturns(MI, Returns);
221e0a9dce5SThomas Lively
2222cb27072SThomas Lively MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));
223d934cb88SDan Gohman break;
2242cb27072SThomas Lively } else if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
2252cb27072SThomas Lively auto BT = static_cast<WebAssembly::BlockType>(MO.getImm());
2262cb27072SThomas Lively assert(BT != WebAssembly::BlockType::Invalid);
2272cb27072SThomas Lively if (BT == WebAssembly::BlockType::Multivalue) {
2282cb27072SThomas Lively SmallVector<wasm::ValType, 1> Returns;
2292cb27072SThomas Lively getFunctionReturns(MI, Returns);
2302cb27072SThomas Lively MCOp = lowerTypeIndexOperand(std::move(Returns),
2312cb27072SThomas Lively SmallVector<wasm::ValType, 4>());
2322cb27072SThomas Lively break;
2332cb27072SThomas Lively }
234d934cb88SDan Gohman }
235d934cb88SDan Gohman }
236e9361d58SDan Gohman MCOp = MCOperand::createImm(MO.getImm());
237e9361d58SDan Gohman break;
2389d37f5afSThomas Lively }
239cf4748f1SDan Gohman case MachineOperand::MO_FPImmediate: {
240cf4748f1SDan Gohman const ConstantFP *Imm = MO.getFPImm();
241698c6b0aSDan Gohman const uint64_t BitPattern =
242698c6b0aSDan Gohman Imm->getValueAPF().bitcastToAPInt().getZExtValue();
243cf4748f1SDan Gohman if (Imm->getType()->isFloatTy())
244698c6b0aSDan Gohman MCOp = MCOperand::createSFPImm(static_cast<uint32_t>(BitPattern));
245cf4748f1SDan Gohman else if (Imm->getType()->isDoubleTy())
246698c6b0aSDan Gohman MCOp = MCOperand::createDFPImm(BitPattern);
247cf4748f1SDan Gohman else
248cf4748f1SDan Gohman llvm_unreachable("unknown floating point immediate type");
249e9361d58SDan Gohman break;
250cf4748f1SDan Gohman }
251e9361d58SDan Gohman case MachineOperand::MO_GlobalAddress:
252ef4c66c1SSam Clegg MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
253e9361d58SDan Gohman break;
2542c8fe6a4SDan Gohman case MachineOperand::MO_ExternalSymbol:
255ef4c66c1SSam Clegg MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
2562c8fe6a4SDan Gohman break;
25724faf859SHeejin Ahn case MachineOperand::MO_MCSymbol:
25824faf859SHeejin Ahn assert(MO.getTargetFlags() == 0 &&
25924faf859SHeejin Ahn "WebAssembly does not use target flags on MCSymbol");
260ef4c66c1SSam Clegg MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
26124faf859SHeejin Ahn break;
262e9361d58SDan Gohman }
263e9361d58SDan Gohman
264e9361d58SDan Gohman OutMI.addOperand(MCOp);
265e9361d58SDan Gohman }
2668a9cb242SWouter van Oortmerssen
2678a9cb242SWouter van Oortmerssen if (!WasmKeepRegisters)
2688a9cb242SWouter van Oortmerssen removeRegisterOperands(MI, OutMI);
269ca9ba764SThomas Lively else if (Desc.variadicOpsAreDefs())
270ca9ba764SThomas Lively OutMI.insert(OutMI.begin(), MCOperand::createImm(MI->getNumExplicitDefs()));
2718a9cb242SWouter van Oortmerssen }
2728a9cb242SWouter van Oortmerssen
removeRegisterOperands(const MachineInstr * MI,MCInst & OutMI)2738a9cb242SWouter van Oortmerssen static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
2748a9cb242SWouter van Oortmerssen // Remove all uses of stackified registers to bring the instruction format
2758a9cb242SWouter van Oortmerssen // into its final stack form used thruout MC, and transition opcodes to
2768a9cb242SWouter van Oortmerssen // their _S variant.
2779301e3aaSMarek Kurdej // We do this separate from the above code that still may need these
2788a9cb242SWouter van Oortmerssen // registers for e.g. call_indirect signatures.
2798a9cb242SWouter van Oortmerssen // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
2808a9cb242SWouter van Oortmerssen // details.
2818a9cb242SWouter van Oortmerssen // TODO: the code above creates new registers which are then removed here.
2828a9cb242SWouter van Oortmerssen // That code could be slightly simplified by not doing that, though maybe
2838a9cb242SWouter van Oortmerssen // it is simpler conceptually to keep the code above in "register mode"
2848a9cb242SWouter van Oortmerssen // until this transition point.
2858a9cb242SWouter van Oortmerssen // FIXME: we are not processing inline assembly, which contains register
2868a9cb242SWouter van Oortmerssen // operands, because it is used by later target generic code.
2878a9cb242SWouter van Oortmerssen if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
2888a9cb242SWouter van Oortmerssen return;
2898a9cb242SWouter van Oortmerssen
2908a9cb242SWouter van Oortmerssen // Transform to _S instruction.
2918a9cb242SWouter van Oortmerssen auto RegOpcode = OutMI.getOpcode();
292c63b5fcbSThomas Lively auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
293c63b5fcbSThomas Lively assert(StackOpcode != -1 && "Failed to stackify instruction");
2948a9cb242SWouter van Oortmerssen OutMI.setOpcode(StackOpcode);
2958a9cb242SWouter van Oortmerssen
2968a9cb242SWouter van Oortmerssen // Remove register operands.
2978a9cb242SWouter van Oortmerssen for (auto I = OutMI.getNumOperands(); I; --I) {
2988a9cb242SWouter van Oortmerssen auto &MO = OutMI.getOperand(I - 1);
2998a9cb242SWouter van Oortmerssen if (MO.isReg()) {
3008a9cb242SWouter van Oortmerssen OutMI.erase(&MO);
3018a9cb242SWouter van Oortmerssen }
3028a9cb242SWouter van Oortmerssen }
3038a9cb242SWouter van Oortmerssen }
304