]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r301441, and update
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Target / WebAssembly / WebAssemblyAsmPrinter.cpp
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
17 #include "WebAssemblyAsmPrinter.h"
18 #include "InstPrinter/WebAssemblyInstPrinter.h"
19 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
20 #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
21 #include "WebAssembly.h"
22 #include "WebAssemblyMCInstLower.h"
23 #include "WebAssemblyMachineFunctionInfo.h"
24 #include "WebAssemblyRegisterInfo.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include "llvm/CodeGen/Analysis.h"
27 #include "llvm/CodeGen/AsmPrinter.h"
28 #include "llvm/CodeGen/MachineConstantPool.h"
29 #include "llvm/CodeGen/MachineInstr.h"
30 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
31 #include "llvm/IR/DataLayout.h"
32 #include "llvm/IR/GlobalVariable.h"
33 #include "llvm/MC/MCContext.h"
34 #include "llvm/MC/MCStreamer.h"
35 #include "llvm/MC/MCSymbol.h"
36 #include "llvm/Support/Debug.h"
37 #include "llvm/Support/TargetRegistry.h"
38 #include "llvm/Support/raw_ostream.h"
39 using namespace llvm;
40
41 #define DEBUG_TYPE "asm-printer"
42
43 //===----------------------------------------------------------------------===//
44 // Helpers.
45 //===----------------------------------------------------------------------===//
46
47 MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {
48   const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
49   const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
50   for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16,
51                 MVT::v4i32, MVT::v4f32})
52     if (TRI->isTypeLegalForClass(*TRC, T))
53       return T;
54   DEBUG(errs() << "Unknown type for register number: " << RegNo);
55   llvm_unreachable("Unknown register type");
56   return MVT::Other;
57 }
58
59 std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {
60   unsigned RegNo = MO.getReg();
61   assert(TargetRegisterInfo::isVirtualRegister(RegNo) &&
62          "Unlowered physical register encountered during assembly printing");
63   assert(!MFI->isVRegStackified(RegNo));
64   unsigned WAReg = MFI->getWAReg(RegNo);
65   assert(WAReg != WebAssemblyFunctionInfo::UnusedReg);
66   return '$' + utostr(WAReg);
67 }
68
69 WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {
70   MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
71   return static_cast<WebAssemblyTargetStreamer *>(TS);
72 }
73
74 //===----------------------------------------------------------------------===//
75 // WebAssemblyAsmPrinter Implementation.
76 //===----------------------------------------------------------------------===//
77
78 void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
79   for (const auto &F : M) {
80     // Emit function type info for all undefined functions
81     if (F.isDeclarationForLinker() && !F.isIntrinsic()) {
82       SmallVector<MVT, 4> Results;
83       SmallVector<MVT, 4> Params;
84       ComputeSignatureVTs(F, TM, Params, Results);
85       getTargetStreamer()->emitIndirectFunctionType(F.getName(), Params,
86                                                     Results);
87     }
88   }
89   for (const auto &G : M.globals()) {
90     if (!G.hasInitializer() && G.hasExternalLinkage()) {
91       uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
92       getTargetStreamer()->emitGlobalImport(G.getGlobalIdentifier());
93       OutStreamer->emitELFSize(getSymbol(&G),
94                                MCConstantExpr::create(Size, OutContext));
95     }
96   }
97
98   if (!TM.getTargetTriple().isOSBinFormatELF()) {
99     MachineModuleInfoWasm &MMIW = MMI->getObjFileInfo<MachineModuleInfoWasm>();
100     getTargetStreamer()->emitGlobal(MMIW.getGlobals());
101     if (MMIW.hasStackPointerGlobal())
102       getTargetStreamer()->emitStackPointer(MMIW.getStackPointerGlobal());
103   }
104 }
105
106 void WebAssemblyAsmPrinter::EmitConstantPool() {
107   assert(MF->getConstantPool()->getConstants().empty() &&
108          "WebAssembly disables constant pools");
109 }
110
111 void WebAssemblyAsmPrinter::EmitJumpTableInfo() {
112   // Nothing to do; jump tables are incorporated into the instruction stream.
113 }
114
115 void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
116   getTargetStreamer()->emitParam(CurrentFnSym, MFI->getParams());
117
118   SmallVector<MVT, 4> ResultVTs;
119   const Function &F(*MF->getFunction());
120
121   // Emit the function index.
122   if (MDNode *Idx = F.getMetadata("wasm.index")) {
123     assert(Idx->getNumOperands() == 1);
124
125     getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant(
126         cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
127   }
128
129   ComputeLegalValueVTs(F, TM, F.getReturnType(), ResultVTs);
130
131   // If the return type needs to be legalized it will get converted into
132   // passing a pointer.
133   if (ResultVTs.size() == 1)
134     getTargetStreamer()->emitResult(CurrentFnSym, ResultVTs);
135   else
136     getTargetStreamer()->emitResult(CurrentFnSym, ArrayRef<MVT>());
137
138   if (TM.getTargetTriple().isOSBinFormatELF()) {
139     assert(MFI->getLocals().empty());
140     for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
141       unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
142       unsigned WAReg = MFI->getWAReg(VReg);
143       // Don't declare unused registers.
144       if (WAReg == WebAssemblyFunctionInfo::UnusedReg)
145         continue;
146       // Don't redeclare parameters.
147       if (WAReg < MFI->getParams().size())
148         continue;
149       // Don't declare stackified registers.
150       if (int(WAReg) < 0)
151         continue;
152       MFI->addLocal(getRegType(VReg));
153     }
154   }
155
156   getTargetStreamer()->emitLocal(MFI->getLocals());
157
158   AsmPrinter::EmitFunctionBodyStart();
159 }
160
161 void WebAssemblyAsmPrinter::EmitFunctionBodyEnd() {
162   if (TM.getTargetTriple().isOSBinFormatELF())
163     getTargetStreamer()->emitEndFunc();
164 }
165
166 void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
167   DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
168
169   switch (MI->getOpcode()) {
170   case WebAssembly::ARGUMENT_I32:
171   case WebAssembly::ARGUMENT_I64:
172   case WebAssembly::ARGUMENT_F32:
173   case WebAssembly::ARGUMENT_F64:
174   case WebAssembly::ARGUMENT_v16i8:
175   case WebAssembly::ARGUMENT_v8i16:
176   case WebAssembly::ARGUMENT_v4i32:
177   case WebAssembly::ARGUMENT_v4f32:
178     // These represent values which are live into the function entry, so there's
179     // no instruction to emit.
180     break;
181   case WebAssembly::FALLTHROUGH_RETURN_I32:
182   case WebAssembly::FALLTHROUGH_RETURN_I64:
183   case WebAssembly::FALLTHROUGH_RETURN_F32:
184   case WebAssembly::FALLTHROUGH_RETURN_F64:
185   case WebAssembly::FALLTHROUGH_RETURN_v16i8:
186   case WebAssembly::FALLTHROUGH_RETURN_v8i16:
187   case WebAssembly::FALLTHROUGH_RETURN_v4i32:
188   case WebAssembly::FALLTHROUGH_RETURN_v4f32: {
189     // These instructions represent the implicit return at the end of a
190     // function body. The operand is always a pop.
191     assert(MFI->isVRegStackified(MI->getOperand(0).getReg()));
192
193     if (isVerbose()) {
194       OutStreamer->AddComment("fallthrough-return: $pop" +
195                               utostr(MFI->getWARegStackId(
196                                   MFI->getWAReg(MI->getOperand(0).getReg()))));
197       OutStreamer->AddBlankLine();
198     }
199     break;
200   }
201   case WebAssembly::FALLTHROUGH_RETURN_VOID:
202     // This instruction represents the implicit return at the end of a
203     // function body with no return value.
204     if (isVerbose()) {
205       OutStreamer->AddComment("fallthrough-return");
206       OutStreamer->AddBlankLine();
207     }
208     break;
209   default: {
210     WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
211     MCInst TmpInst;
212     MCInstLowering.Lower(MI, TmpInst);
213     EmitToStreamer(*OutStreamer, TmpInst);
214     break;
215   }
216   }
217 }
218
219 const MCExpr *WebAssemblyAsmPrinter::lowerConstant(const Constant *CV) {
220   if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV))
221     if (GV->getValueType()->isFunctionTy())
222       return MCSymbolRefExpr::create(
223           getSymbol(GV), MCSymbolRefExpr::VK_WebAssembly_FUNCTION, OutContext);
224   return AsmPrinter::lowerConstant(CV);
225 }
226
227 bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
228                                             unsigned OpNo, unsigned AsmVariant,
229                                             const char *ExtraCode,
230                                             raw_ostream &OS) {
231   if (AsmVariant != 0)
232     report_fatal_error("There are no defined alternate asm variants");
233
234   // First try the generic code, which knows about modifiers like 'c' and 'n'.
235   if (!AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS))
236     return false;
237
238   if (!ExtraCode) {
239     const MachineOperand &MO = MI->getOperand(OpNo);
240     switch (MO.getType()) {
241     case MachineOperand::MO_Immediate:
242       OS << MO.getImm();
243       return false;
244     case MachineOperand::MO_Register:
245       OS << regToString(MO);
246       return false;
247     case MachineOperand::MO_GlobalAddress:
248       getSymbol(MO.getGlobal())->print(OS, MAI);
249       printOffset(MO.getOffset(), OS);
250       return false;
251     case MachineOperand::MO_ExternalSymbol:
252       GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI);
253       printOffset(MO.getOffset(), OS);
254       return false;
255     case MachineOperand::MO_MachineBasicBlock:
256       MO.getMBB()->getSymbol()->print(OS, MAI);
257       return false;
258     default:
259       break;
260     }
261   }
262
263   return true;
264 }
265
266 bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
267                                                   unsigned OpNo,
268                                                   unsigned AsmVariant,
269                                                   const char *ExtraCode,
270                                                   raw_ostream &OS) {
271   if (AsmVariant != 0)
272     report_fatal_error("There are no defined alternate asm variants");
273
274   if (!ExtraCode) {
275     // TODO: For now, we just hard-code 0 as the constant offset; teach
276     // SelectInlineAsmMemoryOperand how to do address mode matching.
277     OS << "0(" + regToString(MI->getOperand(OpNo)) + ')';
278     return false;
279   }
280
281   return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant, ExtraCode, OS);
282 }
283
284 // Force static initialization.
285 extern "C" void LLVMInitializeWebAssemblyAsmPrinter() {
286   RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32());
287   RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64());
288 }