1dd58ef01SDimitry Andric //===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===//
2dd58ef01SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6dd58ef01SDimitry Andric //
7dd58ef01SDimitry Andric //===----------------------------------------------------------------------===//
8dd58ef01SDimitry Andric ///
9dd58ef01SDimitry Andric /// \file
10eb11fae6SDimitry Andric /// This file contains a printer that converts from our internal
11dd58ef01SDimitry Andric /// representation of machine-dependent LLVM code to the WebAssembly assembly
12dd58ef01SDimitry Andric /// language.
13dd58ef01SDimitry Andric ///
14dd58ef01SDimitry Andric //===----------------------------------------------------------------------===//
15dd58ef01SDimitry Andric
1671d5a254SDimitry Andric #include "WebAssemblyAsmPrinter.h"
17dd58ef01SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
18050e163aSDimitry Andric #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
19e6d15924SDimitry Andric #include "TargetInfo/WebAssemblyTargetInfo.h"
20344a3780SDimitry Andric #include "Utils/WebAssemblyTypeUtilities.h"
21b915e9e0SDimitry Andric #include "WebAssembly.h"
22dd58ef01SDimitry Andric #include "WebAssemblyMCInstLower.h"
23dd58ef01SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
24dd58ef01SDimitry Andric #include "WebAssemblyRegisterInfo.h"
25344a3780SDimitry Andric #include "WebAssemblyRuntimeLibcallSignatures.h"
26e6d15924SDimitry Andric #include "WebAssemblyTargetMachine.h"
27b1c73532SDimitry Andric #include "WebAssemblyUtilities.h"
287fa27ce4SDimitry Andric #include "llvm/ADT/MapVector.h"
29e6d15924SDimitry Andric #include "llvm/ADT/SmallSet.h"
30dd58ef01SDimitry Andric #include "llvm/ADT/StringExtras.h"
317fa27ce4SDimitry Andric #include "llvm/Analysis/ValueTracking.h"
32e6d15924SDimitry Andric #include "llvm/BinaryFormat/Wasm.h"
33dd58ef01SDimitry Andric #include "llvm/CodeGen/Analysis.h"
34dd58ef01SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
35dd58ef01SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
36dd58ef01SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
3771d5a254SDimitry Andric #include "llvm/CodeGen/MachineModuleInfoImpls.h"
38dd58ef01SDimitry Andric #include "llvm/IR/DataLayout.h"
39e6d15924SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
4071d5a254SDimitry Andric #include "llvm/IR/GlobalVariable.h"
41e6d15924SDimitry Andric #include "llvm/IR/Metadata.h"
42ac9a064cSDimitry Andric #include "llvm/IR/Module.h"
43dd58ef01SDimitry Andric #include "llvm/MC/MCContext.h"
44eb11fae6SDimitry Andric #include "llvm/MC/MCSectionWasm.h"
45dd58ef01SDimitry Andric #include "llvm/MC/MCStreamer.h"
46dd58ef01SDimitry Andric #include "llvm/MC/MCSymbol.h"
477c7aba6eSDimitry Andric #include "llvm/MC/MCSymbolWasm.h"
48c0981da4SDimitry Andric #include "llvm/MC/TargetRegistry.h"
49dd58ef01SDimitry Andric #include "llvm/Support/Debug.h"
50dd58ef01SDimitry Andric #include "llvm/Support/raw_ostream.h"
51e6d15924SDimitry Andric
52dd58ef01SDimitry Andric using namespace llvm;
53dd58ef01SDimitry Andric
54dd58ef01SDimitry Andric #define DEBUG_TYPE "asm-printer"
55dd58ef01SDimitry Andric
56e6d15924SDimitry Andric extern cl::opt<bool> WasmKeepRegisters;
57e6d15924SDimitry Andric
58dd58ef01SDimitry Andric //===----------------------------------------------------------------------===//
59dd58ef01SDimitry Andric // Helpers.
60dd58ef01SDimitry Andric //===----------------------------------------------------------------------===//
61dd58ef01SDimitry Andric
getRegType(unsigned RegNo) const62dd58ef01SDimitry Andric MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {
6312f3ca4cSDimitry Andric const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
6401095a5dSDimitry Andric const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
65b915e9e0SDimitry Andric for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16,
66ac9a064cSDimitry Andric MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64, MVT::v8f16})
6712f3ca4cSDimitry Andric if (TRI->isTypeLegalForClass(*TRC, T))
68dd58ef01SDimitry Andric return T;
69eb11fae6SDimitry Andric LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo);
70dd58ef01SDimitry Andric llvm_unreachable("Unknown register type");
71dd58ef01SDimitry Andric return MVT::Other;
72dd58ef01SDimitry Andric }
73dd58ef01SDimitry Andric
regToString(const MachineOperand & MO)74dd58ef01SDimitry Andric std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {
751d5ae102SDimitry Andric Register RegNo = MO.getReg();
76e3b55780SDimitry Andric assert(RegNo.isVirtual() &&
77dd58ef01SDimitry Andric "Unlowered physical register encountered during assembly printing");
78dd58ef01SDimitry Andric assert(!MFI->isVRegStackified(RegNo));
79dd58ef01SDimitry Andric unsigned WAReg = MFI->getWAReg(RegNo);
80b1c73532SDimitry Andric assert(WAReg != WebAssembly::UnusedReg);
81dd58ef01SDimitry Andric return '$' + utostr(WAReg);
82dd58ef01SDimitry Andric }
83dd58ef01SDimitry Andric
getTargetStreamer()8401095a5dSDimitry Andric WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {
85050e163aSDimitry Andric MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
86050e163aSDimitry Andric return static_cast<WebAssemblyTargetStreamer *>(TS);
87dd58ef01SDimitry Andric }
88dd58ef01SDimitry Andric
89b60736ecSDimitry Andric // Emscripten exception handling helpers
90b60736ecSDimitry Andric //
91b60736ecSDimitry Andric // This converts invoke names generated by LowerEmscriptenEHSjLj to real names
92b60736ecSDimitry Andric // that are expected by JavaScript glue code. The invoke names generated by
93b60736ecSDimitry Andric // Emscripten JS glue code are based on their argument and return types; for
94b60736ecSDimitry Andric // example, for a function that takes an i32 and returns nothing, it is
95b60736ecSDimitry Andric // 'invoke_vi'. But the format of invoke generated by LowerEmscriptenEHSjLj pass
96b60736ecSDimitry Andric // contains a mangled string generated from their IR types, for example,
97b60736ecSDimitry Andric // "__invoke_void_%struct.mystruct*_int", because final wasm types are not
98b60736ecSDimitry Andric // available in the IR pass. So we convert those names to the form that
99b60736ecSDimitry Andric // Emscripten JS code expects.
100b60736ecSDimitry Andric //
101b60736ecSDimitry Andric // Refer to LowerEmscriptenEHSjLj pass for more details.
102b60736ecSDimitry Andric
103b60736ecSDimitry Andric // Returns true if the given function name is an invoke name generated by
104b60736ecSDimitry Andric // LowerEmscriptenEHSjLj pass.
isEmscriptenInvokeName(StringRef Name)105b60736ecSDimitry Andric static bool isEmscriptenInvokeName(StringRef Name) {
106b60736ecSDimitry Andric if (Name.front() == '"' && Name.back() == '"')
107b60736ecSDimitry Andric Name = Name.substr(1, Name.size() - 2);
108312c0ed1SDimitry Andric return Name.starts_with("__invoke_");
109b60736ecSDimitry Andric }
110b60736ecSDimitry Andric
111b60736ecSDimitry Andric // Returns a character that represents the given wasm value type in invoke
112b60736ecSDimitry Andric // signatures.
getInvokeSig(wasm::ValType VT)113b60736ecSDimitry Andric static char getInvokeSig(wasm::ValType VT) {
114b60736ecSDimitry Andric switch (VT) {
115b60736ecSDimitry Andric case wasm::ValType::I32:
116b60736ecSDimitry Andric return 'i';
117b60736ecSDimitry Andric case wasm::ValType::I64:
118b60736ecSDimitry Andric return 'j';
119b60736ecSDimitry Andric case wasm::ValType::F32:
120b60736ecSDimitry Andric return 'f';
121b60736ecSDimitry Andric case wasm::ValType::F64:
122b60736ecSDimitry Andric return 'd';
123b60736ecSDimitry Andric case wasm::ValType::V128:
124b60736ecSDimitry Andric return 'V';
125b60736ecSDimitry Andric case wasm::ValType::FUNCREF:
126b60736ecSDimitry Andric return 'F';
127b60736ecSDimitry Andric case wasm::ValType::EXTERNREF:
128b60736ecSDimitry Andric return 'X';
129ac9a064cSDimitry Andric case wasm::ValType::EXNREF:
130ac9a064cSDimitry Andric return 'E';
131ac9a064cSDimitry Andric default:
132b60736ecSDimitry Andric llvm_unreachable("Unhandled wasm::ValType enum");
133b60736ecSDimitry Andric }
134ac9a064cSDimitry Andric }
135b60736ecSDimitry Andric
136b60736ecSDimitry Andric // Given the wasm signature, generate the invoke name in the format JS glue code
137b60736ecSDimitry Andric // expects.
getEmscriptenInvokeSymbolName(wasm::WasmSignature * Sig)138b60736ecSDimitry Andric static std::string getEmscriptenInvokeSymbolName(wasm::WasmSignature *Sig) {
139b60736ecSDimitry Andric assert(Sig->Returns.size() <= 1);
140b60736ecSDimitry Andric std::string Ret = "invoke_";
141b60736ecSDimitry Andric if (!Sig->Returns.empty())
142b60736ecSDimitry Andric for (auto VT : Sig->Returns)
143b60736ecSDimitry Andric Ret += getInvokeSig(VT);
144b60736ecSDimitry Andric else
145b60736ecSDimitry Andric Ret += 'v';
146b60736ecSDimitry Andric // Invokes' first argument is a pointer to the original function, so skip it
147b60736ecSDimitry Andric for (unsigned I = 1, E = Sig->Params.size(); I < E; I++)
148b60736ecSDimitry Andric Ret += getInvokeSig(Sig->Params[I]);
149b60736ecSDimitry Andric return Ret;
150b60736ecSDimitry Andric }
151b60736ecSDimitry Andric
152dd58ef01SDimitry Andric //===----------------------------------------------------------------------===//
153dd58ef01SDimitry Andric // WebAssemblyAsmPrinter Implementation.
154dd58ef01SDimitry Andric //===----------------------------------------------------------------------===//
155dd58ef01SDimitry Andric
getMCSymbolForFunction(const Function * F,bool EnableEmEH,wasm::WasmSignature * Sig,bool & InvokeDetected)156b60736ecSDimitry Andric MCSymbolWasm *WebAssemblyAsmPrinter::getMCSymbolForFunction(
157b60736ecSDimitry Andric const Function *F, bool EnableEmEH, wasm::WasmSignature *Sig,
158b60736ecSDimitry Andric bool &InvokeDetected) {
159b60736ecSDimitry Andric MCSymbolWasm *WasmSym = nullptr;
160b60736ecSDimitry Andric if (EnableEmEH && isEmscriptenInvokeName(F->getName())) {
161b60736ecSDimitry Andric assert(Sig);
162b60736ecSDimitry Andric InvokeDetected = true;
163b60736ecSDimitry Andric if (Sig->Returns.size() > 1) {
164b60736ecSDimitry Andric std::string Msg =
165b60736ecSDimitry Andric "Emscripten EH/SjLj does not support multivalue returns: " +
166b60736ecSDimitry Andric std::string(F->getName()) + ": " +
167b60736ecSDimitry Andric WebAssembly::signatureToString(Sig);
168c0981da4SDimitry Andric report_fatal_error(Twine(Msg));
169b60736ecSDimitry Andric }
170b60736ecSDimitry Andric WasmSym = cast<MCSymbolWasm>(
171b60736ecSDimitry Andric GetExternalSymbolSymbol(getEmscriptenInvokeSymbolName(Sig)));
172b60736ecSDimitry Andric } else {
173b60736ecSDimitry Andric WasmSym = cast<MCSymbolWasm>(getSymbol(F));
174b60736ecSDimitry Andric }
175b60736ecSDimitry Andric return WasmSym;
176b60736ecSDimitry Andric }
177b60736ecSDimitry Andric
emitGlobalVariable(const GlobalVariable * GV)178344a3780SDimitry Andric void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
179344a3780SDimitry Andric if (!WebAssembly::isWasmVarAddressSpace(GV->getAddressSpace())) {
180344a3780SDimitry Andric AsmPrinter::emitGlobalVariable(GV);
181344a3780SDimitry Andric return;
182344a3780SDimitry Andric }
183344a3780SDimitry Andric
184344a3780SDimitry Andric assert(!GV->isThreadLocal());
185344a3780SDimitry Andric
186344a3780SDimitry Andric MCSymbolWasm *Sym = cast<MCSymbolWasm>(getSymbol(GV));
187344a3780SDimitry Andric
188344a3780SDimitry Andric if (!Sym->getType()) {
189ecbca9f5SDimitry Andric SmallVector<MVT, 1> VTs;
190ecbca9f5SDimitry Andric Type *GlobalVT = GV->getValueType();
191145449b1SDimitry Andric if (Subtarget) {
192145449b1SDimitry Andric // Subtarget is only set when a function is defined, because
193145449b1SDimitry Andric // each function can declare a different subtarget. For example,
194145449b1SDimitry Andric // on ARM a compilation unit might have a function on ARM and
195145449b1SDimitry Andric // another on Thumb. Therefore only if Subtarget is non-null we
196145449b1SDimitry Andric // can actually calculate the legal VTs.
197145449b1SDimitry Andric const WebAssemblyTargetLowering &TLI = *Subtarget->getTargetLowering();
198ecbca9f5SDimitry Andric computeLegalValueVTs(TLI, GV->getParent()->getContext(),
199ac9a064cSDimitry Andric GV->getDataLayout(), GlobalVT, VTs);
200145449b1SDimitry Andric }
201ecbca9f5SDimitry Andric WebAssembly::wasmSymbolSetType(Sym, GlobalVT, VTs);
202344a3780SDimitry Andric }
203344a3780SDimitry Andric
204344a3780SDimitry Andric emitVisibility(Sym, GV->getVisibility(), !GV->isDeclaration());
205145449b1SDimitry Andric emitSymbolType(Sym);
206344a3780SDimitry Andric if (GV->hasInitializer()) {
207344a3780SDimitry Andric assert(getSymbolPreferLocal(*GV) == Sym);
208344a3780SDimitry Andric emitLinkage(GV, Sym);
209344a3780SDimitry Andric OutStreamer->emitLabel(Sym);
210344a3780SDimitry Andric // TODO: Actually emit the initializer value. Otherwise the global has the
211344a3780SDimitry Andric // default value for its type (0, ref.null, etc).
212145449b1SDimitry Andric OutStreamer->addBlankLine();
213344a3780SDimitry Andric }
214344a3780SDimitry Andric }
215344a3780SDimitry Andric
getOrCreateWasmSymbol(StringRef Name)216344a3780SDimitry Andric MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) {
217344a3780SDimitry Andric auto *WasmSym = cast<MCSymbolWasm>(GetExternalSymbolSymbol(Name));
218344a3780SDimitry Andric
219344a3780SDimitry Andric // May be called multiple times, so early out.
220145449b1SDimitry Andric if (WasmSym->getType())
221344a3780SDimitry Andric return WasmSym;
222344a3780SDimitry Andric
223344a3780SDimitry Andric const WebAssemblySubtarget &Subtarget = getSubtarget();
224344a3780SDimitry Andric
225344a3780SDimitry Andric // Except for certain known symbols, all symbols used by CodeGen are
226344a3780SDimitry Andric // functions. It's OK to hardcode knowledge of specific symbols here; this
227344a3780SDimitry Andric // method is precisely there for fetching the signatures of known
228344a3780SDimitry Andric // Clang-provided symbols.
229344a3780SDimitry Andric if (Name == "__stack_pointer" || Name == "__tls_base" ||
230344a3780SDimitry Andric Name == "__memory_base" || Name == "__table_base" ||
231344a3780SDimitry Andric Name == "__tls_size" || Name == "__tls_align") {
232344a3780SDimitry Andric bool Mutable =
233344a3780SDimitry Andric Name == "__stack_pointer" || Name == "__tls_base";
234344a3780SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
235344a3780SDimitry Andric WasmSym->setGlobalType(wasm::WasmGlobalType{
236344a3780SDimitry Andric uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64
237344a3780SDimitry Andric : wasm::WASM_TYPE_I32),
238344a3780SDimitry Andric Mutable});
239344a3780SDimitry Andric return WasmSym;
240344a3780SDimitry Andric }
241344a3780SDimitry Andric
242312c0ed1SDimitry Andric if (Name.starts_with("GCC_except_table")) {
243c0981da4SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA);
244c0981da4SDimitry Andric return WasmSym;
245c0981da4SDimitry Andric }
246c0981da4SDimitry Andric
247344a3780SDimitry Andric SmallVector<wasm::ValType, 4> Returns;
248344a3780SDimitry Andric SmallVector<wasm::ValType, 4> Params;
249c0981da4SDimitry Andric if (Name == "__cpp_exception" || Name == "__c_longjmp") {
250344a3780SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
251c0981da4SDimitry Andric // In static linking we define tag symbols in WasmException::endModule().
252c0981da4SDimitry Andric // But we may have multiple objects to be linked together, each of which
253c0981da4SDimitry Andric // defines the tag symbols. To resolve them, we declare them as weak. In
254c0981da4SDimitry Andric // dynamic linking we make tag symbols undefined in the backend, define it
255c0981da4SDimitry Andric // in JS, and feed them to each importing module.
256c0981da4SDimitry Andric if (!isPositionIndependent())
257344a3780SDimitry Andric WasmSym->setWeak(true);
258344a3780SDimitry Andric WasmSym->setExternal(true);
259344a3780SDimitry Andric
260c0981da4SDimitry Andric // Currently both C++ exceptions and C longjmps have a single pointer type
261c0981da4SDimitry Andric // param. For C++ exceptions it is a pointer to an exception object, and for
262c0981da4SDimitry Andric // C longjmps it is pointer to a struct that contains a setjmp buffer and a
263c0981da4SDimitry Andric // longjmp return value. We may consider using multiple value parameters for
264c0981da4SDimitry Andric // longjmps later when multivalue support is ready.
265c0981da4SDimitry Andric wasm::ValType AddrType =
266c0981da4SDimitry Andric Subtarget.hasAddr64() ? wasm::ValType::I64 : wasm::ValType::I32;
267c0981da4SDimitry Andric Params.push_back(AddrType);
268344a3780SDimitry Andric } else { // Function symbols
269344a3780SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
270ac9a064cSDimitry Andric WebAssembly::getLibcallSignature(Subtarget, Name, Returns, Params);
271344a3780SDimitry Andric }
272ac9a064cSDimitry Andric auto Signature = OutContext.createWasmSignature();
273ac9a064cSDimitry Andric Signature->Returns = std::move(Returns);
274ac9a064cSDimitry Andric Signature->Params = std::move(Params);
275ac9a064cSDimitry Andric WasmSym->setSignature(Signature);
276344a3780SDimitry Andric
277344a3780SDimitry Andric return WasmSym;
278344a3780SDimitry Andric }
279344a3780SDimitry Andric
emitSymbolType(const MCSymbolWasm * Sym)280145449b1SDimitry Andric void WebAssemblyAsmPrinter::emitSymbolType(const MCSymbolWasm *Sym) {
281e3b55780SDimitry Andric std::optional<wasm::WasmSymbolType> WasmTy = Sym->getType();
282145449b1SDimitry Andric if (!WasmTy)
283145449b1SDimitry Andric return;
284145449b1SDimitry Andric
285145449b1SDimitry Andric switch (*WasmTy) {
286145449b1SDimitry Andric case wasm::WASM_SYMBOL_TYPE_GLOBAL:
287145449b1SDimitry Andric getTargetStreamer()->emitGlobalType(Sym);
288145449b1SDimitry Andric break;
289145449b1SDimitry Andric case wasm::WASM_SYMBOL_TYPE_TAG:
290145449b1SDimitry Andric getTargetStreamer()->emitTagType(Sym);
291145449b1SDimitry Andric break;
292145449b1SDimitry Andric case wasm::WASM_SYMBOL_TYPE_TABLE:
293145449b1SDimitry Andric getTargetStreamer()->emitTableType(Sym);
294145449b1SDimitry Andric break;
295145449b1SDimitry Andric default:
296145449b1SDimitry Andric break; // We only handle globals, tags and tables here
297145449b1SDimitry Andric }
298145449b1SDimitry Andric }
299145449b1SDimitry Andric
emitDecls(const Module & M)300145449b1SDimitry Andric void WebAssemblyAsmPrinter::emitDecls(const Module &M) {
301344a3780SDimitry Andric if (signaturesEmitted)
302344a3780SDimitry Andric return;
303344a3780SDimitry Andric signaturesEmitted = true;
304344a3780SDimitry Andric
305344a3780SDimitry Andric // Normally symbols for globals get discovered as the MI gets lowered,
306145449b1SDimitry Andric // but we need to know about them ahead of time. This will however,
307145449b1SDimitry Andric // only find symbols that have been used. Unused symbols from globals will
308145449b1SDimitry Andric // not be found here.
309344a3780SDimitry Andric MachineModuleInfoWasm &MMIW = MMI->getObjFileInfo<MachineModuleInfoWasm>();
3107fa27ce4SDimitry Andric for (StringRef Name : MMIW.MachineSymbolsUsed) {
3117fa27ce4SDimitry Andric auto *WasmSym = cast<MCSymbolWasm>(getOrCreateWasmSymbol(Name));
312145449b1SDimitry Andric if (WasmSym->isFunction()) {
313145449b1SDimitry Andric // TODO(wvo): is there any case where this overlaps with the call to
314145449b1SDimitry Andric // emitFunctionType in the loop below?
315145449b1SDimitry Andric getTargetStreamer()->emitFunctionType(WasmSym);
316145449b1SDimitry Andric }
317344a3780SDimitry Andric }
318344a3780SDimitry Andric
319344a3780SDimitry Andric for (auto &It : OutContext.getSymbols()) {
320145449b1SDimitry Andric // Emit .globaltype, .tagtype, or .tabletype declarations for extern
321145449b1SDimitry Andric // declarations, i.e. those that have only been declared (but not defined)
322145449b1SDimitry Andric // in the current module
323ac9a064cSDimitry Andric auto Sym = cast_or_null<MCSymbolWasm>(It.getValue().Symbol);
324ac9a064cSDimitry Andric if (Sym && !Sym->isDefined())
325145449b1SDimitry Andric emitSymbolType(Sym);
326d8e91e46SDimitry Andric }
327d8e91e46SDimitry Andric
328b60736ecSDimitry Andric DenseSet<MCSymbol *> InvokeSymbols;
32901095a5dSDimitry Andric for (const auto &F : M) {
330706b4fc4SDimitry Andric if (F.isIntrinsic())
331706b4fc4SDimitry Andric continue;
332706b4fc4SDimitry Andric
333145449b1SDimitry Andric // Emit function type info for all functions. This will emit duplicate
334145449b1SDimitry Andric // information for defined functions (which already have function type
335145449b1SDimitry Andric // info emitted alongside their definition), but this is necessary in
336145449b1SDimitry Andric // order to enable the single-pass WebAssemblyAsmTypeCheck to succeed.
337b915e9e0SDimitry Andric SmallVector<MVT, 4> Results;
338b915e9e0SDimitry Andric SmallVector<MVT, 4> Params;
339cfca06d7SDimitry Andric computeSignatureVTs(F.getFunctionType(), &F, F, TM, Params, Results);
340b60736ecSDimitry Andric // At this point these MCSymbols may or may not have been created already
341b60736ecSDimitry Andric // and thus also contain a signature, but we need to get the signature
342b60736ecSDimitry Andric // anyway here in case it is an invoke that has not yet been created. We
343b60736ecSDimitry Andric // will discard it later if it turns out not to be necessary.
344ac9a064cSDimitry Andric auto Signature = signatureFromMVTs(OutContext, Results, Params);
345b60736ecSDimitry Andric bool InvokeDetected = false;
34677fc4c14SDimitry Andric auto *Sym = getMCSymbolForFunction(
34777fc4c14SDimitry Andric &F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj,
348ac9a064cSDimitry Andric Signature, InvokeDetected);
349b60736ecSDimitry Andric
350b60736ecSDimitry Andric // Multiple functions can be mapped to the same invoke symbol. For
351b60736ecSDimitry Andric // example, two IR functions '__invoke_void_i8*' and '__invoke_void_i32'
352b60736ecSDimitry Andric // are both mapped to '__invoke_vi'. We keep them in a set once we emit an
353b60736ecSDimitry Andric // Emscripten EH symbol so we don't emit the same symbol twice.
354b60736ecSDimitry Andric if (InvokeDetected && !InvokeSymbols.insert(Sym).second)
355b60736ecSDimitry Andric continue;
356b60736ecSDimitry Andric
357d8e91e46SDimitry Andric Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
358d8e91e46SDimitry Andric if (!Sym->getSignature()) {
359ac9a064cSDimitry Andric Sym->setSignature(Signature);
360d8e91e46SDimitry Andric }
361b60736ecSDimitry Andric
362d8e91e46SDimitry Andric getTargetStreamer()->emitFunctionType(Sym);
363eb11fae6SDimitry Andric
364b60736ecSDimitry Andric if (F.hasFnAttribute("wasm-import-module")) {
365d8e91e46SDimitry Andric StringRef Name =
366d8e91e46SDimitry Andric F.getFnAttribute("wasm-import-module").getValueAsString();
367ac9a064cSDimitry Andric Sym->setImportModule(OutContext.allocateString(Name));
368d8e91e46SDimitry Andric getTargetStreamer()->emitImportModule(Sym, Name);
369eb11fae6SDimitry Andric }
370b60736ecSDimitry Andric if (F.hasFnAttribute("wasm-import-name")) {
371b60736ecSDimitry Andric // If this is a converted Emscripten EH/SjLj symbol, we shouldn't use
372b60736ecSDimitry Andric // the original function name but the converted symbol name.
373e6d15924SDimitry Andric StringRef Name =
374b60736ecSDimitry Andric InvokeDetected
375b60736ecSDimitry Andric ? Sym->getName()
376b60736ecSDimitry Andric : F.getFnAttribute("wasm-import-name").getValueAsString();
377ac9a064cSDimitry Andric Sym->setImportName(OutContext.allocateString(Name));
378e6d15924SDimitry Andric getTargetStreamer()->emitImportName(Sym, Name);
379e6d15924SDimitry Andric }
380706b4fc4SDimitry Andric
381706b4fc4SDimitry Andric if (F.hasFnAttribute("wasm-export-name")) {
382706b4fc4SDimitry Andric auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));
383706b4fc4SDimitry Andric StringRef Name = F.getFnAttribute("wasm-export-name").getValueAsString();
384ac9a064cSDimitry Andric Sym->setExportName(OutContext.allocateString(Name));
385706b4fc4SDimitry Andric getTargetStreamer()->emitExportName(Sym, Name);
386706b4fc4SDimitry Andric }
38701095a5dSDimitry Andric }
388344a3780SDimitry Andric }
389344a3780SDimitry Andric
emitEndOfAsmFile(Module & M)390344a3780SDimitry Andric void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
391145449b1SDimitry Andric // This is required to emit external declarations (like .functypes) when
392145449b1SDimitry Andric // no functions are defined in the compilation unit and therefore,
393145449b1SDimitry Andric // emitDecls() is not called until now.
394145449b1SDimitry Andric emitDecls(M);
395344a3780SDimitry Andric
396344a3780SDimitry Andric // When a function's address is taken, a TABLE_INDEX relocation is emitted
397344a3780SDimitry Andric // against the function symbol at the use site. However the relocation
398344a3780SDimitry Andric // doesn't explicitly refer to the table. In the future we may want to
399344a3780SDimitry Andric // define a new kind of reloc against both the function and the table, so
400344a3780SDimitry Andric // that the linker can see that the function symbol keeps the table alive,
401344a3780SDimitry Andric // but for now manually mark the table as live.
402344a3780SDimitry Andric for (const auto &F : M) {
403344a3780SDimitry Andric if (!F.isIntrinsic() && F.hasAddressTaken()) {
404344a3780SDimitry Andric MCSymbolWasm *FunctionTable =
405344a3780SDimitry Andric WebAssembly::getOrCreateFunctionTableSymbol(OutContext, Subtarget);
406344a3780SDimitry Andric OutStreamer->emitSymbolAttribute(FunctionTable, MCSA_NoDeadStrip);
407344a3780SDimitry Andric break;
408344a3780SDimitry Andric }
409344a3780SDimitry Andric }
410d8e91e46SDimitry Andric
411b915e9e0SDimitry Andric for (const auto &G : M.globals()) {
412344a3780SDimitry Andric if (!G.hasInitializer() && G.hasExternalLinkage() &&
413344a3780SDimitry Andric !WebAssembly::isWasmVarAddressSpace(G.getAddressSpace()) &&
414344a3780SDimitry Andric G.getValueType()->isSized()) {
41571d5a254SDimitry Andric uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
41671d5a254SDimitry Andric OutStreamer->emitELFSize(getSymbol(&G),
41771d5a254SDimitry Andric MCConstantExpr::create(Size, OutContext));
41801095a5dSDimitry Andric }
41901095a5dSDimitry Andric }
420eb11fae6SDimitry Andric
421eb11fae6SDimitry Andric if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) {
422eb11fae6SDimitry Andric for (const Metadata *MD : Named->operands()) {
423e6d15924SDimitry Andric const auto *Tuple = dyn_cast<MDTuple>(MD);
424eb11fae6SDimitry Andric if (!Tuple || Tuple->getNumOperands() != 2)
425eb11fae6SDimitry Andric continue;
426eb11fae6SDimitry Andric const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0));
427eb11fae6SDimitry Andric const MDString *Contents = dyn_cast<MDString>(Tuple->getOperand(1));
428eb11fae6SDimitry Andric if (!Name || !Contents)
429eb11fae6SDimitry Andric continue;
430eb11fae6SDimitry Andric
431145449b1SDimitry Andric OutStreamer->pushSection();
432eb11fae6SDimitry Andric std::string SectionName = (".custom_section." + Name->getString()).str();
433e6d15924SDimitry Andric MCSectionWasm *MySection =
434eb11fae6SDimitry Andric OutContext.getWasmSection(SectionName, SectionKind::getMetadata());
435145449b1SDimitry Andric OutStreamer->switchSection(MySection);
436cfca06d7SDimitry Andric OutStreamer->emitBytes(Contents->getString());
437145449b1SDimitry Andric OutStreamer->popSection();
438eb11fae6SDimitry Andric }
439eb11fae6SDimitry Andric }
440e6d15924SDimitry Andric
441e6d15924SDimitry Andric EmitProducerInfo(M);
442e6d15924SDimitry Andric EmitTargetFeatures(M);
4437fa27ce4SDimitry Andric EmitFunctionAttributes(M);
444e6d15924SDimitry Andric }
445e6d15924SDimitry Andric
EmitProducerInfo(Module & M)446e6d15924SDimitry Andric void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
447e6d15924SDimitry Andric llvm::SmallVector<std::pair<std::string, std::string>, 4> Languages;
448e6d15924SDimitry Andric if (const NamedMDNode *Debug = M.getNamedMetadata("llvm.dbg.cu")) {
449e6d15924SDimitry Andric llvm::SmallSet<StringRef, 4> SeenLanguages;
450e6d15924SDimitry Andric for (size_t I = 0, E = Debug->getNumOperands(); I < E; ++I) {
451e6d15924SDimitry Andric const auto *CU = cast<DICompileUnit>(Debug->getOperand(I));
452e6d15924SDimitry Andric StringRef Language = dwarf::LanguageString(CU->getSourceLanguage());
453e6d15924SDimitry Andric Language.consume_front("DW_LANG_");
454e6d15924SDimitry Andric if (SeenLanguages.insert(Language).second)
455e6d15924SDimitry Andric Languages.emplace_back(Language.str(), "");
456e6d15924SDimitry Andric }
457e6d15924SDimitry Andric }
458e6d15924SDimitry Andric
459e6d15924SDimitry Andric llvm::SmallVector<std::pair<std::string, std::string>, 4> Tools;
460e6d15924SDimitry Andric if (const NamedMDNode *Ident = M.getNamedMetadata("llvm.ident")) {
461e6d15924SDimitry Andric llvm::SmallSet<StringRef, 4> SeenTools;
462e6d15924SDimitry Andric for (size_t I = 0, E = Ident->getNumOperands(); I < E; ++I) {
463e6d15924SDimitry Andric const auto *S = cast<MDString>(Ident->getOperand(I)->getOperand(0));
464e6d15924SDimitry Andric std::pair<StringRef, StringRef> Field = S->getString().split("version");
465e6d15924SDimitry Andric StringRef Name = Field.first.trim();
466e6d15924SDimitry Andric StringRef Version = Field.second.trim();
467e6d15924SDimitry Andric if (SeenTools.insert(Name).second)
468e6d15924SDimitry Andric Tools.emplace_back(Name.str(), Version.str());
469e6d15924SDimitry Andric }
470e6d15924SDimitry Andric }
471e6d15924SDimitry Andric
472e6d15924SDimitry Andric int FieldCount = int(!Languages.empty()) + int(!Tools.empty());
473e6d15924SDimitry Andric if (FieldCount != 0) {
474e6d15924SDimitry Andric MCSectionWasm *Producers = OutContext.getWasmSection(
475e6d15924SDimitry Andric ".custom_section.producers", SectionKind::getMetadata());
476145449b1SDimitry Andric OutStreamer->pushSection();
477145449b1SDimitry Andric OutStreamer->switchSection(Producers);
478cfca06d7SDimitry Andric OutStreamer->emitULEB128IntValue(FieldCount);
479e6d15924SDimitry Andric for (auto &Producers : {std::make_pair("language", &Languages),
480e6d15924SDimitry Andric std::make_pair("processed-by", &Tools)}) {
481e6d15924SDimitry Andric if (Producers.second->empty())
482e6d15924SDimitry Andric continue;
483cfca06d7SDimitry Andric OutStreamer->emitULEB128IntValue(strlen(Producers.first));
484cfca06d7SDimitry Andric OutStreamer->emitBytes(Producers.first);
485cfca06d7SDimitry Andric OutStreamer->emitULEB128IntValue(Producers.second->size());
486e6d15924SDimitry Andric for (auto &Producer : *Producers.second) {
487cfca06d7SDimitry Andric OutStreamer->emitULEB128IntValue(Producer.first.size());
488cfca06d7SDimitry Andric OutStreamer->emitBytes(Producer.first);
489cfca06d7SDimitry Andric OutStreamer->emitULEB128IntValue(Producer.second.size());
490cfca06d7SDimitry Andric OutStreamer->emitBytes(Producer.second);
491e6d15924SDimitry Andric }
492e6d15924SDimitry Andric }
493145449b1SDimitry Andric OutStreamer->popSection();
494e6d15924SDimitry Andric }
495e6d15924SDimitry Andric }
496e6d15924SDimitry Andric
EmitTargetFeatures(Module & M)497e6d15924SDimitry Andric void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) {
498e6d15924SDimitry Andric struct FeatureEntry {
499e6d15924SDimitry Andric uint8_t Prefix;
500cfca06d7SDimitry Andric std::string Name;
501e6d15924SDimitry Andric };
502e6d15924SDimitry Andric
503e6d15924SDimitry Andric // Read target features and linkage policies from module metadata
504e6d15924SDimitry Andric SmallVector<FeatureEntry, 4> EmittedFeatures;
505cfca06d7SDimitry Andric auto EmitFeature = [&](std::string Feature) {
506cfca06d7SDimitry Andric std::string MDKey = (StringRef("wasm-feature-") + Feature).str();
507e6d15924SDimitry Andric Metadata *Policy = M.getModuleFlag(MDKey);
508e6d15924SDimitry Andric if (Policy == nullptr)
509cfca06d7SDimitry Andric return;
510e6d15924SDimitry Andric
511e6d15924SDimitry Andric FeatureEntry Entry;
512e6d15924SDimitry Andric Entry.Prefix = 0;
513cfca06d7SDimitry Andric Entry.Name = Feature;
514e6d15924SDimitry Andric
515e6d15924SDimitry Andric if (auto *MD = cast<ConstantAsMetadata>(Policy))
516e6d15924SDimitry Andric if (auto *I = cast<ConstantInt>(MD->getValue()))
517e6d15924SDimitry Andric Entry.Prefix = I->getZExtValue();
518e6d15924SDimitry Andric
519e6d15924SDimitry Andric // Silently ignore invalid metadata
520e6d15924SDimitry Andric if (Entry.Prefix != wasm::WASM_FEATURE_PREFIX_USED &&
521e6d15924SDimitry Andric Entry.Prefix != wasm::WASM_FEATURE_PREFIX_REQUIRED &&
522e6d15924SDimitry Andric Entry.Prefix != wasm::WASM_FEATURE_PREFIX_DISALLOWED)
523cfca06d7SDimitry Andric return;
524e6d15924SDimitry Andric
525e6d15924SDimitry Andric EmittedFeatures.push_back(Entry);
526cfca06d7SDimitry Andric };
527cfca06d7SDimitry Andric
528cfca06d7SDimitry Andric for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
529cfca06d7SDimitry Andric EmitFeature(KV.Key);
530e6d15924SDimitry Andric }
531cfca06d7SDimitry Andric // This pseudo-feature tells the linker whether shared memory would be safe
532cfca06d7SDimitry Andric EmitFeature("shared-mem");
533e6d15924SDimitry Andric
534c0981da4SDimitry Andric // This is an "architecture", not a "feature", but we emit it as such for
535c0981da4SDimitry Andric // the benefit of tools like Binaryen and consistency with other producers.
536c0981da4SDimitry Andric // FIXME: Subtarget is null here, so can't Subtarget->hasAddr64() ?
537c0981da4SDimitry Andric if (M.getDataLayout().getPointerSize() == 8) {
538c0981da4SDimitry Andric // Can't use EmitFeature since "wasm-feature-memory64" is not a module
539c0981da4SDimitry Andric // flag.
540c0981da4SDimitry Andric EmittedFeatures.push_back({wasm::WASM_FEATURE_PREFIX_USED, "memory64"});
541c0981da4SDimitry Andric }
542c0981da4SDimitry Andric
543e6d15924SDimitry Andric if (EmittedFeatures.size() == 0)
544e6d15924SDimitry Andric return;
545e6d15924SDimitry Andric
546e6d15924SDimitry Andric // Emit features and linkage policies into the "target_features" section
547e6d15924SDimitry Andric MCSectionWasm *FeaturesSection = OutContext.getWasmSection(
548e6d15924SDimitry Andric ".custom_section.target_features", SectionKind::getMetadata());
549145449b1SDimitry Andric OutStreamer->pushSection();
550145449b1SDimitry Andric OutStreamer->switchSection(FeaturesSection);
551e6d15924SDimitry Andric
552cfca06d7SDimitry Andric OutStreamer->emitULEB128IntValue(EmittedFeatures.size());
553e6d15924SDimitry Andric for (auto &F : EmittedFeatures) {
554cfca06d7SDimitry Andric OutStreamer->emitIntValue(F.Prefix, 1);
555cfca06d7SDimitry Andric OutStreamer->emitULEB128IntValue(F.Name.size());
556cfca06d7SDimitry Andric OutStreamer->emitBytes(F.Name);
557e6d15924SDimitry Andric }
558e6d15924SDimitry Andric
559145449b1SDimitry Andric OutStreamer->popSection();
560044eb2f6SDimitry Andric }
56101095a5dSDimitry Andric
EmitFunctionAttributes(Module & M)5627fa27ce4SDimitry Andric void WebAssemblyAsmPrinter::EmitFunctionAttributes(Module &M) {
5637fa27ce4SDimitry Andric auto V = M.getNamedGlobal("llvm.global.annotations");
5647fa27ce4SDimitry Andric if (!V)
5657fa27ce4SDimitry Andric return;
5667fa27ce4SDimitry Andric
5677fa27ce4SDimitry Andric // Group all the custom attributes by name.
5687fa27ce4SDimitry Andric MapVector<StringRef, SmallVector<MCSymbol *, 4>> CustomSections;
5697fa27ce4SDimitry Andric const ConstantArray *CA = cast<ConstantArray>(V->getOperand(0));
5707fa27ce4SDimitry Andric for (Value *Op : CA->operands()) {
5717fa27ce4SDimitry Andric auto *CS = cast<ConstantStruct>(Op);
5727fa27ce4SDimitry Andric // The first field is a pointer to the annotated variable.
5737fa27ce4SDimitry Andric Value *AnnotatedVar = CS->getOperand(0)->stripPointerCasts();
5747fa27ce4SDimitry Andric // Only annotated functions are supported for now.
5757fa27ce4SDimitry Andric if (!isa<Function>(AnnotatedVar))
5767fa27ce4SDimitry Andric continue;
5777fa27ce4SDimitry Andric auto *F = cast<Function>(AnnotatedVar);
5787fa27ce4SDimitry Andric
5797fa27ce4SDimitry Andric // The second field is a pointer to a global annotation string.
5807fa27ce4SDimitry Andric auto *GV = cast<GlobalVariable>(CS->getOperand(1)->stripPointerCasts());
5817fa27ce4SDimitry Andric StringRef AnnotationString;
5827fa27ce4SDimitry Andric getConstantStringInfo(GV, AnnotationString);
5837fa27ce4SDimitry Andric auto *Sym = cast<MCSymbolWasm>(getSymbol(F));
5847fa27ce4SDimitry Andric CustomSections[AnnotationString].push_back(Sym);
5857fa27ce4SDimitry Andric }
5867fa27ce4SDimitry Andric
5877fa27ce4SDimitry Andric // Emit a custom section for each unique attribute.
5887fa27ce4SDimitry Andric for (const auto &[Name, Symbols] : CustomSections) {
5897fa27ce4SDimitry Andric MCSectionWasm *CustomSection = OutContext.getWasmSection(
5907fa27ce4SDimitry Andric ".custom_section.llvm.func_attr.annotate." + Name, SectionKind::getMetadata());
5917fa27ce4SDimitry Andric OutStreamer->pushSection();
5927fa27ce4SDimitry Andric OutStreamer->switchSection(CustomSection);
5937fa27ce4SDimitry Andric
5947fa27ce4SDimitry Andric for (auto &Sym : Symbols) {
5957fa27ce4SDimitry Andric OutStreamer->emitValue(
5967fa27ce4SDimitry Andric MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_WASM_FUNCINDEX,
5977fa27ce4SDimitry Andric OutContext),
5987fa27ce4SDimitry Andric 4);
5997fa27ce4SDimitry Andric }
6007fa27ce4SDimitry Andric OutStreamer->popSection();
6017fa27ce4SDimitry Andric }
6027fa27ce4SDimitry Andric }
6037fa27ce4SDimitry Andric
emitConstantPool()604cfca06d7SDimitry Andric void WebAssemblyAsmPrinter::emitConstantPool() {
605145449b1SDimitry Andric emitDecls(*MMI->getModule());
60601095a5dSDimitry Andric assert(MF->getConstantPool()->getConstants().empty() &&
60701095a5dSDimitry Andric "WebAssembly disables constant pools");
60801095a5dSDimitry Andric }
60901095a5dSDimitry Andric
emitJumpTableInfo()610cfca06d7SDimitry Andric void WebAssemblyAsmPrinter::emitJumpTableInfo() {
61101095a5dSDimitry Andric // Nothing to do; jump tables are incorporated into the instruction stream.
61201095a5dSDimitry Andric }
61301095a5dSDimitry Andric
emitFunctionBodyStart()614cfca06d7SDimitry Andric void WebAssemblyAsmPrinter::emitFunctionBodyStart() {
615044eb2f6SDimitry Andric const Function &F = MF->getFunction();
616d8e91e46SDimitry Andric SmallVector<MVT, 1> ResultVTs;
617d8e91e46SDimitry Andric SmallVector<MVT, 4> ParamVTs;
618cfca06d7SDimitry Andric computeSignatureVTs(F.getFunctionType(), &F, F, TM, ParamVTs, ResultVTs);
619cfca06d7SDimitry Andric
620ac9a064cSDimitry Andric auto Signature = signatureFromMVTs(OutContext, ResultVTs, ParamVTs);
621d8e91e46SDimitry Andric auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym);
622ac9a064cSDimitry Andric WasmSym->setSignature(Signature);
623d8e91e46SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
624d8e91e46SDimitry Andric
625d8e91e46SDimitry Andric getTargetStreamer()->emitFunctionType(WasmSym);
626b915e9e0SDimitry Andric
627b915e9e0SDimitry Andric // Emit the function index.
628b915e9e0SDimitry Andric if (MDNode *Idx = F.getMetadata("wasm.index")) {
629b915e9e0SDimitry Andric assert(Idx->getNumOperands() == 1);
630b915e9e0SDimitry Andric
631b915e9e0SDimitry Andric getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant(
632b915e9e0SDimitry Andric cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
633b915e9e0SDimitry Andric }
634b915e9e0SDimitry Andric
635d8e91e46SDimitry Andric SmallVector<wasm::ValType, 16> Locals;
636e6d15924SDimitry Andric valTypesFromMVTs(MFI->getLocals(), Locals);
637d8e91e46SDimitry Andric getTargetStreamer()->emitLocal(Locals);
638dd58ef01SDimitry Andric
639cfca06d7SDimitry Andric AsmPrinter::emitFunctionBodyStart();
640dd58ef01SDimitry Andric }
641dd58ef01SDimitry Andric
emitInstruction(const MachineInstr * MI)642cfca06d7SDimitry Andric void WebAssemblyAsmPrinter::emitInstruction(const MachineInstr *MI) {
643eb11fae6SDimitry Andric LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
6441f917f69SDimitry Andric WebAssembly_MC::verifyInstructionPredicates(MI->getOpcode(),
6451f917f69SDimitry Andric Subtarget->getFeatureBits());
646dd58ef01SDimitry Andric
647dd58ef01SDimitry Andric switch (MI->getOpcode()) {
648d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_i32:
649d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_i32_S:
650d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_i64:
651d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_i64_S:
652d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_f32:
653d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_f32_S:
654d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_f64:
655d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_f64_S:
656b915e9e0SDimitry Andric case WebAssembly::ARGUMENT_v16i8:
657d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_v16i8_S:
658b915e9e0SDimitry Andric case WebAssembly::ARGUMENT_v8i16:
659d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_v8i16_S:
660b915e9e0SDimitry Andric case WebAssembly::ARGUMENT_v4i32:
661d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_v4i32_S:
662d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_v2i64:
663d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_v2i64_S:
664b915e9e0SDimitry Andric case WebAssembly::ARGUMENT_v4f32:
665d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_v4f32_S:
666d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_v2f64:
667d8e91e46SDimitry Andric case WebAssembly::ARGUMENT_v2f64_S:
668ac9a064cSDimitry Andric case WebAssembly::ARGUMENT_v8f16:
669ac9a064cSDimitry Andric case WebAssembly::ARGUMENT_v8f16_S:
670dd58ef01SDimitry Andric // These represent values which are live into the function entry, so there's
671dd58ef01SDimitry Andric // no instruction to emit.
672dd58ef01SDimitry Andric break;
6731d5ae102SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN: {
67401095a5dSDimitry Andric // These instructions represent the implicit return at the end of a
6751d5ae102SDimitry Andric // function body.
67601095a5dSDimitry Andric if (isVerbose()) {
6771d5ae102SDimitry Andric OutStreamer->AddComment("fallthrough-return");
678145449b1SDimitry Andric OutStreamer->addBlankLine();
67901095a5dSDimitry Andric }
68001095a5dSDimitry Andric break;
68101095a5dSDimitry Andric }
682e6d15924SDimitry Andric case WebAssembly::COMPILER_FENCE:
683e6d15924SDimitry Andric // This is a compiler barrier that prevents instruction reordering during
684e6d15924SDimitry Andric // backend compilation, and should not be emitted.
685e6d15924SDimitry Andric break;
686dd58ef01SDimitry Andric default: {
687dd58ef01SDimitry Andric WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
688dd58ef01SDimitry Andric MCInst TmpInst;
689e6d15924SDimitry Andric MCInstLowering.lower(MI, TmpInst);
690dd58ef01SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst);
691dd58ef01SDimitry Andric break;
692dd58ef01SDimitry Andric }
693dd58ef01SDimitry Andric }
694dd58ef01SDimitry Andric }
695dd58ef01SDimitry Andric
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)696dd58ef01SDimitry Andric bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
697e6d15924SDimitry Andric unsigned OpNo,
698dd58ef01SDimitry Andric const char *ExtraCode,
699dd58ef01SDimitry Andric raw_ostream &OS) {
700dd58ef01SDimitry Andric // First try the generic code, which knows about modifiers like 'c' and 'n'.
701e6d15924SDimitry Andric if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
702dd58ef01SDimitry Andric return false;
703dd58ef01SDimitry Andric
704dd58ef01SDimitry Andric if (!ExtraCode) {
705dd58ef01SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNo);
706dd58ef01SDimitry Andric switch (MO.getType()) {
707dd58ef01SDimitry Andric case MachineOperand::MO_Immediate:
708dd58ef01SDimitry Andric OS << MO.getImm();
709dd58ef01SDimitry Andric return false;
710dd58ef01SDimitry Andric case MachineOperand::MO_Register:
711d8e91e46SDimitry Andric // FIXME: only opcode that still contains registers, as required by
712d8e91e46SDimitry Andric // MachineInstr::getDebugVariable().
713d8e91e46SDimitry Andric assert(MI->getOpcode() == WebAssembly::INLINEASM);
714dd58ef01SDimitry Andric OS << regToString(MO);
715dd58ef01SDimitry Andric return false;
716dd58ef01SDimitry Andric case MachineOperand::MO_GlobalAddress:
717e6d15924SDimitry Andric PrintSymbolOperand(MO, OS);
718dd58ef01SDimitry Andric return false;
719dd58ef01SDimitry Andric case MachineOperand::MO_ExternalSymbol:
720dd58ef01SDimitry Andric GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI);
721dd58ef01SDimitry Andric printOffset(MO.getOffset(), OS);
722dd58ef01SDimitry Andric return false;
723dd58ef01SDimitry Andric case MachineOperand::MO_MachineBasicBlock:
724dd58ef01SDimitry Andric MO.getMBB()->getSymbol()->print(OS, MAI);
725dd58ef01SDimitry Andric return false;
726dd58ef01SDimitry Andric default:
727dd58ef01SDimitry Andric break;
728dd58ef01SDimitry Andric }
729dd58ef01SDimitry Andric }
730dd58ef01SDimitry Andric
731dd58ef01SDimitry Andric return true;
732dd58ef01SDimitry Andric }
733dd58ef01SDimitry Andric
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)734dd58ef01SDimitry Andric bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
735dd58ef01SDimitry Andric unsigned OpNo,
736dd58ef01SDimitry Andric const char *ExtraCode,
737dd58ef01SDimitry Andric raw_ostream &OS) {
738044eb2f6SDimitry Andric // The current approach to inline asm is that "r" constraints are expressed
739044eb2f6SDimitry Andric // as local indices, rather than values on the operand stack. This simplifies
740044eb2f6SDimitry Andric // using "r" as it eliminates the need to push and pop the values in a
741044eb2f6SDimitry Andric // particular order, however it also makes it impossible to have an "m"
742044eb2f6SDimitry Andric // constraint. So we don't support it.
743dd58ef01SDimitry Andric
744e6d15924SDimitry Andric return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
745dd58ef01SDimitry Andric }
746dd58ef01SDimitry Andric
747dd58ef01SDimitry Andric // Force static initialization.
LLVMInitializeWebAssemblyAsmPrinter()748706b4fc4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmPrinter() {
749b915e9e0SDimitry Andric RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32());
750b915e9e0SDimitry Andric RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64());
751dd58ef01SDimitry Andric }
752