LLVM  12.0.0git
WebAssemblyMCInstLower.cpp
Go to the documentation of this file.
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 
15 #include "WebAssemblyMCInstLower.h"
18 #include "WebAssemblyAsmPrinter.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"
31 using namespace llvm;
32 
33 // This disables the removal of registers when lowering into MC, as required
34 // by some current tests.
36  WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
37  cl::desc("WebAssembly: output stack registers in"
38  " instruction output for test purposes only."),
39  cl::init(false));
40 
43 
44 static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
45 
46 MCSymbol *
47 WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
48  const GlobalValue *Global = MO.getGlobal();
49  if (!isa<Function>(Global))
50  return cast<MCSymbolWasm>(Printer.getSymbol(Global));
51 
52  const auto *FuncTy = cast<FunctionType>(Global->getValueType());
53  const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
54  const TargetMachine &TM = MF.getTarget();
55  const Function &CurrentFunc = MF.getFunction();
56 
57  SmallVector<MVT, 1> ResultMVTs;
58  SmallVector<MVT, 4> ParamMVTs;
59  const auto *const F = dyn_cast<Function>(Global);
60  computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs);
61  auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs);
62 
63  bool InvokeDetected = false;
64  auto *WasmSym = Printer.getMCSymbolForFunction(
65  F, EnableEmException || EnableEmSjLj, Signature.get(), InvokeDetected);
66  WasmSym->setSignature(Signature.get());
67  Printer.addSignature(std::move(Signature));
68  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
69  return WasmSym;
70 }
71 
72 MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
73  const MachineOperand &MO) const {
74  const char *Name = MO.getSymbolName();
75  auto *WasmSym = cast<MCSymbolWasm>(Printer.GetExternalSymbolSymbol(Name));
76  const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
77 
78  // Except for certain known symbols, all symbols used by CodeGen are
79  // functions. It's OK to hardcode knowledge of specific symbols here; this
80  // method is precisely there for fetching the signatures of known
81  // Clang-provided symbols.
82  if (strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0 ||
83  strcmp(Name, "__memory_base") == 0 || strcmp(Name, "__table_base") == 0 ||
84  strcmp(Name, "__tls_size") == 0 || strcmp(Name, "__tls_align") == 0) {
85  bool Mutable =
86  strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0;
87  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
88  WasmSym->setGlobalType(wasm::WasmGlobalType{
89  uint8_t(Subtarget.hasAddr64() && strcmp(Name, "__table_base") != 0
92  Mutable});
93  return WasmSym;
94  }
95 
98  if (strcmp(Name, "__cpp_exception") == 0) {
99  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT);
100  // We can't confirm its signature index for now because there can be
101  // imported exceptions. Set it to be 0 for now.
102  WasmSym->setEventType(
103  {wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0});
104  // We may have multiple C++ compilation units to be linked together, each of
105  // which defines the exception symbol. To resolve them, we declare them as
106  // weak.
107  WasmSym->setWeak(true);
108  WasmSym->setExternal(true);
109 
110  // All C++ exceptions are assumed to have a single i32 (for wasm32) or i64
111  // (for wasm64) param type and void return type. The reaon is, all C++
112  // exception values are pointers, and to share the type section with
113  // functions, exceptions are assumed to have void return type.
114  Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64
116  } else { // Function symbols
117  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
118  getLibcallSignature(Subtarget, Name, Returns, Params);
119  }
120  auto Signature =
121  std::make_unique<wasm::WasmSignature>(std::move(Returns), std::move(Params));
122  WasmSym->setSignature(Signature.get());
123  Printer.addSignature(std::move(Signature));
124 
125  return WasmSym;
126 }
127 
128 MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
129  MCSymbol *Sym) const {
131  unsigned TargetFlags = MO.getTargetFlags();
132 
133  switch (TargetFlags) {
135  break;
138  break;
141  break;
144  break;
147  break;
148  default:
149  llvm_unreachable("Unknown target flag on GV operand");
150  }
151 
152  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx);
153 
154  if (MO.getOffset() != 0) {
155  const auto *WasmSym = cast<MCSymbolWasm>(Sym);
156  if (TargetFlags == WebAssemblyII::MO_GOT)
157  report_fatal_error("GOT symbol references do not support offsets");
158  if (WasmSym->isFunction())
159  report_fatal_error("Function addresses with offsets not supported");
160  if (WasmSym->isGlobal())
161  report_fatal_error("Global indexes with offsets not supported");
162  if (WasmSym->isEvent())
163  report_fatal_error("Event indexes with offsets not supported");
164 
166  Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
167  }
168 
169  return MCOperand::createExpr(Expr);
170 }
171 
172 MCOperand WebAssemblyMCInstLower::lowerTypeIndexOperand(
174  SmallVector<wasm::ValType, 4> &&Params) const {
175  auto Signature = std::make_unique<wasm::WasmSignature>(std::move(Returns),
176  std::move(Params));
177  MCSymbol *Sym = Printer.createTempSymbol("typeindex");
178  auto *WasmSym = cast<MCSymbolWasm>(Sym);
179  WasmSym->setSignature(Signature.get());
180  Printer.addSignature(std::move(Signature));
181  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
182  const MCExpr *Expr =
184  return MCOperand::createExpr(Expr);
185 }
186 
187 // Return the WebAssembly type associated with the given register class.
189  if (RC == &WebAssembly::I32RegClass)
190  return wasm::ValType::I32;
191  if (RC == &WebAssembly::I64RegClass)
192  return wasm::ValType::I64;
193  if (RC == &WebAssembly::F32RegClass)
194  return wasm::ValType::F32;
195  if (RC == &WebAssembly::F64RegClass)
196  return wasm::ValType::F64;
197  if (RC == &WebAssembly::V128RegClass)
198  return wasm::ValType::V128;
199  llvm_unreachable("Unexpected register class");
200 }
201 
202 static void getFunctionReturns(const MachineInstr *MI,
204  const Function &F = MI->getMF()->getFunction();
205  const TargetMachine &TM = MI->getMF()->getTarget();
206  Type *RetTy = F.getReturnType();
207  SmallVector<MVT, 4> CallerRetTys;
208  computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
209  valTypesFromMVTs(CallerRetTys, Returns);
210 }
211 
213  MCInst &OutMI) const {
214  OutMI.setOpcode(MI->getOpcode());
215 
216  const MCInstrDesc &Desc = MI->getDesc();
217  unsigned NumVariadicDefs = MI->getNumExplicitDefs() - Desc.getNumDefs();
218  for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
219  const MachineOperand &MO = MI->getOperand(I);
220 
221  MCOperand MCOp;
222  switch (MO.getType()) {
223  default:
224  MI->print(errs());
225  llvm_unreachable("unknown operand type");
227  MI->print(errs());
228  llvm_unreachable("MachineBasicBlock operand should have been rewritten");
230  // Ignore all implicit register operands.
231  if (MO.isImplicit())
232  continue;
233  const WebAssemblyFunctionInfo &MFI =
234  *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
235  unsigned WAReg = MFI.getWAReg(MO.getReg());
236  MCOp = MCOperand::createReg(WAReg);
237  break;
238  }
240  unsigned DescIndex = I - NumVariadicDefs;
241  if (DescIndex < Desc.NumOperands) {
242  const MCOperandInfo &Info = Desc.OpInfo[DescIndex];
243  if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
246 
247  const MachineRegisterInfo &MRI =
248  MI->getParent()->getParent()->getRegInfo();
249  for (const MachineOperand &MO : MI->defs())
250  Returns.push_back(getType(MRI.getRegClass(MO.getReg())));
251  for (const MachineOperand &MO : MI->explicit_uses())
252  if (MO.isReg())
253  Params.push_back(getType(MRI.getRegClass(MO.getReg())));
254 
255  // call_indirect instructions have a callee operand at the end which
256  // doesn't count as a param.
257  if (WebAssembly::isCallIndirect(MI->getOpcode()))
258  Params.pop_back();
259 
260  // return_call_indirect instructions have the return type of the
261  // caller
262  if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT)
263  getFunctionReturns(MI, Returns);
264 
265  MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));
266  break;
267  } else if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
268  auto BT = static_cast<WebAssembly::BlockType>(MO.getImm());
272  getFunctionReturns(MI, Returns);
273  MCOp = lowerTypeIndexOperand(std::move(Returns),
275  break;
276  }
277  } else if (Info.OperandType == WebAssembly::OPERAND_HEAPTYPE) {
278  assert(static_cast<WebAssembly::HeapType>(MO.getImm()) !=
280  // With typed function references, this will need a case for type
281  // index operands. Otherwise, fall through.
282  }
283  }
284  MCOp = MCOperand::createImm(MO.getImm());
285  break;
286  }
288  // TODO: MC converts all floating point immediate operands to double.
289  // This is fine for numeric values, but may cause NaNs to change bits.
290  const ConstantFP *Imm = MO.getFPImm();
291  if (Imm->getType()->isFloatTy())
293  else if (Imm->getType()->isDoubleTy())
295  else
296  llvm_unreachable("unknown floating point immediate type");
297  break;
298  }
300  MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
301  break;
303  // The target flag indicates whether this is a symbol for a
304  // variable or a function.
305  assert(MO.getTargetFlags() == 0 &&
306  "WebAssembly uses only symbol flags on ExternalSymbols");
307  MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
308  break;
310  // This is currently used only for LSDA symbols (GCC_except_table),
311  // because global addresses or other external symbols are handled above.
312  assert(MO.getTargetFlags() == 0 &&
313  "WebAssembly does not use target flags on MCSymbol");
314  MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
315  break;
316  }
317 
318  OutMI.addOperand(MCOp);
319  }
320 
321  if (!WasmKeepRegisters)
322  removeRegisterOperands(MI, OutMI);
323  else if (Desc.variadicOpsAreDefs())
324  OutMI.insert(OutMI.begin(), MCOperand::createImm(MI->getNumExplicitDefs()));
325 }
326 
327 static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
328  // Remove all uses of stackified registers to bring the instruction format
329  // into its final stack form used thruout MC, and transition opcodes to
330  // their _S variant.
331  // We do this separate from the above code that still may need these
332  // registers for e.g. call_indirect signatures.
333  // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
334  // details.
335  // TODO: the code above creates new registers which are then removed here.
336  // That code could be slightly simplified by not doing that, though maybe
337  // it is simpler conceptually to keep the code above in "register mode"
338  // until this transition point.
339  // FIXME: we are not processing inline assembly, which contains register
340  // operands, because it is used by later target generic code.
341  if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
342  return;
343 
344  // Transform to _S instruction.
345  auto RegOpcode = OutMI.getOpcode();
346  auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
347  assert(StackOpcode != -1 && "Failed to stackify instruction");
348  OutMI.setOpcode(StackOpcode);
349 
350  // Remove register operands.
351  for (auto I = OutMI.getNumOperands(); I; --I) {
352  auto &MO = OutMI.getOperand(I - 1);
353  if (MO.isReg()) {
354  OutMI.erase(&MO);
355  }
356  }
357 }
unsigned getTargetFlags() const
const Function & getFunction() const
Definition: Function.h:135
iterator begin()
Definition: MCInst.h:193
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
int getStackOpcode(unsigned short Opcode)
MCSymbol * GetExternalSymbolSymbol(StringRef Sym) const
Return the MCSymbol for the specified ExternalSymbol.
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:381
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:140
This class represents lattice values for constants.
Definition: AllocatorList.h:23
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
MCSymbolWasm * getMCSymbolForFunction(const Function *F, bool EnableEmEH, wasm::WasmSignature *Sig, bool &InvokeDetected)
static MCOperand createExpr(const MCExpr *Val)
Definition: MCInst.h:136
Describe properties that are true of each instruction in the target description file.
Definition: MCInstrDesc.h:196
cl::opt< bool > EnableEmSjLj
This file declares the class to lower WebAssembly MachineInstrs to their corresponding MCInst records...
float convertToFloat() const
Definition: APFloat.h:1137
F(f)
cl::opt< bool > WasmKeepRegisters("wasm-keep-registers", cl::Hidden, cl::desc("WebAssembly: output stack registers in" " instruction output for test purposes only."), cl::init(false))
static void getFunctionReturns(const MachineInstr *MI, SmallVectorImpl< wasm::ValType > &Returns)
This file registers the WebAssembly target.
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:194
signature immediate for block/loop.
std::unique_ptr< wasm::WasmSignature > signatureFromMVTs(const SmallVectorImpl< MVT > &Results, const SmallVectorImpl< MVT > &Params)
static MCOperand createReg(unsigned Reg)
Definition: MCInst.h:115
const ConstantFP * getFPImm() const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: APFloat.h:43
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:35
void erase(iterator I)
Definition: MCInst.h:190
Name of external global symbol.
static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI)
const char * getSymbolName() const
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:246
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:520
iterator insert(iterator I, const MCOperand &Op)
Definition: MCInst.h:198
Analysis containing CSE Info
Definition: CSEInfo.cpp:25
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:158
void computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc, const Function &ContextFunc, const TargetMachine &TM, SmallVectorImpl< MVT > &Params, SmallVectorImpl< MVT > &Results)
unsigned short NumOperands
Definition: MCInstrDesc.h:199
void getLibcallSignature(const WebAssemblySubtarget &Subtarget, RTLIB::Libcall LC, SmallVectorImpl< wasm::ValType > &Rets, SmallVectorImpl< wasm::ValType > &Params)
bool isFloatTy() const
Return true if this is 'float', a 32-bit IEEE fp type.
Definition: Type.h:148
Address of a global value.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:427
unsigned const MachineRegisterInfo * MRI
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:46
This file provides signature information for runtime libcalls.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const WebAssemblySubtarget & getSubtarget() const
This file contains the declarations for the subclasses of Constant, which represent the different fla...
const GlobalValue * getGlobal() const
ConstantFP - Floating Point Values [float, double].
Definition: Constants.h:273
This file provides WebAssembly-specific target descriptions.
double convertToDouble() const
Definition: APFloat.h:1136
cl::opt< bool > EnableEmException
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
unsigned getNumOperands() const
Definition: MCInst.h:182
type signature immediate for call_indirect.
static wasm::ValType getType(const TargetRegisterClass *RC)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void addSignature(std::unique_ptr< wasm::WasmSignature > &&Sig)
const APFloat & getValueAPF() const
Definition: Constants.h:312
void setOpcode(unsigned Op)
Definition: MCInst.h:171
MCSymbol * getSymbol(const GlobalValue *GV) const
Definition: AsmPrinter.cpp:472
MachineOperand class - Representation of each machine instruction operand.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1116
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:180
unsigned getNumDefs() const
Return the number of MachineOperands that are register definitions.
Definition: MCInstrDesc.h:244
static MCOperand createFPImm(double Val)
Definition: MCInst.h:129
int64_t getImm() const
MCSymbol reference (for debug/eh info)
const MachineBasicBlock * getParent() const
Definition: MachineInstr.h:284
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Representation of each machine instruction.
Definition: MachineInstr.h:62
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
bool isCallIndirect(unsigned Opc)
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
int64_t getOffset() const
Return the offset from the symbol in this operand.
#define I(x, y, z)
Definition: MD5.cpp:59
This file declares WebAssembly-specific per-machine-function information.
virtual void print(raw_ostream &OS, const Module *M) const
print - Print out the internal state of the pass.
Definition: Pass.cpp:125
bool variadicOpsAreDefs() const
Return true if variadic operands of this instruction are definitions.
Definition: MCInstrDesc.h:410
unsigned getWAReg(unsigned VReg) const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
heap type immediate for ref.null.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void valTypesFromMVTs(const ArrayRef< MVT > &In, SmallVectorImpl< wasm::ValType > &Out)
void setSignature(wasm::WasmSignature *Sig)
Definition: MCSymbolWasm.h:115
MCSymbol * getMCSymbol() const
void computeLegalValueVTs(const Function &F, const TargetMachine &TM, Type *Ty, SmallVectorImpl< MVT > &ValueVTs)
void addOperand(const MCOperand Op)
Definition: MCInst.h:184
Floating-point immediate operand.
void lower(const MachineInstr *MI, MCInst &OutMI) const
const MCOperandInfo * OpInfo
Definition: MCInstrDesc.h:207
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:77
IRTranslator LLVM IR MI
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1556
Register getReg() const
getReg - Returns the register number.
This holds information about one operand of a machine instruction, indicating the register class for ...
Definition: MCInstrDesc.h:84
unsigned getOpcode() const
Definition: MCInst.h:172
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:34
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
Definition: Type.h:151
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
MCSymbol * createTempSymbol(const Twine &Name) const
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:122
bool isImplicit() const