LLVM  10.0.0svn
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"
16 #include "WebAssemblyAsmPrinter.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/MC/MCAsmInfo.h"
24 #include "llvm/MC/MCContext.h"
25 #include "llvm/MC/MCExpr.h"
26 #include "llvm/MC/MCInst.h"
27 #include "llvm/MC/MCSymbolWasm.h"
30 using namespace llvm;
31 
32 // Defines llvm::WebAssembly::getStackOpcode to convert register instructions to
33 // stack instructions
34 #define GET_INSTRMAP_INFO 1
35 #include "WebAssemblyGenInstrInfo.inc"
36 
37 // This disables the removal of registers when lowering into MC, as required
38 // by some current tests.
40  WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
41  cl::desc("WebAssembly: output stack registers in"
42  " instruction output for test purposes only."),
43  cl::init(false));
44 
45 static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
46 
47 MCSymbol *
48 WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
49  const GlobalValue *Global = MO.getGlobal();
50  auto *WasmSym = cast<MCSymbolWasm>(Printer.getSymbol(Global));
51 
52  if (const auto *FuncTy = dyn_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  computeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs);
60 
61  auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs);
62  WasmSym->setSignature(Signature.get());
63  Printer.addSignature(std::move(Signature));
64  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
65  }
66 
67  return WasmSym;
68 }
69 
70 MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
71  const MachineOperand &MO) const {
72  const char *Name = MO.getSymbolName();
73  auto *WasmSym = cast<MCSymbolWasm>(Printer.GetExternalSymbolSymbol(Name));
74  const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
75 
76  // Except for certain known symbols, all symbols used by CodeGen are
77  // functions. It's OK to hardcode knowledge of specific symbols here; this
78  // method is precisely there for fetching the signatures of known
79  // Clang-provided symbols.
80  if (strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0 ||
81  strcmp(Name, "__memory_base") == 0 || strcmp(Name, "__table_base") == 0 ||
82  strcmp(Name, "__tls_size") == 0 || strcmp(Name, "__tls_align") == 0) {
83  bool Mutable =
84  strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0;
85  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
86  WasmSym->setGlobalType(wasm::WasmGlobalType{
87  uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64
89  Mutable});
90  return WasmSym;
91  }
92 
95  if (strcmp(Name, "__cpp_exception") == 0) {
96  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT);
97  // We can't confirm its signature index for now because there can be
98  // imported exceptions. Set it to be 0 for now.
99  WasmSym->setEventType(
100  {wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0});
101  // We may have multiple C++ compilation units to be linked together, each of
102  // which defines the exception symbol. To resolve them, we declare them as
103  // weak.
104  WasmSym->setWeak(true);
105  WasmSym->setExternal(true);
106 
107  // All C++ exceptions are assumed to have a single i32 (for wasm32) or i64
108  // (for wasm64) param type and void return type. The reaon is, all C++
109  // exception values are pointers, and to share the type section with
110  // functions, exceptions are assumed to have void return type.
111  Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64
113  } else { // Function symbols
114  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
115  getLibcallSignature(Subtarget, Name, Returns, Params);
116  }
117  auto Signature =
118  std::make_unique<wasm::WasmSignature>(std::move(Returns), std::move(Params));
119  WasmSym->setSignature(Signature.get());
120  Printer.addSignature(std::move(Signature));
121 
122  return WasmSym;
123 }
124 
125 MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
126  MCSymbol *Sym) const {
128  unsigned TargetFlags = MO.getTargetFlags();
129 
130  switch (TargetFlags) {
132  break;
135  break;
138  break;
141  break;
142  default:
143  llvm_unreachable("Unknown target flag on GV operand");
144  }
145 
146  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx);
147 
148  if (MO.getOffset() != 0) {
149  const auto *WasmSym = cast<MCSymbolWasm>(Sym);
150  if (TargetFlags == WebAssemblyII::MO_GOT)
151  report_fatal_error("GOT symbol references do not support offsets");
152  if (WasmSym->isFunction())
153  report_fatal_error("Function addresses with offsets not supported");
154  if (WasmSym->isGlobal())
155  report_fatal_error("Global indexes with offsets not supported");
156  if (WasmSym->isEvent())
157  report_fatal_error("Event indexes with offsets not supported");
158 
160  Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
161  }
162 
163  return MCOperand::createExpr(Expr);
164 }
165 
166 // Return the WebAssembly type associated with the given register class.
168  if (RC == &WebAssembly::I32RegClass)
169  return wasm::ValType::I32;
170  if (RC == &WebAssembly::I64RegClass)
171  return wasm::ValType::I64;
172  if (RC == &WebAssembly::F32RegClass)
173  return wasm::ValType::F32;
174  if (RC == &WebAssembly::F64RegClass)
175  return wasm::ValType::F64;
176  if (RC == &WebAssembly::V128RegClass)
177  return wasm::ValType::V128;
178  llvm_unreachable("Unexpected register class");
179 }
180 
182  MCInst &OutMI) const {
183  OutMI.setOpcode(MI->getOpcode());
184 
185  const MCInstrDesc &Desc = MI->getDesc();
186  for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
187  const MachineOperand &MO = MI->getOperand(I);
188 
189  MCOperand MCOp;
190  switch (MO.getType()) {
191  default:
192  MI->print(errs());
193  llvm_unreachable("unknown operand type");
195  MI->print(errs());
196  llvm_unreachable("MachineBasicBlock operand should have been rewritten");
198  // Ignore all implicit register operands.
199  if (MO.isImplicit())
200  continue;
201  const WebAssemblyFunctionInfo &MFI =
203  unsigned WAReg = MFI.getWAReg(MO.getReg());
204  MCOp = MCOperand::createReg(WAReg);
205  break;
206  }
208  if (I < Desc.NumOperands) {
209  const MCOperandInfo &Info = Desc.OpInfo[I];
211  MCSymbol *Sym = Printer.createTempSymbol("typeindex");
212 
215 
216  const MachineRegisterInfo &MRI =
217  MI->getParent()->getParent()->getRegInfo();
218  for (const MachineOperand &MO : MI->defs())
219  Returns.push_back(getType(MRI.getRegClass(MO.getReg())));
220  for (const MachineOperand &MO : MI->explicit_uses())
221  if (MO.isReg())
222  Params.push_back(getType(MRI.getRegClass(MO.getReg())));
223 
224  // call_indirect instructions have a callee operand at the end which
225  // doesn't count as a param.
227  Params.pop_back();
228 
229  // return_call_indirect instructions have the return type of the
230  // caller
231  if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT) {
232  const Function &F = MI->getMF()->getFunction();
233  const TargetMachine &TM = MI->getMF()->getTarget();
234  Type *RetTy = F.getReturnType();
235  SmallVector<MVT, 4> CallerRetTys;
236  computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
237  valTypesFromMVTs(CallerRetTys, Returns);
238  }
239 
240  auto *WasmSym = cast<MCSymbolWasm>(Sym);
241  auto Signature = std::make_unique<wasm::WasmSignature>(std::move(Returns),
242  std::move(Params));
243  WasmSym->setSignature(Signature.get());
244  Printer.addSignature(std::move(Signature));
245  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
246 
247  const MCExpr *Expr = MCSymbolRefExpr::create(
248  WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
249  MCOp = MCOperand::createExpr(Expr);
250  break;
251  }
252  }
253  MCOp = MCOperand::createImm(MO.getImm());
254  break;
256  // TODO: MC converts all floating point immediate operands to double.
257  // This is fine for numeric values, but may cause NaNs to change bits.
258  const ConstantFP *Imm = MO.getFPImm();
259  if (Imm->getType()->isFloatTy())
261  else if (Imm->getType()->isDoubleTy())
263  else
264  llvm_unreachable("unknown floating point immediate type");
265  break;
266  }
268  MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
269  break;
271  // The target flag indicates whether this is a symbol for a
272  // variable or a function.
273  assert(MO.getTargetFlags() == 0 &&
274  "WebAssembly uses only symbol flags on ExternalSymbols");
275  MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
276  break;
278  // This is currently used only for LSDA symbols (GCC_except_table),
279  // because global addresses or other external symbols are handled above.
280  assert(MO.getTargetFlags() == 0 &&
281  "WebAssembly does not use target flags on MCSymbol");
282  MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
283  break;
284  }
285 
286  OutMI.addOperand(MCOp);
287  }
288 
289  if (!WasmKeepRegisters)
290  removeRegisterOperands(MI, OutMI);
291 }
292 
293 static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
294  // Remove all uses of stackified registers to bring the instruction format
295  // into its final stack form used thruout MC, and transition opcodes to
296  // their _S variant.
297  // We do this seperate from the above code that still may need these
298  // registers for e.g. call_indirect signatures.
299  // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
300  // details.
301  // TODO: the code above creates new registers which are then removed here.
302  // That code could be slightly simplified by not doing that, though maybe
303  // it is simpler conceptually to keep the code above in "register mode"
304  // until this transition point.
305  // FIXME: we are not processing inline assembly, which contains register
306  // operands, because it is used by later target generic code.
307  if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
308  return;
309 
310  // Transform to _S instruction.
311  auto RegOpcode = OutMI.getOpcode();
312  auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
313  assert(StackOpcode != -1 && "Failed to stackify instruction");
314  OutMI.setOpcode(StackOpcode);
315 
316  // Remove register operands.
317  for (auto I = OutMI.getNumOperands(); I; --I) {
318  auto &MO = OutMI.getOperand(I - 1);
319  if (MO.isReg()) {
320  OutMI.erase(&MO);
321  }
322  }
323 }
unsigned getTargetFlags() const
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
bool isLabel() const
Returns true if the MachineInstr represents a label.
MCSymbol * GetExternalSymbolSymbol(StringRef Sym) const
Return the MCSymbol for the specified ExternalSymbol.
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:327
const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
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:139
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
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
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:179
bool isInlineAsm() const
This file declares the class to lower WebAssembly MachineInstrs to their corresponding MCInst records...
float convertToFloat() const
Definition: APFloat.h:1113
MachineBasicBlock reference.
F(f)
void computeSignatureVTs(const FunctionType *Ty, const Function &F, const TargetMachine &TM, SmallVectorImpl< MVT > &Params, SmallVectorImpl< MVT > &Results)
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))
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
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
unsigned getNumOperands() const
Retuns the total number of operands.
Definition: MachineInstr.h:414
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:189
Name of external global symbol.
static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI)
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:411
const char * getSymbolName() const
uint8_t OperandType
Information about the type of the operand.
Definition: MCInstrDesc.h:82
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
Definition: MachineInstr.h:408
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:245
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:465
Analysis containing CSE Info
Definition: CSEInfo.cpp:20
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:158
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false)
Definition: MCExpr.cpp:169
unsigned short NumOperands
Definition: MCInstrDesc.h:182
void getLibcallSignature(const WebAssemblySubtarget &Subtarget, RTLIB::Libcall LC, SmallVectorImpl< wasm::ValType > &Rets, SmallVectorImpl< wasm::ValType > &Params)
bool isFloatTy() const
Return true if this is &#39;float&#39;, a 32-bit IEEE fp type.
Definition: Type.h:147
Address of a global value.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:432
Type * getReturnType() const
Returns the type of the ret val.
Definition: Function.h:168
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:263
This file provides WebAssembly-specific target descriptions.
double convertToDouble() const
Definition: APFloat.h:1112
iterator_range< mop_iterator > defs()
Returns a range over all explicit operands that are register definitions.
Definition: MachineInstr.h:499
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
unsigned getNumOperands() const
Definition: MCInst.h:181
void print(raw_ostream &OS, bool IsStandalone=true, bool SkipOpers=false, bool SkipDebugLoc=false, bool AddNewLine=true, const TargetInstrInfo *TII=nullptr) const
Print this MI to OS.
type signature immediate for call_indirect.
static wasm::ValType getType(const TargetRegisterClass *RC)
bool isDebugInstr() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
iterator_range< mop_iterator > explicit_uses()
Definition: MachineInstr.h:517
void addSignature(std::unique_ptr< wasm::WasmSignature > &&Sig)
const APFloat & getValueAPF() const
Definition: Constants.h:302
void setOpcode(unsigned Op)
Definition: MCInst.h:170
MCSymbol * getSymbol(const GlobalValue *GV) const
Definition: AsmPrinter.cpp:449
MachineOperand class - Representation of each machine instruction operand.
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:837
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:179
static MCOperand createFPImm(double Val)
Definition: MCInst.h:129
int64_t getImm() const
const Function & getFunction() const
Return the LLVM function that this machine code represents.
MCSymbol reference (for debug/eh info)
const MachineBasicBlock * getParent() const
Definition: MachineInstr.h:256
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
Representation of each machine instruction.
Definition: MachineInstr.h:64
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.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
int64_t getOffset() const
Return the offset from the symbol in this operand.
#define I(x, y, z)
Definition: MD5.cpp:58
This file declares WebAssembly-specific per-machine-function information.
Type * getValueType() const
Definition: GlobalValue.h:279
unsigned getWAReg(unsigned VReg) const
const LLVMTargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
bool isReg() const
isReg - Tests if this is a MO_Register operand.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void valTypesFromMVTs(const ArrayRef< MVT > &In, SmallVectorImpl< wasm::ValType > &Out)
MCSymbol * getMCSymbol() const
void computeLegalValueVTs(const Function &F, const TargetMachine &TM, Type *Ty, SmallVectorImpl< MVT > &ValueVTs)
Floating-point immediate operand.
void lower(const MachineInstr *MI, MCInst &OutMI) const
const MCOperandInfo * OpInfo
Definition: MCInstrDesc.h:190
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:65
IRTranslator LLVM IR MI
void addOperand(const MCOperand &Op)
Definition: MCInst.h:183
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:70
unsigned getOpcode() const
Definition: MCInst.h:171
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:416
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:34
bool isDoubleTy() const
Return true if this is &#39;double&#39;, a 64-bit IEEE fp type.
Definition: Type.h:150
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