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