Line data Source code
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"
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/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"
39 : #include "llvm/Support/TargetRegistry.h"
40 : #include "llvm/Support/raw_ostream.h"
41 : using namespace llvm;
42 :
43 : #define DEBUG_TYPE "asm-printer"
44 :
45 : //===----------------------------------------------------------------------===//
46 : // Helpers.
47 : //===----------------------------------------------------------------------===//
48 :
49 0 : MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {
50 0 : const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
51 0 : const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
52 0 : for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16,
53 0 : MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64})
54 0 : if (TRI->isTypeLegalForClass(*TRC, T))
55 0 : return T;
56 : LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo);
57 0 : llvm_unreachable("Unknown register type");
58 : return MVT::Other;
59 : }
60 :
61 0 : std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {
62 0 : unsigned RegNo = MO.getReg();
63 : assert(TargetRegisterInfo::isVirtualRegister(RegNo) &&
64 : "Unlowered physical register encountered during assembly printing");
65 : assert(!MFI->isVRegStackified(RegNo));
66 0 : unsigned WAReg = MFI->getWAReg(RegNo);
67 : assert(WAReg != WebAssemblyFunctionInfo::UnusedReg);
68 0 : return '$' + utostr(WAReg);
69 : }
70 :
71 0 : WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {
72 : MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
73 0 : return static_cast<WebAssemblyTargetStreamer *>(TS);
74 : }
75 :
76 : //===----------------------------------------------------------------------===//
77 : // WebAssemblyAsmPrinter Implementation.
78 : //===----------------------------------------------------------------------===//
79 :
80 301 : void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
81 3906 : for (const auto &F : M) {
82 : // Emit function type info for all undefined functions
83 7210 : if (F.isDeclarationForLinker() && !F.isIntrinsic()) {
84 : SmallVector<MVT, 4> Results;
85 : SmallVector<MVT, 4> Params;
86 556 : ComputeSignatureVTs(F.getFunctionType(), F, TM, Params, Results);
87 278 : auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));
88 278 : if (!Sym->getSignature()) {
89 78 : auto Signature = SignatureFromMVTs(Results, Params);
90 : Sym->setSignature(Signature.get());
91 : addSignature(std::move(Signature));
92 : }
93 : // FIXME: this was originally intended for post-linking and was only used
94 : // for imports that were only called indirectly (i.e. s2wasm could not
95 : // infer the type from a call). With object files it applies to all
96 : // imports. so fix the names and the tests, or rethink how import
97 : // delcarations work in asm files.
98 278 : getTargetStreamer()->emitIndirectFunctionType(Sym);
99 :
100 556 : if (TM.getTargetTriple().isOSBinFormatWasm() &&
101 278 : F.hasFnAttribute("wasm-import-module")) {
102 : StringRef Name =
103 2 : F.getFnAttribute("wasm-import-module").getValueAsString();
104 2 : getTargetStreamer()->emitImportModule(Sym, Name);
105 : }
106 : }
107 : }
108 536 : for (const auto &G : M.globals()) {
109 235 : if (!G.hasInitializer() && G.hasExternalLinkage()) {
110 39 : if (G.getValueType()->isSized()) {
111 38 : uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
112 38 : OutStreamer->emitELFSize(getSymbol(&G),
113 38 : MCConstantExpr::create(Size, OutContext));
114 : }
115 : }
116 : }
117 :
118 301 : if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) {
119 14 : for (const Metadata *MD : Named->operands()) {
120 : const MDTuple *Tuple = dyn_cast<MDTuple>(MD);
121 10 : if (!Tuple || Tuple->getNumOperands() != 2)
122 0 : continue;
123 10 : const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0));
124 : const MDString *Contents = dyn_cast<MDString>(Tuple->getOperand(1));
125 10 : if (!Name || !Contents)
126 : continue;
127 :
128 10 : OutStreamer->PushSection();
129 10 : std::string SectionName = (".custom_section." + Name->getString()).str();
130 : MCSectionWasm *mySection =
131 10 : OutContext.getWasmSection(SectionName, SectionKind::getMetadata());
132 10 : OutStreamer->SwitchSection(mySection);
133 10 : OutStreamer->EmitBytes(Contents->getString());
134 10 : OutStreamer->PopSection();
135 : }
136 : }
137 301 : }
138 :
139 2982 : void WebAssemblyAsmPrinter::EmitConstantPool() {
140 : assert(MF->getConstantPool()->getConstants().empty() &&
141 : "WebAssembly disables constant pools");
142 2982 : }
143 :
144 2982 : void WebAssemblyAsmPrinter::EmitJumpTableInfo() {
145 : // Nothing to do; jump tables are incorporated into the instruction stream.
146 2982 : }
147 :
148 2982 : void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
149 2982 : const Function &F = MF->getFunction();
150 : SmallVector<MVT, 1> ResultVTs;
151 : SmallVector<MVT, 4> ParamVTs;
152 5964 : ComputeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs);
153 2982 : auto Signature = SignatureFromMVTs(ResultVTs, ParamVTs);
154 2982 : auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym);
155 : WasmSym->setSignature(Signature.get());
156 : addSignature(std::move(Signature));
157 :
158 : // FIXME: clean up how params and results are emitted (use signatures)
159 5964 : getTargetStreamer()->emitParam(CurrentFnSym, ParamVTs);
160 :
161 : // Emit the function index.
162 5964 : if (MDNode *Idx = F.getMetadata("wasm.index")) {
163 : assert(Idx->getNumOperands() == 1);
164 :
165 2 : getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant(
166 2 : cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
167 : }
168 :
169 5964 : getTargetStreamer()->emitResult(CurrentFnSym, ResultVTs);
170 5964 : getTargetStreamer()->emitLocal(MFI->getLocals());
171 :
172 : AsmPrinter::EmitFunctionBodyStart();
173 2982 : }
174 :
175 31626 : void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
176 : LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
177 :
178 63252 : switch (MI->getOpcode()) {
179 : case WebAssembly::ARGUMENT_i32:
180 : case WebAssembly::ARGUMENT_i32_S:
181 : case WebAssembly::ARGUMENT_i64:
182 : case WebAssembly::ARGUMENT_i64_S:
183 : case WebAssembly::ARGUMENT_f32:
184 : case WebAssembly::ARGUMENT_f32_S:
185 : case WebAssembly::ARGUMENT_f64:
186 : case WebAssembly::ARGUMENT_f64_S:
187 : case WebAssembly::ARGUMENT_v16i8:
188 : case WebAssembly::ARGUMENT_v16i8_S:
189 : case WebAssembly::ARGUMENT_v8i16:
190 : case WebAssembly::ARGUMENT_v8i16_S:
191 : case WebAssembly::ARGUMENT_v4i32:
192 : case WebAssembly::ARGUMENT_v4i32_S:
193 : case WebAssembly::ARGUMENT_v2i64:
194 : case WebAssembly::ARGUMENT_v2i64_S:
195 : case WebAssembly::ARGUMENT_v4f32:
196 : case WebAssembly::ARGUMENT_v4f32_S:
197 : case WebAssembly::ARGUMENT_v2f64:
198 : case WebAssembly::ARGUMENT_v2f64_S:
199 : // These represent values which are live into the function entry, so there's
200 : // no instruction to emit.
201 : break;
202 376 : case WebAssembly::FALLTHROUGH_RETURN_I32:
203 : case WebAssembly::FALLTHROUGH_RETURN_I32_S:
204 : case WebAssembly::FALLTHROUGH_RETURN_I64:
205 : case WebAssembly::FALLTHROUGH_RETURN_I64_S:
206 : case WebAssembly::FALLTHROUGH_RETURN_F32:
207 : case WebAssembly::FALLTHROUGH_RETURN_F32_S:
208 : case WebAssembly::FALLTHROUGH_RETURN_F64:
209 : case WebAssembly::FALLTHROUGH_RETURN_F64_S:
210 : case WebAssembly::FALLTHROUGH_RETURN_v16i8:
211 : case WebAssembly::FALLTHROUGH_RETURN_v16i8_S:
212 : case WebAssembly::FALLTHROUGH_RETURN_v8i16:
213 : case WebAssembly::FALLTHROUGH_RETURN_v8i16_S:
214 : case WebAssembly::FALLTHROUGH_RETURN_v4i32:
215 : case WebAssembly::FALLTHROUGH_RETURN_v4i32_S:
216 : case WebAssembly::FALLTHROUGH_RETURN_v2i64:
217 : case WebAssembly::FALLTHROUGH_RETURN_v2i64_S:
218 : case WebAssembly::FALLTHROUGH_RETURN_v4f32:
219 : case WebAssembly::FALLTHROUGH_RETURN_v4f32_S:
220 : case WebAssembly::FALLTHROUGH_RETURN_v2f64:
221 : case WebAssembly::FALLTHROUGH_RETURN_v2f64_S: {
222 : // These instructions represent the implicit return at the end of a
223 : // function body. Always pops one value off the stack.
224 376 : if (isVerbose()) {
225 172 : OutStreamer->AddComment("fallthrough-return-value");
226 86 : OutStreamer->AddBlankLine();
227 : }
228 : break;
229 : }
230 188 : case WebAssembly::FALLTHROUGH_RETURN_VOID:
231 : case WebAssembly::FALLTHROUGH_RETURN_VOID_S:
232 : // This instruction represents the implicit return at the end of a
233 : // function body with no return value.
234 188 : if (isVerbose()) {
235 8 : OutStreamer->AddComment("fallthrough-return-void");
236 4 : OutStreamer->AddBlankLine();
237 : }
238 : break;
239 24888 : default: {
240 24888 : WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
241 : MCInst TmpInst;
242 24888 : MCInstLowering.Lower(MI, TmpInst);
243 49776 : EmitToStreamer(*OutStreamer, TmpInst);
244 : break;
245 : }
246 : }
247 31626 : }
248 :
249 179 : const MCExpr *WebAssemblyAsmPrinter::lowerConstant(const Constant *CV) {
250 : if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV))
251 284 : if (GV->getValueType()->isFunctionTy()) {
252 78 : return MCSymbolRefExpr::create(
253 78 : getSymbol(GV), MCSymbolRefExpr::VK_WebAssembly_FUNCTION, OutContext);
254 : }
255 101 : return AsmPrinter::lowerConstant(CV);
256 : }
257 :
258 14 : bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
259 : unsigned OpNo, unsigned AsmVariant,
260 : const char *ExtraCode,
261 : raw_ostream &OS) {
262 14 : if (AsmVariant != 0)
263 0 : report_fatal_error("There are no defined alternate asm variants");
264 :
265 : // First try the generic code, which knows about modifiers like 'c' and 'n'.
266 14 : if (!AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS))
267 : return false;
268 :
269 14 : if (!ExtraCode) {
270 14 : const MachineOperand &MO = MI->getOperand(OpNo);
271 14 : switch (MO.getType()) {
272 12 : case MachineOperand::MO_Immediate:
273 12 : OS << MO.getImm();
274 12 : return false;
275 0 : case MachineOperand::MO_Register:
276 : // FIXME: only opcode that still contains registers, as required by
277 : // MachineInstr::getDebugVariable().
278 : assert(MI->getOpcode() == WebAssembly::INLINEASM);
279 0 : OS << regToString(MO);
280 0 : return false;
281 2 : case MachineOperand::MO_GlobalAddress:
282 2 : getSymbol(MO.getGlobal())->print(OS, MAI);
283 4 : printOffset(MO.getOffset(), OS);
284 2 : return false;
285 0 : case MachineOperand::MO_ExternalSymbol:
286 0 : GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI);
287 0 : printOffset(MO.getOffset(), OS);
288 0 : return false;
289 0 : case MachineOperand::MO_MachineBasicBlock:
290 0 : MO.getMBB()->getSymbol()->print(OS, MAI);
291 0 : return false;
292 : default:
293 : break;
294 : }
295 : }
296 :
297 : return true;
298 : }
299 :
300 0 : bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
301 : unsigned OpNo,
302 : unsigned AsmVariant,
303 : const char *ExtraCode,
304 : raw_ostream &OS) {
305 0 : if (AsmVariant != 0)
306 0 : report_fatal_error("There are no defined alternate asm variants");
307 :
308 : // The current approach to inline asm is that "r" constraints are expressed
309 : // as local indices, rather than values on the operand stack. This simplifies
310 : // using "r" as it eliminates the need to push and pop the values in a
311 : // particular order, however it also makes it impossible to have an "m"
312 : // constraint. So we don't support it.
313 :
314 0 : return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant, ExtraCode, OS);
315 : }
316 :
317 : // Force static initialization.
318 65841 : extern "C" void LLVMInitializeWebAssemblyAsmPrinter() {
319 65841 : RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32());
320 65841 : RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64());
321 65841 : }
|