LLVM  4.0.0
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 /// \brief 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 
20 #include "WebAssembly.h"
21 #include "WebAssemblyMCInstLower.h"
24 #include "WebAssemblySubtarget.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include "llvm/CodeGen/Analysis.h"
30 #include "llvm/IR/DataLayout.h"
31 #include "llvm/MC/MCContext.h"
32 #include "llvm/MC/MCStreamer.h"
33 #include "llvm/MC/MCSymbol.h"
34 #include "llvm/Support/Debug.h"
37 using namespace llvm;
38 
39 #define DEBUG_TYPE "asm-printer"
40 
41 namespace {
42 
43 class WebAssemblyAsmPrinter final : public AsmPrinter {
44  const MachineRegisterInfo *MRI;
46 
47 public:
48  WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
49  : AsmPrinter(TM, std::move(Streamer)), MRI(nullptr), MFI(nullptr) {}
50 
51 private:
52  StringRef getPassName() const override {
53  return "WebAssembly Assembly Printer";
54  }
55 
56  //===------------------------------------------------------------------===//
57  // MachineFunctionPass Implementation.
58  //===------------------------------------------------------------------===//
59 
60  bool runOnMachineFunction(MachineFunction &MF) override {
61  MRI = &MF.getRegInfo();
62  MFI = MF.getInfo<WebAssemblyFunctionInfo>();
64  }
65 
66  //===------------------------------------------------------------------===//
67  // AsmPrinter Implementation.
68  //===------------------------------------------------------------------===//
69 
70  void EmitEndOfAsmFile(Module &M) override;
71  void EmitJumpTableInfo() override;
72  void EmitConstantPool() override;
73  void EmitFunctionBodyStart() override;
74  void EmitFunctionBodyEnd() override;
75  void EmitInstruction(const MachineInstr *MI) override;
76  const MCExpr *lowerConstant(const Constant *CV) override;
77  bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
78  unsigned AsmVariant, const char *ExtraCode,
79  raw_ostream &OS) override;
80  bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
81  unsigned AsmVariant, const char *ExtraCode,
82  raw_ostream &OS) override;
83 
84  MVT getRegType(unsigned RegNo) const;
85  std::string regToString(const MachineOperand &MO);
86  WebAssemblyTargetStreamer *getTargetStreamer();
87 };
88 
89 } // end anonymous namespace
90 
91 //===----------------------------------------------------------------------===//
92 // Helpers.
93 //===----------------------------------------------------------------------===//
94 
95 MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {
96  const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
99  if (TRC->hasType(T))
100  return T;
101  DEBUG(errs() << "Unknown type for register number: " << RegNo);
102  llvm_unreachable("Unknown register type");
103  return MVT::Other;
104 }
105 
106 std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {
107  unsigned RegNo = MO.getReg();
109  "Unlowered physical register encountered during assembly printing");
110  assert(!MFI->isVRegStackified(RegNo));
111  unsigned WAReg = MFI->getWAReg(RegNo);
113  return '$' + utostr(WAReg);
114 }
115 
116 WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {
117  MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
118  return static_cast<WebAssemblyTargetStreamer *>(TS);
119 }
120 
121 //===----------------------------------------------------------------------===//
122 // WebAssemblyAsmPrinter Implementation.
123 //===----------------------------------------------------------------------===//
124 
125 void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
126  for (const auto &F : M) {
127  // Emit function type info for all undefined functions
128  if (F.isDeclarationForLinker() && !F.isIntrinsic()) {
130  SmallVector<MVT, 4> Params;
131  ComputeSignatureVTs(F, TM, Params, Results);
132  getTargetStreamer()->emitIndirectFunctionType(F.getName(), Params,
133  Results);
134  }
135  }
136  for (const auto &G : M.globals()) {
137  if (!G.hasInitializer() && G.hasExternalLinkage()) {
138  getTargetStreamer()->emitGlobalImport(G.getGlobalIdentifier());
139  }
140  }
141 }
142 
143 void WebAssemblyAsmPrinter::EmitConstantPool() {
144  assert(MF->getConstantPool()->getConstants().empty() &&
145  "WebAssembly disables constant pools");
146 }
147 
148 void WebAssemblyAsmPrinter::EmitJumpTableInfo() {
149  // Nothing to do; jump tables are incorporated into the instruction stream.
150 }
151 
152 void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
153  if (!MFI->getParams().empty())
154  getTargetStreamer()->emitParam(MFI->getParams());
155 
156  SmallVector<MVT, 4> ResultVTs;
157  const Function &F(*MF->getFunction());
158 
159  // Emit the function index.
160  if (MDNode *Idx = F.getMetadata("wasm.index")) {
161  assert(Idx->getNumOperands() == 1);
162 
163  getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant(
164  cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
165  }
166 
167  ComputeLegalValueVTs(F, TM, F.getReturnType(), ResultVTs);
168 
169  // If the return type needs to be legalized it will get converted into
170  // passing a pointer.
171  if (ResultVTs.size() == 1)
172  getTargetStreamer()->emitResult(ResultVTs);
173 
174  // FIXME: When ExplicitLocals is enabled by default, we won't need
175  // to define the locals here (and MFI can go back to being pointer-to-const).
176  for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
177  unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
178  unsigned WAReg = MFI->getWAReg(VReg);
179  // Don't declare unused registers.
181  continue;
182  // Don't redeclare parameters.
183  if (WAReg < MFI->getParams().size())
184  continue;
185  // Don't declare stackified registers.
186  if (int(WAReg) < 0)
187  continue;
188  MFI->addLocal(getRegType(VReg));
189  }
190 
191  getTargetStreamer()->emitLocal(MFI->getLocals());
192 
194 }
195 
196 void WebAssemblyAsmPrinter::EmitFunctionBodyEnd() {
197  getTargetStreamer()->emitEndFunc();
198 }
199 
200 void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
201  DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
202 
203  switch (MI->getOpcode()) {
204  case WebAssembly::ARGUMENT_I32:
205  case WebAssembly::ARGUMENT_I64:
206  case WebAssembly::ARGUMENT_F32:
207  case WebAssembly::ARGUMENT_F64:
208  case WebAssembly::ARGUMENT_v16i8:
209  case WebAssembly::ARGUMENT_v8i16:
210  case WebAssembly::ARGUMENT_v4i32:
211  case WebAssembly::ARGUMENT_v4f32:
212  // These represent values which are live into the function entry, so there's
213  // no instruction to emit.
214  break;
215  case WebAssembly::FALLTHROUGH_RETURN_I32:
216  case WebAssembly::FALLTHROUGH_RETURN_I64:
217  case WebAssembly::FALLTHROUGH_RETURN_F32:
218  case WebAssembly::FALLTHROUGH_RETURN_F64:
219  case WebAssembly::FALLTHROUGH_RETURN_v16i8:
220  case WebAssembly::FALLTHROUGH_RETURN_v8i16:
221  case WebAssembly::FALLTHROUGH_RETURN_v4i32:
222  case WebAssembly::FALLTHROUGH_RETURN_v4f32: {
223  // These instructions represent the implicit return at the end of a
224  // function body. The operand is always a pop.
225  assert(MFI->isVRegStackified(MI->getOperand(0).getReg()));
226 
227  if (isVerbose()) {
228  OutStreamer->AddComment("fallthrough-return: $pop" +
229  utostr(MFI->getWARegStackId(
230  MFI->getWAReg(MI->getOperand(0).getReg()))));
231  OutStreamer->AddBlankLine();
232  }
233  break;
234  }
235  case WebAssembly::FALLTHROUGH_RETURN_VOID:
236  // This instruction represents the implicit return at the end of a
237  // function body with no return value.
238  if (isVerbose()) {
239  OutStreamer->AddComment("fallthrough-return");
240  OutStreamer->AddBlankLine();
241  }
242  break;
243  default: {
244  WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
245  MCInst TmpInst;
246  MCInstLowering.Lower(MI, TmpInst);
247  EmitToStreamer(*OutStreamer, TmpInst);
248  break;
249  }
250  }
251 }
252 
253 const MCExpr *WebAssemblyAsmPrinter::lowerConstant(const Constant *CV) {
254  if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV))
255  if (GV->getValueType()->isFunctionTy())
258  return AsmPrinter::lowerConstant(CV);
259 }
260 
261 bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
262  unsigned OpNo, unsigned AsmVariant,
263  const char *ExtraCode,
264  raw_ostream &OS) {
265  if (AsmVariant != 0)
266  report_fatal_error("There are no defined alternate asm variants");
267 
268  // First try the generic code, which knows about modifiers like 'c' and 'n'.
269  if (!AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS))
270  return false;
271 
272  if (!ExtraCode) {
273  const MachineOperand &MO = MI->getOperand(OpNo);
274  switch (MO.getType()) {
276  OS << MO.getImm();
277  return false;
279  OS << regToString(MO);
280  return false;
282  getSymbol(MO.getGlobal())->print(OS, MAI);
283  printOffset(MO.getOffset(), OS);
284  return false;
286  GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI);
287  printOffset(MO.getOffset(), OS);
288  return false;
290  MO.getMBB()->getSymbol()->print(OS, MAI);
291  return false;
292  default:
293  break;
294  }
295  }
296 
297  return true;
298 }
299 
300 bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
301  unsigned OpNo,
302  unsigned AsmVariant,
303  const char *ExtraCode,
304  raw_ostream &OS) {
305  if (AsmVariant != 0)
306  report_fatal_error("There are no defined alternate asm variants");
307 
308  if (!ExtraCode) {
309  // TODO: For now, we just hard-code 0 as the constant offset; teach
310  // SelectInlineAsmMemoryOperand how to do address mode matching.
311  OS << "0(" + regToString(MI->getOperand(OpNo)) + ')';
312  return false;
313  }
314 
315  return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant, ExtraCode, OS);
316 }
317 
318 // Force static initialization.
322 }
bool hasType(MVT vt) const
Return true if this TargetRegisterClass has the ValueType vt.
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
const GlobalValue * getGlobal() const
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:298
This class is used to lower an MachineInstr into an MCInst.
void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition: MCSymbol.cpp:53
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
MachineBasicBlock * getMBB() const
static unsigned index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:52
This class prints an WebAssembly MCInst to wasm file syntax.
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:73
This file declares the class to lower WebAssembly MachineInstrs to their corresponding MCInst records...
Function Alias Analysis Results
MachineBasicBlock reference.
const char * getSymbolName() const
Metadata node.
Definition: Metadata.h:830
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
void ComputeLegalValueVTs(const Function &F, const TargetMachine &TM, Type *Ty, SmallVectorImpl< MVT > &ValueVTs)
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:34
Name of external global symbol.
#define F(x, y, z)
Definition: MD5.cpp:51
bool runOnMachineFunction(MachineFunction &MF) override
Emit the specified function out to the OutStreamer.
Definition: AsmPrinter.h:244
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...
static std::string utostr(uint64_t X, bool isNeg=false)
Definition: StringExtras.h:79
int64_t getImm() const
Expected< const typename ELFT::Sym * > getSymbol(typename ELFT::SymRange Symbols, uint32_t Index)
Definition: Object/ELF.h:236
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:150
WebAssembly-specific streamer interface, to implement support WebAssembly-specific assembly directive...
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:273
Address of a global value.
unsigned const MachineRegisterInfo * MRI
MVT - Machine Value Type.
void ComputeSignatureVTs(const Function &F, const TargetMachine &TM, SmallVectorImpl< MVT > &Params, SmallVectorImpl< MVT > &Results)
This is an important base class in LLVM.
Definition: Constant.h:42
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:279
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.
This class is intended to be used as a driving class for all asm writers.
Definition: AsmPrinter.h:67
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang","erlang-compatible garbage collector")
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
int64_t getOffset() const
Return the offset from the symbol in this operand.
MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This file declares WebAssembly-specific target streamer classes.
This file contains the WebAssembly implementation of the WebAssemblyRegisterInfo class.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
void LLVMInitializeWebAssemblyAsmPrinter()
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 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:843
const DataFlowGraph & G
Definition: RDFGraph.cpp:206
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
virtual void EmitFunctionBodyStart()
Targets can override this to emit stuff before the first basic block in the function.
Definition: AsmPrinter.h:338
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:52
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
LLVM_ATTRIBUTE_ALWAYS_INLINE size_type size() const
Definition: SmallVector.h:135
This file declares WebAssembly-specific per-machine-function information.
unsigned getReg() const
getReg - Returns the register number.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
RegisterAsmPrinter - Helper template for registering a target specific assembly printer, for use in the target machine initialization function.
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:44
static TraceState * TS
#define DEBUG(X)
Definition: Debug.h:100
Primary interface to the complete machine description for the target machine.
IRTranslator LLVM IR MI
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:47
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml","ocaml 3.10-compatible collector")
Target & getTheWebAssemblyTarget32()
Target & getTheWebAssemblyTarget64()