10b57cec5SDimitry Andric //===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file contains a printer that converts from our internal 110b57cec5SDimitry Andric /// representation of machine-dependent LLVM code to the WebAssembly assembly 120b57cec5SDimitry Andric /// language. 130b57cec5SDimitry Andric /// 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "WebAssemblyAsmPrinter.h" 170b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyInstPrinter.h" 180b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 190b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyTargetStreamer.h" 200b57cec5SDimitry Andric #include "TargetInfo/WebAssemblyTargetInfo.h" 210b57cec5SDimitry Andric #include "WebAssembly.h" 220b57cec5SDimitry Andric #include "WebAssemblyMCInstLower.h" 230b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 240b57cec5SDimitry Andric #include "WebAssemblyRegisterInfo.h" 250b57cec5SDimitry Andric #include "WebAssemblyTargetMachine.h" 260b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h" 270b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 280b57cec5SDimitry Andric #include "llvm/BinaryFormat/Wasm.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/Analysis.h" 300b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h" 310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 330b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfoImpls.h" 340b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 350b57cec5SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 360b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 370b57cec5SDimitry Andric #include "llvm/IR/Metadata.h" 380b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 390b57cec5SDimitry Andric #include "llvm/MC/MCSectionWasm.h" 400b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 410b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 420b57cec5SDimitry Andric #include "llvm/MC/MCSymbolWasm.h" 430b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 440b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h" 450b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric using namespace llvm; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer" 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric extern cl::opt<bool> WasmKeepRegisters; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 540b57cec5SDimitry Andric // Helpers. 550b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const { 580b57cec5SDimitry Andric const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); 590b57cec5SDimitry Andric const TargetRegisterClass *TRC = MRI->getRegClass(RegNo); 600b57cec5SDimitry Andric for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16, 610b57cec5SDimitry Andric MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64}) 620b57cec5SDimitry Andric if (TRI->isTypeLegalForClass(*TRC, T)) 630b57cec5SDimitry Andric return T; 640b57cec5SDimitry Andric LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo); 650b57cec5SDimitry Andric llvm_unreachable("Unknown register type"); 660b57cec5SDimitry Andric return MVT::Other; 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) { 708bcb0991SDimitry Andric Register RegNo = MO.getReg(); 718bcb0991SDimitry Andric assert(Register::isVirtualRegister(RegNo) && 720b57cec5SDimitry Andric "Unlowered physical register encountered during assembly printing"); 730b57cec5SDimitry Andric assert(!MFI->isVRegStackified(RegNo)); 740b57cec5SDimitry Andric unsigned WAReg = MFI->getWAReg(RegNo); 750b57cec5SDimitry Andric assert(WAReg != WebAssemblyFunctionInfo::UnusedReg); 760b57cec5SDimitry Andric return '$' + utostr(WAReg); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() { 800b57cec5SDimitry Andric MCTargetStreamer *TS = OutStreamer->getTargetStreamer(); 810b57cec5SDimitry Andric return static_cast<WebAssemblyTargetStreamer *>(TS); 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 850b57cec5SDimitry Andric // WebAssemblyAsmPrinter Implementation. 860b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { 890b57cec5SDimitry Andric for (auto &It : OutContext.getSymbols()) { 900b57cec5SDimitry Andric // Emit a .globaltype and .eventtype declaration. 910b57cec5SDimitry Andric auto Sym = cast<MCSymbolWasm>(It.getValue()); 920b57cec5SDimitry Andric if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL) 930b57cec5SDimitry Andric getTargetStreamer()->emitGlobalType(Sym); 940b57cec5SDimitry Andric else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT) 950b57cec5SDimitry Andric getTargetStreamer()->emitEventType(Sym); 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric for (const auto &F : M) { 99*480093f4SDimitry Andric if (F.isIntrinsic()) 100*480093f4SDimitry Andric continue; 101*480093f4SDimitry Andric 1020b57cec5SDimitry Andric // Emit function type info for all undefined functions 103*480093f4SDimitry Andric if (F.isDeclarationForLinker()) { 1040b57cec5SDimitry Andric SmallVector<MVT, 4> Results; 1050b57cec5SDimitry Andric SmallVector<MVT, 4> Params; 1060b57cec5SDimitry Andric computeSignatureVTs(F.getFunctionType(), F, TM, Params, Results); 1070b57cec5SDimitry Andric auto *Sym = cast<MCSymbolWasm>(getSymbol(&F)); 1080b57cec5SDimitry Andric Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 1090b57cec5SDimitry Andric if (!Sym->getSignature()) { 1100b57cec5SDimitry Andric auto Signature = signatureFromMVTs(Results, Params); 1110b57cec5SDimitry Andric Sym->setSignature(Signature.get()); 1120b57cec5SDimitry Andric addSignature(std::move(Signature)); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric // FIXME: this was originally intended for post-linking and was only used 1150b57cec5SDimitry Andric // for imports that were only called indirectly (i.e. s2wasm could not 1160b57cec5SDimitry Andric // infer the type from a call). With object files it applies to all 1170b57cec5SDimitry Andric // imports. so fix the names and the tests, or rethink how import 1180b57cec5SDimitry Andric // delcarations work in asm files. 1190b57cec5SDimitry Andric getTargetStreamer()->emitFunctionType(Sym); 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric if (TM.getTargetTriple().isOSBinFormatWasm() && 1220b57cec5SDimitry Andric F.hasFnAttribute("wasm-import-module")) { 1230b57cec5SDimitry Andric StringRef Name = 1240b57cec5SDimitry Andric F.getFnAttribute("wasm-import-module").getValueAsString(); 1250b57cec5SDimitry Andric Sym->setImportModule(Name); 1260b57cec5SDimitry Andric getTargetStreamer()->emitImportModule(Sym, Name); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric if (TM.getTargetTriple().isOSBinFormatWasm() && 1290b57cec5SDimitry Andric F.hasFnAttribute("wasm-import-name")) { 1300b57cec5SDimitry Andric StringRef Name = 1310b57cec5SDimitry Andric F.getFnAttribute("wasm-import-name").getValueAsString(); 1320b57cec5SDimitry Andric Sym->setImportName(Name); 1330b57cec5SDimitry Andric getTargetStreamer()->emitImportName(Sym, Name); 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric } 136*480093f4SDimitry Andric 137*480093f4SDimitry Andric if (F.hasFnAttribute("wasm-export-name")) { 138*480093f4SDimitry Andric auto *Sym = cast<MCSymbolWasm>(getSymbol(&F)); 139*480093f4SDimitry Andric StringRef Name = F.getFnAttribute("wasm-export-name").getValueAsString(); 140*480093f4SDimitry Andric Sym->setExportName(Name); 141*480093f4SDimitry Andric getTargetStreamer()->emitExportName(Sym, Name); 142*480093f4SDimitry Andric } 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric for (const auto &G : M.globals()) { 1460b57cec5SDimitry Andric if (!G.hasInitializer() && G.hasExternalLinkage()) { 1470b57cec5SDimitry Andric if (G.getValueType()->isSized()) { 1480b57cec5SDimitry Andric uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType()); 1490b57cec5SDimitry Andric OutStreamer->emitELFSize(getSymbol(&G), 1500b57cec5SDimitry Andric MCConstantExpr::create(Size, OutContext)); 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) { 1560b57cec5SDimitry Andric for (const Metadata *MD : Named->operands()) { 1570b57cec5SDimitry Andric const auto *Tuple = dyn_cast<MDTuple>(MD); 1580b57cec5SDimitry Andric if (!Tuple || Tuple->getNumOperands() != 2) 1590b57cec5SDimitry Andric continue; 1600b57cec5SDimitry Andric const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0)); 1610b57cec5SDimitry Andric const MDString *Contents = dyn_cast<MDString>(Tuple->getOperand(1)); 1620b57cec5SDimitry Andric if (!Name || !Contents) 1630b57cec5SDimitry Andric continue; 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric OutStreamer->PushSection(); 1660b57cec5SDimitry Andric std::string SectionName = (".custom_section." + Name->getString()).str(); 1670b57cec5SDimitry Andric MCSectionWasm *MySection = 1680b57cec5SDimitry Andric OutContext.getWasmSection(SectionName, SectionKind::getMetadata()); 1690b57cec5SDimitry Andric OutStreamer->SwitchSection(MySection); 1700b57cec5SDimitry Andric OutStreamer->EmitBytes(Contents->getString()); 1710b57cec5SDimitry Andric OutStreamer->PopSection(); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric EmitProducerInfo(M); 1760b57cec5SDimitry Andric EmitTargetFeatures(M); 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) { 1800b57cec5SDimitry Andric llvm::SmallVector<std::pair<std::string, std::string>, 4> Languages; 1810b57cec5SDimitry Andric if (const NamedMDNode *Debug = M.getNamedMetadata("llvm.dbg.cu")) { 1820b57cec5SDimitry Andric llvm::SmallSet<StringRef, 4> SeenLanguages; 1830b57cec5SDimitry Andric for (size_t I = 0, E = Debug->getNumOperands(); I < E; ++I) { 1840b57cec5SDimitry Andric const auto *CU = cast<DICompileUnit>(Debug->getOperand(I)); 1850b57cec5SDimitry Andric StringRef Language = dwarf::LanguageString(CU->getSourceLanguage()); 1860b57cec5SDimitry Andric Language.consume_front("DW_LANG_"); 1870b57cec5SDimitry Andric if (SeenLanguages.insert(Language).second) 1880b57cec5SDimitry Andric Languages.emplace_back(Language.str(), ""); 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric llvm::SmallVector<std::pair<std::string, std::string>, 4> Tools; 1930b57cec5SDimitry Andric if (const NamedMDNode *Ident = M.getNamedMetadata("llvm.ident")) { 1940b57cec5SDimitry Andric llvm::SmallSet<StringRef, 4> SeenTools; 1950b57cec5SDimitry Andric for (size_t I = 0, E = Ident->getNumOperands(); I < E; ++I) { 1960b57cec5SDimitry Andric const auto *S = cast<MDString>(Ident->getOperand(I)->getOperand(0)); 1970b57cec5SDimitry Andric std::pair<StringRef, StringRef> Field = S->getString().split("version"); 1980b57cec5SDimitry Andric StringRef Name = Field.first.trim(); 1990b57cec5SDimitry Andric StringRef Version = Field.second.trim(); 2000b57cec5SDimitry Andric if (SeenTools.insert(Name).second) 2010b57cec5SDimitry Andric Tools.emplace_back(Name.str(), Version.str()); 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric int FieldCount = int(!Languages.empty()) + int(!Tools.empty()); 2060b57cec5SDimitry Andric if (FieldCount != 0) { 2070b57cec5SDimitry Andric MCSectionWasm *Producers = OutContext.getWasmSection( 2080b57cec5SDimitry Andric ".custom_section.producers", SectionKind::getMetadata()); 2090b57cec5SDimitry Andric OutStreamer->PushSection(); 2100b57cec5SDimitry Andric OutStreamer->SwitchSection(Producers); 2110b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(FieldCount); 2120b57cec5SDimitry Andric for (auto &Producers : {std::make_pair("language", &Languages), 2130b57cec5SDimitry Andric std::make_pair("processed-by", &Tools)}) { 2140b57cec5SDimitry Andric if (Producers.second->empty()) 2150b57cec5SDimitry Andric continue; 2160b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(strlen(Producers.first)); 2170b57cec5SDimitry Andric OutStreamer->EmitBytes(Producers.first); 2180b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(Producers.second->size()); 2190b57cec5SDimitry Andric for (auto &Producer : *Producers.second) { 2200b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(Producer.first.size()); 2210b57cec5SDimitry Andric OutStreamer->EmitBytes(Producer.first); 2220b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(Producer.second.size()); 2230b57cec5SDimitry Andric OutStreamer->EmitBytes(Producer.second); 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric OutStreamer->PopSection(); 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) { 2310b57cec5SDimitry Andric struct FeatureEntry { 2320b57cec5SDimitry Andric uint8_t Prefix; 2330b57cec5SDimitry Andric StringRef Name; 2340b57cec5SDimitry Andric }; 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric // Read target features and linkage policies from module metadata 2370b57cec5SDimitry Andric SmallVector<FeatureEntry, 4> EmittedFeatures; 2380b57cec5SDimitry Andric for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { 2390b57cec5SDimitry Andric std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str(); 2400b57cec5SDimitry Andric Metadata *Policy = M.getModuleFlag(MDKey); 2410b57cec5SDimitry Andric if (Policy == nullptr) 2420b57cec5SDimitry Andric continue; 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric FeatureEntry Entry; 2450b57cec5SDimitry Andric Entry.Prefix = 0; 2460b57cec5SDimitry Andric Entry.Name = KV.Key; 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric if (auto *MD = cast<ConstantAsMetadata>(Policy)) 2490b57cec5SDimitry Andric if (auto *I = cast<ConstantInt>(MD->getValue())) 2500b57cec5SDimitry Andric Entry.Prefix = I->getZExtValue(); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric // Silently ignore invalid metadata 2530b57cec5SDimitry Andric if (Entry.Prefix != wasm::WASM_FEATURE_PREFIX_USED && 2540b57cec5SDimitry Andric Entry.Prefix != wasm::WASM_FEATURE_PREFIX_REQUIRED && 2550b57cec5SDimitry Andric Entry.Prefix != wasm::WASM_FEATURE_PREFIX_DISALLOWED) 2560b57cec5SDimitry Andric continue; 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric EmittedFeatures.push_back(Entry); 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric if (EmittedFeatures.size() == 0) 2620b57cec5SDimitry Andric return; 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric // Emit features and linkage policies into the "target_features" section 2650b57cec5SDimitry Andric MCSectionWasm *FeaturesSection = OutContext.getWasmSection( 2660b57cec5SDimitry Andric ".custom_section.target_features", SectionKind::getMetadata()); 2670b57cec5SDimitry Andric OutStreamer->PushSection(); 2680b57cec5SDimitry Andric OutStreamer->SwitchSection(FeaturesSection); 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(EmittedFeatures.size()); 2710b57cec5SDimitry Andric for (auto &F : EmittedFeatures) { 2720b57cec5SDimitry Andric OutStreamer->EmitIntValue(F.Prefix, 1); 2730b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(F.Name.size()); 2740b57cec5SDimitry Andric OutStreamer->EmitBytes(F.Name); 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric OutStreamer->PopSection(); 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitConstantPool() { 2810b57cec5SDimitry Andric assert(MF->getConstantPool()->getConstants().empty() && 2820b57cec5SDimitry Andric "WebAssembly disables constant pools"); 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitJumpTableInfo() { 2860b57cec5SDimitry Andric // Nothing to do; jump tables are incorporated into the instruction stream. 2870b57cec5SDimitry Andric } 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { 2900b57cec5SDimitry Andric const Function &F = MF->getFunction(); 2910b57cec5SDimitry Andric SmallVector<MVT, 1> ResultVTs; 2920b57cec5SDimitry Andric SmallVector<MVT, 4> ParamVTs; 2930b57cec5SDimitry Andric computeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs); 2940b57cec5SDimitry Andric auto Signature = signatureFromMVTs(ResultVTs, ParamVTs); 2950b57cec5SDimitry Andric auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym); 2960b57cec5SDimitry Andric WasmSym->setSignature(Signature.get()); 2970b57cec5SDimitry Andric addSignature(std::move(Signature)); 2980b57cec5SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric // FIXME: clean up how params and results are emitted (use signatures) 3010b57cec5SDimitry Andric getTargetStreamer()->emitFunctionType(WasmSym); 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric // Emit the function index. 3040b57cec5SDimitry Andric if (MDNode *Idx = F.getMetadata("wasm.index")) { 3050b57cec5SDimitry Andric assert(Idx->getNumOperands() == 1); 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant( 3080b57cec5SDimitry Andric cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue())); 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric SmallVector<wasm::ValType, 16> Locals; 3120b57cec5SDimitry Andric valTypesFromMVTs(MFI->getLocals(), Locals); 3130b57cec5SDimitry Andric getTargetStreamer()->emitLocal(Locals); 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric AsmPrinter::EmitFunctionBodyStart(); 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { 3190b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n'); 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric switch (MI->getOpcode()) { 3220b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i32: 3230b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i32_S: 3240b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i64: 3250b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i64_S: 3260b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f32: 3270b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f32_S: 3280b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f64: 3290b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f64_S: 3300b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v16i8: 3310b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v16i8_S: 3320b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v8i16: 3330b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v8i16_S: 3340b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4i32: 3350b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4i32_S: 3360b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2i64: 3370b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2i64_S: 3380b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4f32: 3390b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4f32_S: 3400b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2f64: 3410b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2f64_S: 3420b57cec5SDimitry Andric // These represent values which are live into the function entry, so there's 3430b57cec5SDimitry Andric // no instruction to emit. 3440b57cec5SDimitry Andric break; 3458bcb0991SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN: { 3460b57cec5SDimitry Andric // These instructions represent the implicit return at the end of a 3478bcb0991SDimitry Andric // function body. 3480b57cec5SDimitry Andric if (isVerbose()) { 3498bcb0991SDimitry Andric OutStreamer->AddComment("fallthrough-return"); 3500b57cec5SDimitry Andric OutStreamer->AddBlankLine(); 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric break; 3530b57cec5SDimitry Andric } 3540b57cec5SDimitry Andric case WebAssembly::COMPILER_FENCE: 3550b57cec5SDimitry Andric // This is a compiler barrier that prevents instruction reordering during 3560b57cec5SDimitry Andric // backend compilation, and should not be emitted. 3570b57cec5SDimitry Andric break; 3580b57cec5SDimitry Andric case WebAssembly::EXTRACT_EXCEPTION_I32: 3590b57cec5SDimitry Andric case WebAssembly::EXTRACT_EXCEPTION_I32_S: 3600b57cec5SDimitry Andric // These are pseudo instructions that simulates popping values from stack. 3610b57cec5SDimitry Andric // We print these only when we have -wasm-keep-registers on for assembly 3620b57cec5SDimitry Andric // readability. 3630b57cec5SDimitry Andric if (!WasmKeepRegisters) 3640b57cec5SDimitry Andric break; 3650b57cec5SDimitry Andric LLVM_FALLTHROUGH; 3660b57cec5SDimitry Andric default: { 3670b57cec5SDimitry Andric WebAssemblyMCInstLower MCInstLowering(OutContext, *this); 3680b57cec5SDimitry Andric MCInst TmpInst; 3690b57cec5SDimitry Andric MCInstLowering.lower(MI, TmpInst); 3700b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst); 3710b57cec5SDimitry Andric break; 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric } 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI, 3770b57cec5SDimitry Andric unsigned OpNo, 3780b57cec5SDimitry Andric const char *ExtraCode, 3790b57cec5SDimitry Andric raw_ostream &OS) { 3800b57cec5SDimitry Andric // First try the generic code, which knows about modifiers like 'c' and 'n'. 3810b57cec5SDimitry Andric if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) 3820b57cec5SDimitry Andric return false; 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric if (!ExtraCode) { 3850b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNo); 3860b57cec5SDimitry Andric switch (MO.getType()) { 3870b57cec5SDimitry Andric case MachineOperand::MO_Immediate: 3880b57cec5SDimitry Andric OS << MO.getImm(); 3890b57cec5SDimitry Andric return false; 3900b57cec5SDimitry Andric case MachineOperand::MO_Register: 3910b57cec5SDimitry Andric // FIXME: only opcode that still contains registers, as required by 3920b57cec5SDimitry Andric // MachineInstr::getDebugVariable(). 3930b57cec5SDimitry Andric assert(MI->getOpcode() == WebAssembly::INLINEASM); 3940b57cec5SDimitry Andric OS << regToString(MO); 3950b57cec5SDimitry Andric return false; 3960b57cec5SDimitry Andric case MachineOperand::MO_GlobalAddress: 3970b57cec5SDimitry Andric PrintSymbolOperand(MO, OS); 3980b57cec5SDimitry Andric return false; 3990b57cec5SDimitry Andric case MachineOperand::MO_ExternalSymbol: 4000b57cec5SDimitry Andric GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI); 4010b57cec5SDimitry Andric printOffset(MO.getOffset(), OS); 4020b57cec5SDimitry Andric return false; 4030b57cec5SDimitry Andric case MachineOperand::MO_MachineBasicBlock: 4040b57cec5SDimitry Andric MO.getMBB()->getSymbol()->print(OS, MAI); 4050b57cec5SDimitry Andric return false; 4060b57cec5SDimitry Andric default: 4070b57cec5SDimitry Andric break; 4080b57cec5SDimitry Andric } 4090b57cec5SDimitry Andric } 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric return true; 4120b57cec5SDimitry Andric } 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 4150b57cec5SDimitry Andric unsigned OpNo, 4160b57cec5SDimitry Andric const char *ExtraCode, 4170b57cec5SDimitry Andric raw_ostream &OS) { 4180b57cec5SDimitry Andric // The current approach to inline asm is that "r" constraints are expressed 4190b57cec5SDimitry Andric // as local indices, rather than values on the operand stack. This simplifies 4200b57cec5SDimitry Andric // using "r" as it eliminates the need to push and pop the values in a 4210b57cec5SDimitry Andric // particular order, however it also makes it impossible to have an "m" 4220b57cec5SDimitry Andric // constraint. So we don't support it. 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); 4250b57cec5SDimitry Andric } 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric // Force static initialization. 428*480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmPrinter() { 4290b57cec5SDimitry Andric RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32()); 4300b57cec5SDimitry Andric RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64()); 4310b57cec5SDimitry Andric } 432