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