WebAssemblyMCInstLower.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // WebAssemblyMCInstLower.cpp - Convert WebAssembly MachineInstr to an MCInst //
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. ///
  9. /// \file
  10. /// This file contains code to lower WebAssembly MachineInstrs to their
  11. /// corresponding MCInst records.
  12. ///
  13. //===----------------------------------------------------------------------===//
  14. #include "WebAssemblyMCInstLower.h"
  15. #include "TargetInfo/WebAssemblyTargetInfo.h"
  16. #include "Utils/WebAssemblyTypeUtilities.h"
  17. #include "Utils/WebAssemblyUtilities.h"
  18. #include "WebAssemblyAsmPrinter.h"
  19. #include "WebAssemblyISelLowering.h"
  20. #include "WebAssemblyMachineFunctionInfo.h"
  21. #include "llvm/CodeGen/AsmPrinter.h"
  22. #include "llvm/CodeGen/MachineFunction.h"
  23. #include "llvm/IR/Constants.h"
  24. #include "llvm/MC/MCAsmInfo.h"
  25. #include "llvm/MC/MCContext.h"
  26. #include "llvm/MC/MCExpr.h"
  27. #include "llvm/MC/MCInst.h"
  28. #include "llvm/MC/MCSymbolWasm.h"
  29. #include "llvm/Support/ErrorHandling.h"
  30. #include "llvm/Support/raw_ostream.h"
  31. using namespace llvm;
  32. // This disables the removal of registers when lowering into MC, as required
  33. // by some current tests.
  34. cl::opt<bool>
  35. WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
  36. cl::desc("WebAssembly: output stack registers in"
  37. " instruction output for test purposes only."),
  38. cl::init(false));
  39. static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
  40. MCSymbol *
  41. WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
  42. const GlobalValue *Global = MO.getGlobal();
  43. if (!isa<Function>(Global)) {
  44. auto *WasmSym = cast<MCSymbolWasm>(Printer.getSymbol(Global));
  45. // If the symbol doesn't have an explicit WasmSymbolType yet and the
  46. // GlobalValue is actually a WebAssembly global, then ensure the symbol is a
  47. // WASM_SYMBOL_TYPE_GLOBAL.
  48. if (WebAssembly::isWasmVarAddressSpace(Global->getAddressSpace()) &&
  49. !WasmSym->getType()) {
  50. const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
  51. const TargetMachine &TM = MF.getTarget();
  52. const Function &CurrentFunc = MF.getFunction();
  53. Type *GlobalVT = Global->getValueType();
  54. SmallVector<MVT, 1> VTs;
  55. computeLegalValueVTs(CurrentFunc, TM, GlobalVT, VTs);
  56. WebAssembly::wasmSymbolSetType(WasmSym, GlobalVT, VTs);
  57. }
  58. return WasmSym;
  59. }
  60. const auto *FuncTy = cast<FunctionType>(Global->getValueType());
  61. const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
  62. const TargetMachine &TM = MF.getTarget();
  63. const Function &CurrentFunc = MF.getFunction();
  64. SmallVector<MVT, 1> ResultMVTs;
  65. SmallVector<MVT, 4> ParamMVTs;
  66. const auto *const F = dyn_cast<Function>(Global);
  67. computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs);
  68. auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs);
  69. bool InvokeDetected = false;
  70. auto *WasmSym = Printer.getMCSymbolForFunction(
  71. F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj,
  72. Signature.get(), InvokeDetected);
  73. WasmSym->setSignature(Signature.get());
  74. Printer.addSignature(std::move(Signature));
  75. WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
  76. return WasmSym;
  77. }
  78. MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
  79. const MachineOperand &MO) const {
  80. return Printer.getOrCreateWasmSymbol(MO.getSymbolName());
  81. }
  82. MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
  83. MCSymbol *Sym) const {
  84. MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None;
  85. unsigned TargetFlags = MO.getTargetFlags();
  86. switch (TargetFlags) {
  87. case WebAssemblyII::MO_NO_FLAG:
  88. break;
  89. case WebAssemblyII::MO_GOT_TLS:
  90. Kind = MCSymbolRefExpr::VK_WASM_GOT_TLS;
  91. break;
  92. case WebAssemblyII::MO_GOT:
  93. Kind = MCSymbolRefExpr::VK_GOT;
  94. break;
  95. case WebAssemblyII::MO_MEMORY_BASE_REL:
  96. Kind = MCSymbolRefExpr::VK_WASM_MBREL;
  97. break;
  98. case WebAssemblyII::MO_TLS_BASE_REL:
  99. Kind = MCSymbolRefExpr::VK_WASM_TLSREL;
  100. break;
  101. case WebAssemblyII::MO_TABLE_BASE_REL:
  102. Kind = MCSymbolRefExpr::VK_WASM_TBREL;
  103. break;
  104. default:
  105. llvm_unreachable("Unknown target flag on GV operand");
  106. }
  107. const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx);
  108. if (MO.getOffset() != 0) {
  109. const auto *WasmSym = cast<MCSymbolWasm>(Sym);
  110. if (TargetFlags == WebAssemblyII::MO_GOT)
  111. report_fatal_error("GOT symbol references do not support offsets");
  112. if (WasmSym->isFunction())
  113. report_fatal_error("Function addresses with offsets not supported");
  114. if (WasmSym->isGlobal())
  115. report_fatal_error("Global indexes with offsets not supported");
  116. if (WasmSym->isTag())
  117. report_fatal_error("Tag indexes with offsets not supported");
  118. if (WasmSym->isTable())
  119. report_fatal_error("Table indexes with offsets not supported");
  120. Expr = MCBinaryExpr::createAdd(
  121. Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
  122. }
  123. return MCOperand::createExpr(Expr);
  124. }
  125. MCOperand WebAssemblyMCInstLower::lowerTypeIndexOperand(
  126. SmallVector<wasm::ValType, 1> &&Returns,
  127. SmallVector<wasm::ValType, 4> &&Params) const {
  128. auto Signature = std::make_unique<wasm::WasmSignature>(std::move(Returns),
  129. std::move(Params));
  130. MCSymbol *Sym = Printer.createTempSymbol("typeindex");
  131. auto *WasmSym = cast<MCSymbolWasm>(Sym);
  132. WasmSym->setSignature(Signature.get());
  133. Printer.addSignature(std::move(Signature));
  134. WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
  135. const MCExpr *Expr =
  136. MCSymbolRefExpr::create(WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
  137. return MCOperand::createExpr(Expr);
  138. }
  139. static void getFunctionReturns(const MachineInstr *MI,
  140. SmallVectorImpl<wasm::ValType> &Returns) {
  141. const Function &F = MI->getMF()->getFunction();
  142. const TargetMachine &TM = MI->getMF()->getTarget();
  143. Type *RetTy = F.getReturnType();
  144. SmallVector<MVT, 4> CallerRetTys;
  145. computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
  146. valTypesFromMVTs(CallerRetTys, Returns);
  147. }
  148. void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
  149. MCInst &OutMI) const {
  150. OutMI.setOpcode(MI->getOpcode());
  151. const MCInstrDesc &Desc = MI->getDesc();
  152. unsigned NumVariadicDefs = MI->getNumExplicitDefs() - Desc.getNumDefs();
  153. for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
  154. const MachineOperand &MO = MI->getOperand(I);
  155. MCOperand MCOp;
  156. switch (MO.getType()) {
  157. default:
  158. MI->print(errs());
  159. llvm_unreachable("unknown operand type");
  160. case MachineOperand::MO_MachineBasicBlock:
  161. MI->print(errs());
  162. llvm_unreachable("MachineBasicBlock operand should have been rewritten");
  163. case MachineOperand::MO_Register: {
  164. // Ignore all implicit register operands.
  165. if (MO.isImplicit())
  166. continue;
  167. const WebAssemblyFunctionInfo &MFI =
  168. *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
  169. unsigned WAReg = MFI.getWAReg(MO.getReg());
  170. MCOp = MCOperand::createReg(WAReg);
  171. break;
  172. }
  173. case MachineOperand::MO_Immediate: {
  174. unsigned DescIndex = I - NumVariadicDefs;
  175. if (DescIndex < Desc.NumOperands) {
  176. const MCOperandInfo &Info = Desc.operands()[DescIndex];
  177. if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
  178. SmallVector<wasm::ValType, 4> Returns;
  179. SmallVector<wasm::ValType, 4> Params;
  180. const MachineRegisterInfo &MRI =
  181. MI->getParent()->getParent()->getRegInfo();
  182. for (const MachineOperand &MO : MI->defs())
  183. Returns.push_back(
  184. WebAssembly::regClassToValType(MRI.getRegClass(MO.getReg())));
  185. for (const MachineOperand &MO : MI->explicit_uses())
  186. if (MO.isReg())
  187. Params.push_back(
  188. WebAssembly::regClassToValType(MRI.getRegClass(MO.getReg())));
  189. // call_indirect instructions have a callee operand at the end which
  190. // doesn't count as a param.
  191. if (WebAssembly::isCallIndirect(MI->getOpcode()))
  192. Params.pop_back();
  193. // return_call_indirect instructions have the return type of the
  194. // caller
  195. if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT)
  196. getFunctionReturns(MI, Returns);
  197. MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));
  198. break;
  199. } else if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
  200. auto BT = static_cast<WebAssembly::BlockType>(MO.getImm());
  201. assert(BT != WebAssembly::BlockType::Invalid);
  202. if (BT == WebAssembly::BlockType::Multivalue) {
  203. SmallVector<wasm::ValType, 1> Returns;
  204. getFunctionReturns(MI, Returns);
  205. MCOp = lowerTypeIndexOperand(std::move(Returns),
  206. SmallVector<wasm::ValType, 4>());
  207. break;
  208. }
  209. }
  210. }
  211. MCOp = MCOperand::createImm(MO.getImm());
  212. break;
  213. }
  214. case MachineOperand::MO_FPImmediate: {
  215. const ConstantFP *Imm = MO.getFPImm();
  216. const uint64_t BitPattern =
  217. Imm->getValueAPF().bitcastToAPInt().getZExtValue();
  218. if (Imm->getType()->isFloatTy())
  219. MCOp = MCOperand::createSFPImm(static_cast<uint32_t>(BitPattern));
  220. else if (Imm->getType()->isDoubleTy())
  221. MCOp = MCOperand::createDFPImm(BitPattern);
  222. else
  223. llvm_unreachable("unknown floating point immediate type");
  224. break;
  225. }
  226. case MachineOperand::MO_GlobalAddress:
  227. MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
  228. break;
  229. case MachineOperand::MO_ExternalSymbol:
  230. MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
  231. break;
  232. case MachineOperand::MO_MCSymbol:
  233. assert(MO.getTargetFlags() == 0 &&
  234. "WebAssembly does not use target flags on MCSymbol");
  235. MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
  236. break;
  237. }
  238. OutMI.addOperand(MCOp);
  239. }
  240. if (!WasmKeepRegisters)
  241. removeRegisterOperands(MI, OutMI);
  242. else if (Desc.variadicOpsAreDefs())
  243. OutMI.insert(OutMI.begin(), MCOperand::createImm(MI->getNumExplicitDefs()));
  244. }
  245. static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
  246. // Remove all uses of stackified registers to bring the instruction format
  247. // into its final stack form used thruout MC, and transition opcodes to
  248. // their _S variant.
  249. // We do this separate from the above code that still may need these
  250. // registers for e.g. call_indirect signatures.
  251. // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
  252. // details.
  253. // TODO: the code above creates new registers which are then removed here.
  254. // That code could be slightly simplified by not doing that, though maybe
  255. // it is simpler conceptually to keep the code above in "register mode"
  256. // until this transition point.
  257. // FIXME: we are not processing inline assembly, which contains register
  258. // operands, because it is used by later target generic code.
  259. if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
  260. return;
  261. // Transform to _S instruction.
  262. auto RegOpcode = OutMI.getOpcode();
  263. auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
  264. assert(StackOpcode != -1 && "Failed to stackify instruction");
  265. OutMI.setOpcode(StackOpcode);
  266. // Remove register operands.
  267. for (auto I = OutMI.getNumOperands(); I; --I) {
  268. auto &MO = OutMI.getOperand(I - 1);
  269. if (MO.isReg()) {
  270. OutMI.erase(&MO);
  271. }
  272. }
  273. }