LLVM  8.0.1
WebAssemblyAsmPrinter.cpp
Go to the documentation of this file.
1 //===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// This file contains a printer that converts from our internal
12 /// representation of machine-dependent LLVM code to the WebAssembly assembly
13 /// language.
14 ///
15 //===----------------------------------------------------------------------===//
16 
17 #include "WebAssemblyAsmPrinter.h"
21 #include "WebAssembly.h"
22 #include "WebAssemblyMCInstLower.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include "llvm/CodeGen/Analysis.h"
31 #include "llvm/IR/DataLayout.h"
32 #include "llvm/IR/GlobalVariable.h"
33 #include "llvm/MC/MCContext.h"
34 #include "llvm/MC/MCSectionWasm.h"
35 #include "llvm/MC/MCStreamer.h"
36 #include "llvm/MC/MCSymbol.h"
37 #include "llvm/MC/MCSymbolWasm.h"
38 #include "llvm/Support/Debug.h"
41 using namespace llvm;
42 
43 #define DEBUG_TYPE "asm-printer"
44 
45 //===----------------------------------------------------------------------===//
46 // Helpers.
47 //===----------------------------------------------------------------------===//
48 
49 MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {
50  const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
51  const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
54  if (TRI->isTypeLegalForClass(*TRC, T))
55  return T;
56  LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo);
57  llvm_unreachable("Unknown register type");
58  return MVT::Other;
59 }
60 
62  unsigned RegNo = MO.getReg();
64  "Unlowered physical register encountered during assembly printing");
65  assert(!MFI->isVRegStackified(RegNo));
66  unsigned WAReg = MFI->getWAReg(RegNo);
68  return '$' + utostr(WAReg);
69 }
70 
72  MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
73  return static_cast<WebAssemblyTargetStreamer *>(TS);
74 }
75 
76 //===----------------------------------------------------------------------===//
77 // WebAssemblyAsmPrinter Implementation.
78 //===----------------------------------------------------------------------===//
79 
81  for (auto &It : OutContext.getSymbols()) {
82  // Emit a .globaltype and .eventtype declaration.
83  auto Sym = cast<MCSymbolWasm>(It.getValue());
84  if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL)
86  else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT)
88  }
89 
90  for (const auto &F : M) {
91  // Emit function type info for all undefined functions
92  if (F.isDeclarationForLinker() && !F.isIntrinsic()) {
94  SmallVector<MVT, 4> Params;
95  ComputeSignatureVTs(F.getFunctionType(), F, TM, Params, Results);
96  auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));
97  Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
98  if (!Sym->getSignature()) {
99  auto Signature = SignatureFromMVTs(Results, Params);
100  Sym->setSignature(Signature.get());
101  addSignature(std::move(Signature));
102  }
103  // FIXME: this was originally intended for post-linking and was only used
104  // for imports that were only called indirectly (i.e. s2wasm could not
105  // infer the type from a call). With object files it applies to all
106  // imports. so fix the names and the tests, or rethink how import
107  // delcarations work in asm files.
109 
110  if (TM.getTargetTriple().isOSBinFormatWasm() &&
111  F.hasFnAttribute("wasm-import-module")) {
112  StringRef Name =
113  F.getFnAttribute("wasm-import-module").getValueAsString();
114  Sym->setImportModule(Name);
115  getTargetStreamer()->emitImportModule(Sym, Name);
116  }
117  if (TM.getTargetTriple().isOSBinFormatWasm() &&
118  F.hasFnAttribute("wasm-import-name")) {
119  StringRef Name =
120  F.getFnAttribute("wasm-import-name").getValueAsString();
121  Sym->setImportName(Name);
122  getTargetStreamer()->emitImportName(Sym, Name);
123  }
124  }
125  }
126 
127  for (const auto &G : M.globals()) {
128  if (!G.hasInitializer() && G.hasExternalLinkage()) {
129  if (G.getValueType()->isSized()) {
130  uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
131  OutStreamer->emitELFSize(getSymbol(&G),
133  }
134  }
135  }
136 
137  if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) {
138  for (const Metadata *MD : Named->operands()) {
139  const MDTuple *Tuple = dyn_cast<MDTuple>(MD);
140  if (!Tuple || Tuple->getNumOperands() != 2)
141  continue;
142  const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0));
143  const MDString *Contents = dyn_cast<MDString>(Tuple->getOperand(1));
144  if (!Name || !Contents)
145  continue;
146 
147  OutStreamer->PushSection();
148  std::string SectionName = (".custom_section." + Name->getString()).str();
149  MCSectionWasm *mySection =
151  OutStreamer->SwitchSection(mySection);
152  OutStreamer->EmitBytes(Contents->getString());
153  OutStreamer->PopSection();
154  }
155  }
156 }
157 
159  assert(MF->getConstantPool()->getConstants().empty() &&
160  "WebAssembly disables constant pools");
161 }
162 
164  // Nothing to do; jump tables are incorporated into the instruction stream.
165 }
166 
168  const Function &F = MF->getFunction();
169  SmallVector<MVT, 1> ResultVTs;
170  SmallVector<MVT, 4> ParamVTs;
171  ComputeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs);
172  auto Signature = SignatureFromMVTs(ResultVTs, ParamVTs);
173  auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym);
174  WasmSym->setSignature(Signature.get());
175  addSignature(std::move(Signature));
176  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
177 
178  // FIXME: clean up how params and results are emitted (use signatures)
180 
181  // Emit the function index.
182  if (MDNode *Idx = F.getMetadata("wasm.index")) {
183  assert(Idx->getNumOperands() == 1);
184 
186  cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
187  }
188 
190  ValTypesFromMVTs(MFI->getLocals(), Locals);
191  getTargetStreamer()->emitLocal(Locals);
192 
194 }
195 
197  LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
198 
199  switch (MI->getOpcode()) {
200  case WebAssembly::ARGUMENT_i32:
201  case WebAssembly::ARGUMENT_i32_S:
202  case WebAssembly::ARGUMENT_i64:
203  case WebAssembly::ARGUMENT_i64_S:
204  case WebAssembly::ARGUMENT_f32:
205  case WebAssembly::ARGUMENT_f32_S:
206  case WebAssembly::ARGUMENT_f64:
207  case WebAssembly::ARGUMENT_f64_S:
208  case WebAssembly::ARGUMENT_v16i8:
209  case WebAssembly::ARGUMENT_v16i8_S:
210  case WebAssembly::ARGUMENT_v8i16:
211  case WebAssembly::ARGUMENT_v8i16_S:
212  case WebAssembly::ARGUMENT_v4i32:
213  case WebAssembly::ARGUMENT_v4i32_S:
214  case WebAssembly::ARGUMENT_v2i64:
215  case WebAssembly::ARGUMENT_v2i64_S:
216  case WebAssembly::ARGUMENT_v4f32:
217  case WebAssembly::ARGUMENT_v4f32_S:
218  case WebAssembly::ARGUMENT_v2f64:
219  case WebAssembly::ARGUMENT_v2f64_S:
220  // These represent values which are live into the function entry, so there's
221  // no instruction to emit.
222  break;
223  case WebAssembly::FALLTHROUGH_RETURN_I32:
224  case WebAssembly::FALLTHROUGH_RETURN_I32_S:
225  case WebAssembly::FALLTHROUGH_RETURN_I64:
226  case WebAssembly::FALLTHROUGH_RETURN_I64_S:
227  case WebAssembly::FALLTHROUGH_RETURN_F32:
228  case WebAssembly::FALLTHROUGH_RETURN_F32_S:
229  case WebAssembly::FALLTHROUGH_RETURN_F64:
230  case WebAssembly::FALLTHROUGH_RETURN_F64_S:
231  case WebAssembly::FALLTHROUGH_RETURN_v16i8:
232  case WebAssembly::FALLTHROUGH_RETURN_v16i8_S:
233  case WebAssembly::FALLTHROUGH_RETURN_v8i16:
234  case WebAssembly::FALLTHROUGH_RETURN_v8i16_S:
235  case WebAssembly::FALLTHROUGH_RETURN_v4i32:
236  case WebAssembly::FALLTHROUGH_RETURN_v4i32_S:
237  case WebAssembly::FALLTHROUGH_RETURN_v2i64:
238  case WebAssembly::FALLTHROUGH_RETURN_v2i64_S:
239  case WebAssembly::FALLTHROUGH_RETURN_v4f32:
240  case WebAssembly::FALLTHROUGH_RETURN_v4f32_S:
241  case WebAssembly::FALLTHROUGH_RETURN_v2f64:
242  case WebAssembly::FALLTHROUGH_RETURN_v2f64_S: {
243  // These instructions represent the implicit return at the end of a
244  // function body. Always pops one value off the stack.
245  if (isVerbose()) {
246  OutStreamer->AddComment("fallthrough-return-value");
247  OutStreamer->AddBlankLine();
248  }
249  break;
250  }
251  case WebAssembly::FALLTHROUGH_RETURN_VOID:
252  case WebAssembly::FALLTHROUGH_RETURN_VOID_S:
253  // This instruction represents the implicit return at the end of a
254  // function body with no return value.
255  if (isVerbose()) {
256  OutStreamer->AddComment("fallthrough-return-void");
257  OutStreamer->AddBlankLine();
258  }
259  break;
260  default: {
261  WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
262  MCInst TmpInst;
263  MCInstLowering.Lower(MI, TmpInst);
264  EmitToStreamer(*OutStreamer, TmpInst);
265  break;
266  }
267  }
268 }
269 
271  if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV))
272  if (GV->getValueType()->isFunctionTy()) {
275  }
276  return AsmPrinter::lowerConstant(CV);
277 }
278 
280  unsigned OpNo, unsigned AsmVariant,
281  const char *ExtraCode,
282  raw_ostream &OS) {
283  if (AsmVariant != 0)
284  report_fatal_error("There are no defined alternate asm variants");
285 
286  // First try the generic code, which knows about modifiers like 'c' and 'n'.
287  if (!AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS))
288  return false;
289 
290  if (!ExtraCode) {
291  const MachineOperand &MO = MI->getOperand(OpNo);
292  switch (MO.getType()) {
294  OS << MO.getImm();
295  return false;
297  // FIXME: only opcode that still contains registers, as required by
298  // MachineInstr::getDebugVariable().
300  OS << regToString(MO);
301  return false;
303  getSymbol(MO.getGlobal())->print(OS, MAI);
304  printOffset(MO.getOffset(), OS);
305  return false;
308  printOffset(MO.getOffset(), OS);
309  return false;
311  MO.getMBB()->getSymbol()->print(OS, MAI);
312  return false;
313  default:
314  break;
315  }
316  }
317 
318  return true;
319 }
320 
322  unsigned OpNo,
323  unsigned AsmVariant,
324  const char *ExtraCode,
325  raw_ostream &OS) {
326  if (AsmVariant != 0)
327  report_fatal_error("There are no defined alternate asm variants");
328 
329  // The current approach to inline asm is that "r" constraints are expressed
330  // as local indices, rather than values on the operand stack. This simplifies
331  // using "r" as it eliminates the need to push and pop the values in a
332  // particular order, however it also makes it impossible to have an "m"
333  // constraint. So we don't support it.
334 
335  return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant, ExtraCode, OS);
336 }
337 
338 // Force static initialization.
342 }
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
MachineBasicBlock * getMBB() const
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition: AsmPrinter.h:94
const TargetRegisterClass * getRegClass(unsigned Reg) const
Return the register class of the specified virtual register.
MCSymbol * GetExternalSymbolSymbol(StringRef Sym) const
Return the MCSymbol for the specified ExternalSymbol.
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:323
This class is used to lower an MachineInstr into an MCInst.
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:24
const std::vector< MVT > & getLocals() const
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:65
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition: AsmPrinter.h:89
virtual void emitGlobalType(const MCSymbolWasm *Sym)=0
.globaltype
This class prints an WebAssembly MCInst to wasm file syntax.
unsigned getReg() const
getReg - Returns the register number.
static bool isVirtualRegister(unsigned Reg)
Return true if the specified register number is in the virtual register namespace.
Target specific streamer interface.
Definition: MCStreamer.h:84
MCSectionWasm * getWasmSection(const Twine &Section, SectionKind K)
Definition: MCContext.h:454
This file declares the class to lower WebAssembly MachineInstrs to their corresponding MCInst records...
void EmitInstruction(const MachineInstr *MI) override
Targets should implement this to emit instructions.
Function Alias Analysis Results
virtual void emitImportModule(const MCSymbolWasm *Sym, StringRef ImportModule)=0
.import_module
MachineBasicBlock reference.
unsigned const TargetRegisterInfo * TRI
Metadata node.
Definition: Metadata.h:864
F(f)
MachineFunction * MF
The current machine function.
Definition: AsmPrinter.h:97
const MDOperand & getOperand(unsigned I) const
Definition: Metadata.h:1069
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
Tuple of metadata.
Definition: Metadata.h:1106
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
A tuple of MDNodes.
Definition: Metadata.h:1326
MVT getRegType(unsigned RegNo) const
amdgpu Simplify well known AMD library false Value Value const Twine & Name
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:36
MDNode * getMetadata(unsigned KindID) const
Get the current metadata attachments for the given kind, if any.
Definition: Metadata.cpp:1444
Name of external global symbol.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:409
const char * getSymbolName() const
INLINEASM - Represents an inline asm block.
Definition: ISDOpcodes.h:667
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS) override
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant...
std::string regToString(const MachineOperand &MO)
virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant as...
RegisterAsmPrinter - Helper template for registering a target specific assembly printer, for use in the target machine initialization function.
void printOffset(int64_t Offset, raw_ostream &OS) const
This is just convenient handler for printing offsets.
const SymbolTable & getSymbols() const
getSymbols - Get a reference for the symbol table for clients that want to, for example, iterate over all symbols.
Definition: MCContext.h:361
bool isVerbose() const
Return true if assembly output should contain comments.
Definition: AsmPrinter.h:203
bool isTypeLegalForClass(const TargetRegisterClass &RC, MVT T) const
Return true if the given TargetRegisterClass has the ValueType T.
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:161
WebAssembly-specific streamer interface, to implement support WebAssembly-specific assembly directive...
StringRef getString() const
Definition: Metadata.cpp:464
Address of a global value.
MCSymbol * CurrentFnSym
The symbol for the current function.
Definition: AsmPrinter.h:113
Machine Value Type.
const MCAsmInfo * MAI
Target Asm Printer information.
Definition: AsmPrinter.h:85
This is an important base class in LLVM.
Definition: Constant.h:42
void EmitEndOfAsmFile(Module &M) override
This virtual method can be overridden by targets that want to emit something at the end of their file...
This represents a section on wasm.
Definition: MCSectionWasm.h:28
const GlobalValue * getGlobal() const
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant...
This file provides WebAssembly-specific target descriptions.
TargetMachine & TM
Target machine description.
Definition: AsmPrinter.h:82
std::unique_ptr< wasm::WasmSignature > SignatureFromMVTs(const SmallVectorImpl< MVT > &Results, const SmallVectorImpl< MVT > &Params)
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
const MCExpr * lowerConstant(const Constant *CV) override
Lower the specified LLVM Constant to an MCExpr.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void addSignature(std::unique_ptr< wasm::WasmSignature > &&Sig)
This file declares WebAssembly-specific target streamer classes.
const std::vector< MachineConstantPoolEntry > & getConstants() const
void Lower(const MachineInstr *MI, MCInst &OutMI) const
This file contains the WebAssembly implementation of the WebAssemblyRegisterInfo class.
void LLVMInitializeWebAssemblyAsmPrinter()
MCSymbol * getSymbol(const GlobalValue *GV) const
Definition: AsmPrinter.cpp:430
virtual const MCExpr * lowerConstant(const Constant *CV)
Lower the specified LLVM Constant to an MCExpr.
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:847
const DataFlowGraph & G
Definition: RDFGraph.cpp:211
void EmitToStreamer(MCStreamer &S, const MCInst &Inst)
Definition: AsmPrinter.cpp:231
static SectionKind getMetadata()
Definition: SectionKind.h:179
std::string utostr(uint64_t X, bool isNeg=false)
Definition: StringExtras.h:224
int64_t getImm() const
const Function & getFunction() const
Return the LLVM function that this machine code represents.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:133
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition: Function.h:164
void ComputeSignatureVTs(const FunctionType *Ty, const Function &F, const TargetMachine &TM, SmallVectorImpl< MVT > &Params, SmallVectorImpl< MVT > &Results)
virtual void EmitFunctionBodyStart()
Targets can override this to emit stuff before the first basic block in the function.
Definition: AsmPrinter.h:392
void EmitConstantPool() override
Print to the current output stream assembly representations of the constants in the constant pool MCP...
const WebAssemblyRegisterInfo * getRegisterInfo() const override
void EmitJumpTableInfo() override
Print assembly representations of the jump tables used by the current function to the current output ...
Representation of each machine instruction.
Definition: MachineInstr.h:64
virtual void emitFunctionType(const MCSymbolWasm *Sym)=0
.functype
void ValTypesFromMVTs(const ArrayRef< MVT > &In, SmallVectorImpl< wasm::ValType > &Out)
virtual void emitImportName(const MCSymbolWasm *Sym, StringRef ImportName)=0
.import_name
int64_t getOffset() const
Return the offset from the symbol in this operand.
MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
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:124
void EmitFunctionBodyStart() override
Targets can override this to emit stuff before the first basic block in the function.
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.h:323
uint32_t Size
Definition: Profile.cpp:47
virtual void emitEventType(const MCSymbolWasm *Sym)=0
.eventtype
unsigned getWAReg(unsigned VReg) const
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS) override
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant as...
virtual void emitLocal(ArrayRef< wasm::ValType > Types)=0
.local
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:46
IRTranslator LLVM IR MI
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
A single uniqued string.
Definition: Metadata.h:604
Target & getTheWebAssemblyTarget32()
unsigned getNumOperands() const
Return number of MDNode operands.
Definition: Metadata.h:1075
#define LLVM_DEBUG(X)
Definition: Debug.h:123
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:414
Target & getTheWebAssemblyTarget64()
WebAssemblyTargetStreamer * getTargetStreamer()
Root of the metadata hierarchy.
Definition: Metadata.h:58
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx)
Definition: MCExpr.cpp:164
virtual void emitIndIdx(const MCExpr *Value)=0
.indidx
void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition: MCSymbol.cpp:60