1292915Sdim//===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===//
2292915Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6292915Sdim//
7292915Sdim//===----------------------------------------------------------------------===//
8292915Sdim///
9292915Sdim/// \file
10341825Sdim/// This file contains a printer that converts from our internal
11292915Sdim/// representation of machine-dependent LLVM code to the WebAssembly assembly
12292915Sdim/// language.
13292915Sdim///
14292915Sdim//===----------------------------------------------------------------------===//
15292915Sdim
16321369Sdim#include "WebAssemblyAsmPrinter.h"
17353358Sdim#include "MCTargetDesc/WebAssemblyInstPrinter.h"
18292915Sdim#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19294024Sdim#include "MCTargetDesc/WebAssemblyTargetStreamer.h"
20353358Sdim#include "TargetInfo/WebAssemblyTargetInfo.h"
21314564Sdim#include "WebAssembly.h"
22292915Sdim#include "WebAssemblyMCInstLower.h"
23292915Sdim#include "WebAssemblyMachineFunctionInfo.h"
24292915Sdim#include "WebAssemblyRegisterInfo.h"
25353358Sdim#include "WebAssemblyTargetMachine.h"
26353358Sdim#include "llvm/ADT/SmallSet.h"
27292915Sdim#include "llvm/ADT/StringExtras.h"
28353358Sdim#include "llvm/BinaryFormat/Wasm.h"
29292915Sdim#include "llvm/CodeGen/Analysis.h"
30292915Sdim#include "llvm/CodeGen/AsmPrinter.h"
31292915Sdim#include "llvm/CodeGen/MachineConstantPool.h"
32292915Sdim#include "llvm/CodeGen/MachineInstr.h"
33321369Sdim#include "llvm/CodeGen/MachineModuleInfoImpls.h"
34292915Sdim#include "llvm/IR/DataLayout.h"
35353358Sdim#include "llvm/IR/DebugInfoMetadata.h"
36321369Sdim#include "llvm/IR/GlobalVariable.h"
37353358Sdim#include "llvm/IR/Metadata.h"
38292915Sdim#include "llvm/MC/MCContext.h"
39341825Sdim#include "llvm/MC/MCSectionWasm.h"
40292915Sdim#include "llvm/MC/MCStreamer.h"
41292915Sdim#include "llvm/MC/MCSymbol.h"
42321369Sdim#include "llvm/MC/MCSymbolWasm.h"
43292915Sdim#include "llvm/Support/Debug.h"
44292915Sdim#include "llvm/Support/TargetRegistry.h"
45292915Sdim#include "llvm/Support/raw_ostream.h"
46353358Sdim
47292915Sdimusing namespace llvm;
48292915Sdim
49292915Sdim#define DEBUG_TYPE "asm-printer"
50292915Sdim
51353358Sdimextern cl::opt<bool> WasmKeepRegisters;
52353358Sdim
53292915Sdim//===----------------------------------------------------------------------===//
54292915Sdim// Helpers.
55292915Sdim//===----------------------------------------------------------------------===//
56292915Sdim
57292915SdimMVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {
58321369Sdim  const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
59309124Sdim  const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
60314564Sdim  for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16,
61344779Sdim                MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64})
62321369Sdim    if (TRI->isTypeLegalForClass(*TRC, T))
63292915Sdim      return T;
64341825Sdim  LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo);
65292915Sdim  llvm_unreachable("Unknown register type");
66292915Sdim  return MVT::Other;
67292915Sdim}
68292915Sdim
69292915Sdimstd::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {
70360784Sdim  Register RegNo = MO.getReg();
71360784Sdim  assert(Register::isVirtualRegister(RegNo) &&
72292915Sdim         "Unlowered physical register encountered during assembly printing");
73292915Sdim  assert(!MFI->isVRegStackified(RegNo));
74292915Sdim  unsigned WAReg = MFI->getWAReg(RegNo);
75292915Sdim  assert(WAReg != WebAssemblyFunctionInfo::UnusedReg);
76292915Sdim  return '$' + utostr(WAReg);
77292915Sdim}
78292915Sdim
79309124SdimWebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {
80294024Sdim  MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
81294024Sdim  return static_cast<WebAssemblyTargetStreamer *>(TS);
82292915Sdim}
83292915Sdim
84292915Sdim//===----------------------------------------------------------------------===//
85292915Sdim// WebAssemblyAsmPrinter Implementation.
86292915Sdim//===----------------------------------------------------------------------===//
87292915Sdim
88309124Sdimvoid WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
89344779Sdim  for (auto &It : OutContext.getSymbols()) {
90344779Sdim    // Emit a .globaltype and .eventtype declaration.
91344779Sdim    auto Sym = cast<MCSymbolWasm>(It.getValue());
92344779Sdim    if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL)
93344779Sdim      getTargetStreamer()->emitGlobalType(Sym);
94344779Sdim    else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT)
95344779Sdim      getTargetStreamer()->emitEventType(Sym);
96344779Sdim  }
97344779Sdim
98309124Sdim  for (const auto &F : M) {
99360784Sdim    if (F.isIntrinsic())
100360784Sdim      continue;
101360784Sdim
102309124Sdim    // Emit function type info for all undefined functions
103360784Sdim    if (F.isDeclarationForLinker()) {
104314564Sdim      SmallVector<MVT, 4> Results;
105314564Sdim      SmallVector<MVT, 4> Params;
106353358Sdim      computeSignatureVTs(F.getFunctionType(), F, TM, Params, Results);
107344779Sdim      auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));
108344779Sdim      Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
109344779Sdim      if (!Sym->getSignature()) {
110353358Sdim        auto Signature = signatureFromMVTs(Results, Params);
111344779Sdim        Sym->setSignature(Signature.get());
112344779Sdim        addSignature(std::move(Signature));
113344779Sdim      }
114344779Sdim      // FIXME: this was originally intended for post-linking and was only used
115344779Sdim      // for imports that were only called indirectly (i.e. s2wasm could not
116344779Sdim      // infer the type from a call). With object files it applies to all
117344779Sdim      // imports. so fix the names and the tests, or rethink how import
118344779Sdim      // delcarations work in asm files.
119344779Sdim      getTargetStreamer()->emitFunctionType(Sym);
120341825Sdim
121341825Sdim      if (TM.getTargetTriple().isOSBinFormatWasm() &&
122341825Sdim          F.hasFnAttribute("wasm-import-module")) {
123344779Sdim        StringRef Name =
124344779Sdim            F.getFnAttribute("wasm-import-module").getValueAsString();
125344779Sdim        Sym->setImportModule(Name);
126344779Sdim        getTargetStreamer()->emitImportModule(Sym, Name);
127341825Sdim      }
128344779Sdim      if (TM.getTargetTriple().isOSBinFormatWasm() &&
129344779Sdim          F.hasFnAttribute("wasm-import-name")) {
130344779Sdim        StringRef Name =
131344779Sdim            F.getFnAttribute("wasm-import-name").getValueAsString();
132344779Sdim        Sym->setImportName(Name);
133344779Sdim        getTargetStreamer()->emitImportName(Sym, Name);
134344779Sdim      }
135309124Sdim    }
136360784Sdim
137360784Sdim    if (F.hasFnAttribute("wasm-export-name")) {
138360784Sdim      auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));
139360784Sdim      StringRef Name = F.getFnAttribute("wasm-export-name").getValueAsString();
140360784Sdim      Sym->setExportName(Name);
141360784Sdim      getTargetStreamer()->emitExportName(Sym, Name);
142360784Sdim    }
143309124Sdim  }
144344779Sdim
145314564Sdim  for (const auto &G : M.globals()) {
146314564Sdim    if (!G.hasInitializer() && G.hasExternalLinkage()) {
147327952Sdim      if (G.getValueType()->isSized()) {
148327952Sdim        uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
149327952Sdim        OutStreamer->emitELFSize(getSymbol(&G),
150327952Sdim                                 MCConstantExpr::create(Size, OutContext));
151327952Sdim      }
152314564Sdim    }
153314564Sdim  }
154341825Sdim
155341825Sdim  if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) {
156341825Sdim    for (const Metadata *MD : Named->operands()) {
157353358Sdim      const auto *Tuple = dyn_cast<MDTuple>(MD);
158341825Sdim      if (!Tuple || Tuple->getNumOperands() != 2)
159341825Sdim        continue;
160341825Sdim      const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0));
161341825Sdim      const MDString *Contents = dyn_cast<MDString>(Tuple->getOperand(1));
162341825Sdim      if (!Name || !Contents)
163341825Sdim        continue;
164341825Sdim
165341825Sdim      OutStreamer->PushSection();
166341825Sdim      std::string SectionName = (".custom_section." + Name->getString()).str();
167353358Sdim      MCSectionWasm *MySection =
168341825Sdim          OutContext.getWasmSection(SectionName, SectionKind::getMetadata());
169353358Sdim      OutStreamer->SwitchSection(MySection);
170341825Sdim      OutStreamer->EmitBytes(Contents->getString());
171341825Sdim      OutStreamer->PopSection();
172341825Sdim    }
173341825Sdim  }
174353358Sdim
175353358Sdim  EmitProducerInfo(M);
176353358Sdim  EmitTargetFeatures(M);
177309124Sdim}
178309124Sdim
179353358Sdimvoid WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
180353358Sdim  llvm::SmallVector<std::pair<std::string, std::string>, 4> Languages;
181353358Sdim  if (const NamedMDNode *Debug = M.getNamedMetadata("llvm.dbg.cu")) {
182353358Sdim    llvm::SmallSet<StringRef, 4> SeenLanguages;
183353358Sdim    for (size_t I = 0, E = Debug->getNumOperands(); I < E; ++I) {
184353358Sdim      const auto *CU = cast<DICompileUnit>(Debug->getOperand(I));
185353358Sdim      StringRef Language = dwarf::LanguageString(CU->getSourceLanguage());
186353358Sdim      Language.consume_front("DW_LANG_");
187353358Sdim      if (SeenLanguages.insert(Language).second)
188353358Sdim        Languages.emplace_back(Language.str(), "");
189353358Sdim    }
190353358Sdim  }
191353358Sdim
192353358Sdim  llvm::SmallVector<std::pair<std::string, std::string>, 4> Tools;
193353358Sdim  if (const NamedMDNode *Ident = M.getNamedMetadata("llvm.ident")) {
194353358Sdim    llvm::SmallSet<StringRef, 4> SeenTools;
195353358Sdim    for (size_t I = 0, E = Ident->getNumOperands(); I < E; ++I) {
196353358Sdim      const auto *S = cast<MDString>(Ident->getOperand(I)->getOperand(0));
197353358Sdim      std::pair<StringRef, StringRef> Field = S->getString().split("version");
198353358Sdim      StringRef Name = Field.first.trim();
199353358Sdim      StringRef Version = Field.second.trim();
200353358Sdim      if (SeenTools.insert(Name).second)
201353358Sdim        Tools.emplace_back(Name.str(), Version.str());
202353358Sdim    }
203353358Sdim  }
204353358Sdim
205353358Sdim  int FieldCount = int(!Languages.empty()) + int(!Tools.empty());
206353358Sdim  if (FieldCount != 0) {
207353358Sdim    MCSectionWasm *Producers = OutContext.getWasmSection(
208353358Sdim        ".custom_section.producers", SectionKind::getMetadata());
209353358Sdim    OutStreamer->PushSection();
210353358Sdim    OutStreamer->SwitchSection(Producers);
211353358Sdim    OutStreamer->EmitULEB128IntValue(FieldCount);
212353358Sdim    for (auto &Producers : {std::make_pair("language", &Languages),
213353358Sdim            std::make_pair("processed-by", &Tools)}) {
214353358Sdim      if (Producers.second->empty())
215353358Sdim        continue;
216353358Sdim      OutStreamer->EmitULEB128IntValue(strlen(Producers.first));
217353358Sdim      OutStreamer->EmitBytes(Producers.first);
218353358Sdim      OutStreamer->EmitULEB128IntValue(Producers.second->size());
219353358Sdim      for (auto &Producer : *Producers.second) {
220353358Sdim        OutStreamer->EmitULEB128IntValue(Producer.first.size());
221353358Sdim        OutStreamer->EmitBytes(Producer.first);
222353358Sdim        OutStreamer->EmitULEB128IntValue(Producer.second.size());
223353358Sdim        OutStreamer->EmitBytes(Producer.second);
224353358Sdim      }
225353358Sdim    }
226353358Sdim    OutStreamer->PopSection();
227353358Sdim  }
228353358Sdim}
229353358Sdim
230353358Sdimvoid WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) {
231353358Sdim  struct FeatureEntry {
232353358Sdim    uint8_t Prefix;
233353358Sdim    StringRef Name;
234353358Sdim  };
235353358Sdim
236353358Sdim  // Read target features and linkage policies from module metadata
237353358Sdim  SmallVector<FeatureEntry, 4> EmittedFeatures;
238353358Sdim  for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
239353358Sdim    std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str();
240353358Sdim    Metadata *Policy = M.getModuleFlag(MDKey);
241353358Sdim    if (Policy == nullptr)
242353358Sdim      continue;
243353358Sdim
244353358Sdim    FeatureEntry Entry;
245353358Sdim    Entry.Prefix = 0;
246353358Sdim    Entry.Name = KV.Key;
247353358Sdim
248353358Sdim    if (auto *MD = cast<ConstantAsMetadata>(Policy))
249353358Sdim      if (auto *I = cast<ConstantInt>(MD->getValue()))
250353358Sdim        Entry.Prefix = I->getZExtValue();
251353358Sdim
252353358Sdim    // Silently ignore invalid metadata
253353358Sdim    if (Entry.Prefix != wasm::WASM_FEATURE_PREFIX_USED &&
254353358Sdim        Entry.Prefix != wasm::WASM_FEATURE_PREFIX_REQUIRED &&
255353358Sdim        Entry.Prefix != wasm::WASM_FEATURE_PREFIX_DISALLOWED)
256353358Sdim      continue;
257353358Sdim
258353358Sdim    EmittedFeatures.push_back(Entry);
259353358Sdim  }
260353358Sdim
261353358Sdim  if (EmittedFeatures.size() == 0)
262353358Sdim    return;
263353358Sdim
264353358Sdim  // Emit features and linkage policies into the "target_features" section
265353358Sdim  MCSectionWasm *FeaturesSection = OutContext.getWasmSection(
266353358Sdim      ".custom_section.target_features", SectionKind::getMetadata());
267353358Sdim  OutStreamer->PushSection();
268353358Sdim  OutStreamer->SwitchSection(FeaturesSection);
269353358Sdim
270353358Sdim  OutStreamer->EmitULEB128IntValue(EmittedFeatures.size());
271353358Sdim  for (auto &F : EmittedFeatures) {
272353358Sdim    OutStreamer->EmitIntValue(F.Prefix, 1);
273353358Sdim    OutStreamer->EmitULEB128IntValue(F.Name.size());
274353358Sdim    OutStreamer->EmitBytes(F.Name);
275353358Sdim  }
276353358Sdim
277353358Sdim  OutStreamer->PopSection();
278353358Sdim}
279353358Sdim
280309124Sdimvoid WebAssemblyAsmPrinter::EmitConstantPool() {
281309124Sdim  assert(MF->getConstantPool()->getConstants().empty() &&
282309124Sdim         "WebAssembly disables constant pools");
283309124Sdim}
284309124Sdim
285309124Sdimvoid WebAssemblyAsmPrinter::EmitJumpTableInfo() {
286309124Sdim  // Nothing to do; jump tables are incorporated into the instruction stream.
287309124Sdim}
288309124Sdim
289292915Sdimvoid WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
290327952Sdim  const Function &F = MF->getFunction();
291344779Sdim  SmallVector<MVT, 1> ResultVTs;
292344779Sdim  SmallVector<MVT, 4> ParamVTs;
293353358Sdim  computeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs);
294353358Sdim  auto Signature = signatureFromMVTs(ResultVTs, ParamVTs);
295344779Sdim  auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym);
296344779Sdim  WasmSym->setSignature(Signature.get());
297344779Sdim  addSignature(std::move(Signature));
298344779Sdim  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
299314564Sdim
300344779Sdim  // FIXME: clean up how params and results are emitted (use signatures)
301344779Sdim  getTargetStreamer()->emitFunctionType(WasmSym);
302344779Sdim
303314564Sdim  // Emit the function index.
304314564Sdim  if (MDNode *Idx = F.getMetadata("wasm.index")) {
305314564Sdim    assert(Idx->getNumOperands() == 1);
306314564Sdim
307314564Sdim    getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant(
308314564Sdim        cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
309314564Sdim  }
310314564Sdim
311344779Sdim  SmallVector<wasm::ValType, 16> Locals;
312353358Sdim  valTypesFromMVTs(MFI->getLocals(), Locals);
313344779Sdim  getTargetStreamer()->emitLocal(Locals);
314294024Sdim
315292915Sdim  AsmPrinter::EmitFunctionBodyStart();
316292915Sdim}
317292915Sdim
318292915Sdimvoid WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
319341825Sdim  LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
320292915Sdim
321292915Sdim  switch (MI->getOpcode()) {
322344779Sdim  case WebAssembly::ARGUMENT_i32:
323344779Sdim  case WebAssembly::ARGUMENT_i32_S:
324344779Sdim  case WebAssembly::ARGUMENT_i64:
325344779Sdim  case WebAssembly::ARGUMENT_i64_S:
326344779Sdim  case WebAssembly::ARGUMENT_f32:
327344779Sdim  case WebAssembly::ARGUMENT_f32_S:
328344779Sdim  case WebAssembly::ARGUMENT_f64:
329344779Sdim  case WebAssembly::ARGUMENT_f64_S:
330314564Sdim  case WebAssembly::ARGUMENT_v16i8:
331344779Sdim  case WebAssembly::ARGUMENT_v16i8_S:
332314564Sdim  case WebAssembly::ARGUMENT_v8i16:
333344779Sdim  case WebAssembly::ARGUMENT_v8i16_S:
334314564Sdim  case WebAssembly::ARGUMENT_v4i32:
335344779Sdim  case WebAssembly::ARGUMENT_v4i32_S:
336344779Sdim  case WebAssembly::ARGUMENT_v2i64:
337344779Sdim  case WebAssembly::ARGUMENT_v2i64_S:
338314564Sdim  case WebAssembly::ARGUMENT_v4f32:
339344779Sdim  case WebAssembly::ARGUMENT_v4f32_S:
340344779Sdim  case WebAssembly::ARGUMENT_v2f64:
341344779Sdim  case WebAssembly::ARGUMENT_v2f64_S:
342292915Sdim    // These represent values which are live into the function entry, so there's
343292915Sdim    // no instruction to emit.
344292915Sdim    break;
345360784Sdim  case WebAssembly::FALLTHROUGH_RETURN: {
346309124Sdim    // These instructions represent the implicit return at the end of a
347360784Sdim    // function body.
348309124Sdim    if (isVerbose()) {
349360784Sdim      OutStreamer->AddComment("fallthrough-return");
350309124Sdim      OutStreamer->AddBlankLine();
351309124Sdim    }
352309124Sdim    break;
353309124Sdim  }
354353358Sdim  case WebAssembly::COMPILER_FENCE:
355353358Sdim    // This is a compiler barrier that prevents instruction reordering during
356353358Sdim    // backend compilation, and should not be emitted.
357353358Sdim    break;
358353358Sdim  case WebAssembly::EXTRACT_EXCEPTION_I32:
359353358Sdim  case WebAssembly::EXTRACT_EXCEPTION_I32_S:
360353358Sdim    // These are pseudo instructions that simulates popping values from stack.
361353358Sdim    // We print these only when we have -wasm-keep-registers on for assembly
362353358Sdim    // readability.
363353358Sdim    if (!WasmKeepRegisters)
364353358Sdim      break;
365353358Sdim    LLVM_FALLTHROUGH;
366292915Sdim  default: {
367292915Sdim    WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
368292915Sdim    MCInst TmpInst;
369353358Sdim    MCInstLowering.lower(MI, TmpInst);
370292915Sdim    EmitToStreamer(*OutStreamer, TmpInst);
371292915Sdim    break;
372292915Sdim  }
373292915Sdim  }
374292915Sdim}
375292915Sdim
376292915Sdimbool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
377353358Sdim                                            unsigned OpNo,
378292915Sdim                                            const char *ExtraCode,
379292915Sdim                                            raw_ostream &OS) {
380292915Sdim  // First try the generic code, which knows about modifiers like 'c' and 'n'.
381353358Sdim  if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
382292915Sdim    return false;
383292915Sdim
384292915Sdim  if (!ExtraCode) {
385292915Sdim    const MachineOperand &MO = MI->getOperand(OpNo);
386292915Sdim    switch (MO.getType()) {
387292915Sdim    case MachineOperand::MO_Immediate:
388292915Sdim      OS << MO.getImm();
389292915Sdim      return false;
390292915Sdim    case MachineOperand::MO_Register:
391344779Sdim      // FIXME: only opcode that still contains registers, as required by
392344779Sdim      // MachineInstr::getDebugVariable().
393344779Sdim      assert(MI->getOpcode() == WebAssembly::INLINEASM);
394292915Sdim      OS << regToString(MO);
395292915Sdim      return false;
396292915Sdim    case MachineOperand::MO_GlobalAddress:
397353358Sdim      PrintSymbolOperand(MO, OS);
398292915Sdim      return false;
399292915Sdim    case MachineOperand::MO_ExternalSymbol:
400292915Sdim      GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI);
401292915Sdim      printOffset(MO.getOffset(), OS);
402292915Sdim      return false;
403292915Sdim    case MachineOperand::MO_MachineBasicBlock:
404292915Sdim      MO.getMBB()->getSymbol()->print(OS, MAI);
405292915Sdim      return false;
406292915Sdim    default:
407292915Sdim      break;
408292915Sdim    }
409292915Sdim  }
410292915Sdim
411292915Sdim  return true;
412292915Sdim}
413292915Sdim
414292915Sdimbool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
415292915Sdim                                                  unsigned OpNo,
416292915Sdim                                                  const char *ExtraCode,
417292915Sdim                                                  raw_ostream &OS) {
418327952Sdim  // The current approach to inline asm is that "r" constraints are expressed
419327952Sdim  // as local indices, rather than values on the operand stack. This simplifies
420327952Sdim  // using "r" as it eliminates the need to push and pop the values in a
421327952Sdim  // particular order, however it also makes it impossible to have an "m"
422327952Sdim  // constraint. So we don't support it.
423292915Sdim
424353358Sdim  return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
425292915Sdim}
426292915Sdim
427292915Sdim// Force static initialization.
428360784Sdimextern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmPrinter() {
429314564Sdim  RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32());
430314564Sdim  RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64());
431292915Sdim}
432