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 88*5ffd83dbSDimitry 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) { 99480093f4SDimitry Andric if (F.isIntrinsic()) 100480093f4SDimitry Andric continue; 101480093f4SDimitry Andric 1020b57cec5SDimitry Andric // Emit function type info for all undefined functions 103480093f4SDimitry Andric if (F.isDeclarationForLinker()) { 1040b57cec5SDimitry Andric SmallVector<MVT, 4> Results; 1050b57cec5SDimitry Andric SmallVector<MVT, 4> Params; 106*5ffd83dbSDimitry Andric computeSignatureVTs(F.getFunctionType(), &F, 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(); 125*5ffd83dbSDimitry Andric Sym->setImportModule(storeName(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(); 132*5ffd83dbSDimitry Andric Sym->setImportName(storeName(Name)); 1330b57cec5SDimitry Andric getTargetStreamer()->emitImportName(Sym, Name); 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric } 136480093f4SDimitry Andric 137480093f4SDimitry Andric if (F.hasFnAttribute("wasm-export-name")) { 138480093f4SDimitry Andric auto *Sym = cast<MCSymbolWasm>(getSymbol(&F)); 139480093f4SDimitry Andric StringRef Name = F.getFnAttribute("wasm-export-name").getValueAsString(); 140*5ffd83dbSDimitry Andric Sym->setExportName(storeName(Name)); 141480093f4SDimitry Andric getTargetStreamer()->emitExportName(Sym, Name); 142480093f4SDimitry 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); 170*5ffd83dbSDimitry 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); 211*5ffd83dbSDimitry 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; 216*5ffd83dbSDimitry Andric OutStreamer->emitULEB128IntValue(strlen(Producers.first)); 217*5ffd83dbSDimitry Andric OutStreamer->emitBytes(Producers.first); 218*5ffd83dbSDimitry Andric OutStreamer->emitULEB128IntValue(Producers.second->size()); 2190b57cec5SDimitry Andric for (auto &Producer : *Producers.second) { 220*5ffd83dbSDimitry Andric OutStreamer->emitULEB128IntValue(Producer.first.size()); 221*5ffd83dbSDimitry Andric OutStreamer->emitBytes(Producer.first); 222*5ffd83dbSDimitry Andric OutStreamer->emitULEB128IntValue(Producer.second.size()); 223*5ffd83dbSDimitry 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; 233*5ffd83dbSDimitry Andric std::string Name; 2340b57cec5SDimitry Andric }; 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric // Read target features and linkage policies from module metadata 2370b57cec5SDimitry Andric SmallVector<FeatureEntry, 4> EmittedFeatures; 238*5ffd83dbSDimitry Andric auto EmitFeature = [&](std::string Feature) { 239*5ffd83dbSDimitry Andric std::string MDKey = (StringRef("wasm-feature-") + Feature).str(); 2400b57cec5SDimitry Andric Metadata *Policy = M.getModuleFlag(MDKey); 2410b57cec5SDimitry Andric if (Policy == nullptr) 242*5ffd83dbSDimitry Andric return; 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric FeatureEntry Entry; 2450b57cec5SDimitry Andric Entry.Prefix = 0; 246*5ffd83dbSDimitry Andric Entry.Name = Feature; 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) 256*5ffd83dbSDimitry Andric return; 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric EmittedFeatures.push_back(Entry); 259*5ffd83dbSDimitry Andric }; 260*5ffd83dbSDimitry Andric 261*5ffd83dbSDimitry Andric for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { 262*5ffd83dbSDimitry Andric EmitFeature(KV.Key); 2630b57cec5SDimitry Andric } 264*5ffd83dbSDimitry Andric // This pseudo-feature tells the linker whether shared memory would be safe 265*5ffd83dbSDimitry Andric EmitFeature("shared-mem"); 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric if (EmittedFeatures.size() == 0) 2680b57cec5SDimitry Andric return; 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric // Emit features and linkage policies into the "target_features" section 2710b57cec5SDimitry Andric MCSectionWasm *FeaturesSection = OutContext.getWasmSection( 2720b57cec5SDimitry Andric ".custom_section.target_features", SectionKind::getMetadata()); 2730b57cec5SDimitry Andric OutStreamer->PushSection(); 2740b57cec5SDimitry Andric OutStreamer->SwitchSection(FeaturesSection); 2750b57cec5SDimitry Andric 276*5ffd83dbSDimitry Andric OutStreamer->emitULEB128IntValue(EmittedFeatures.size()); 2770b57cec5SDimitry Andric for (auto &F : EmittedFeatures) { 278*5ffd83dbSDimitry Andric OutStreamer->emitIntValue(F.Prefix, 1); 279*5ffd83dbSDimitry Andric OutStreamer->emitULEB128IntValue(F.Name.size()); 280*5ffd83dbSDimitry Andric OutStreamer->emitBytes(F.Name); 2810b57cec5SDimitry Andric } 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric OutStreamer->PopSection(); 2840b57cec5SDimitry Andric } 2850b57cec5SDimitry Andric 286*5ffd83dbSDimitry Andric void WebAssemblyAsmPrinter::emitConstantPool() { 2870b57cec5SDimitry Andric assert(MF->getConstantPool()->getConstants().empty() && 2880b57cec5SDimitry Andric "WebAssembly disables constant pools"); 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric 291*5ffd83dbSDimitry Andric void WebAssemblyAsmPrinter::emitJumpTableInfo() { 2920b57cec5SDimitry Andric // Nothing to do; jump tables are incorporated into the instruction stream. 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric 295*5ffd83dbSDimitry Andric void WebAssemblyAsmPrinter::emitFunctionBodyStart() { 2960b57cec5SDimitry Andric const Function &F = MF->getFunction(); 2970b57cec5SDimitry Andric SmallVector<MVT, 1> ResultVTs; 2980b57cec5SDimitry Andric SmallVector<MVT, 4> ParamVTs; 299*5ffd83dbSDimitry Andric computeSignatureVTs(F.getFunctionType(), &F, F, TM, ParamVTs, ResultVTs); 300*5ffd83dbSDimitry Andric 3010b57cec5SDimitry Andric auto Signature = signatureFromMVTs(ResultVTs, ParamVTs); 3020b57cec5SDimitry Andric auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym); 3030b57cec5SDimitry Andric WasmSym->setSignature(Signature.get()); 3040b57cec5SDimitry Andric addSignature(std::move(Signature)); 3050b57cec5SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric // FIXME: clean up how params and results are emitted (use signatures) 3080b57cec5SDimitry Andric getTargetStreamer()->emitFunctionType(WasmSym); 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric // Emit the function index. 3110b57cec5SDimitry Andric if (MDNode *Idx = F.getMetadata("wasm.index")) { 3120b57cec5SDimitry Andric assert(Idx->getNumOperands() == 1); 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant( 3150b57cec5SDimitry Andric cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue())); 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric SmallVector<wasm::ValType, 16> Locals; 3190b57cec5SDimitry Andric valTypesFromMVTs(MFI->getLocals(), Locals); 3200b57cec5SDimitry Andric getTargetStreamer()->emitLocal(Locals); 3210b57cec5SDimitry Andric 322*5ffd83dbSDimitry Andric AsmPrinter::emitFunctionBodyStart(); 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric 325*5ffd83dbSDimitry Andric void WebAssemblyAsmPrinter::emitInstruction(const MachineInstr *MI) { 3260b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n'); 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric switch (MI->getOpcode()) { 3290b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i32: 3300b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i32_S: 3310b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i64: 3320b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i64_S: 3330b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f32: 3340b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f32_S: 3350b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f64: 3360b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f64_S: 3370b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v16i8: 3380b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v16i8_S: 3390b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v8i16: 3400b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v8i16_S: 3410b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4i32: 3420b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4i32_S: 3430b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2i64: 3440b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2i64_S: 3450b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4f32: 3460b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4f32_S: 3470b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2f64: 3480b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2f64_S: 3490b57cec5SDimitry Andric // These represent values which are live into the function entry, so there's 3500b57cec5SDimitry Andric // no instruction to emit. 3510b57cec5SDimitry Andric break; 3528bcb0991SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN: { 3530b57cec5SDimitry Andric // These instructions represent the implicit return at the end of a 3548bcb0991SDimitry Andric // function body. 3550b57cec5SDimitry Andric if (isVerbose()) { 3568bcb0991SDimitry Andric OutStreamer->AddComment("fallthrough-return"); 3570b57cec5SDimitry Andric OutStreamer->AddBlankLine(); 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric break; 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric case WebAssembly::COMPILER_FENCE: 3620b57cec5SDimitry Andric // This is a compiler barrier that prevents instruction reordering during 3630b57cec5SDimitry Andric // backend compilation, and should not be emitted. 3640b57cec5SDimitry Andric break; 3650b57cec5SDimitry Andric case WebAssembly::EXTRACT_EXCEPTION_I32: 3660b57cec5SDimitry Andric case WebAssembly::EXTRACT_EXCEPTION_I32_S: 3670b57cec5SDimitry Andric // These are pseudo instructions that simulates popping values from stack. 3680b57cec5SDimitry Andric // We print these only when we have -wasm-keep-registers on for assembly 3690b57cec5SDimitry Andric // readability. 3700b57cec5SDimitry Andric if (!WasmKeepRegisters) 3710b57cec5SDimitry Andric break; 3720b57cec5SDimitry Andric LLVM_FALLTHROUGH; 3730b57cec5SDimitry Andric default: { 3740b57cec5SDimitry Andric WebAssemblyMCInstLower MCInstLowering(OutContext, *this); 3750b57cec5SDimitry Andric MCInst TmpInst; 3760b57cec5SDimitry Andric MCInstLowering.lower(MI, TmpInst); 3770b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst); 3780b57cec5SDimitry Andric break; 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric } 3810b57cec5SDimitry Andric } 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI, 3840b57cec5SDimitry Andric unsigned OpNo, 3850b57cec5SDimitry Andric const char *ExtraCode, 3860b57cec5SDimitry Andric raw_ostream &OS) { 3870b57cec5SDimitry Andric // First try the generic code, which knows about modifiers like 'c' and 'n'. 3880b57cec5SDimitry Andric if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) 3890b57cec5SDimitry Andric return false; 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric if (!ExtraCode) { 3920b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNo); 3930b57cec5SDimitry Andric switch (MO.getType()) { 3940b57cec5SDimitry Andric case MachineOperand::MO_Immediate: 3950b57cec5SDimitry Andric OS << MO.getImm(); 3960b57cec5SDimitry Andric return false; 3970b57cec5SDimitry Andric case MachineOperand::MO_Register: 3980b57cec5SDimitry Andric // FIXME: only opcode that still contains registers, as required by 3990b57cec5SDimitry Andric // MachineInstr::getDebugVariable(). 4000b57cec5SDimitry Andric assert(MI->getOpcode() == WebAssembly::INLINEASM); 4010b57cec5SDimitry Andric OS << regToString(MO); 4020b57cec5SDimitry Andric return false; 4030b57cec5SDimitry Andric case MachineOperand::MO_GlobalAddress: 4040b57cec5SDimitry Andric PrintSymbolOperand(MO, OS); 4050b57cec5SDimitry Andric return false; 4060b57cec5SDimitry Andric case MachineOperand::MO_ExternalSymbol: 4070b57cec5SDimitry Andric GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI); 4080b57cec5SDimitry Andric printOffset(MO.getOffset(), OS); 4090b57cec5SDimitry Andric return false; 4100b57cec5SDimitry Andric case MachineOperand::MO_MachineBasicBlock: 4110b57cec5SDimitry Andric MO.getMBB()->getSymbol()->print(OS, MAI); 4120b57cec5SDimitry Andric return false; 4130b57cec5SDimitry Andric default: 4140b57cec5SDimitry Andric break; 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric } 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric return true; 4190b57cec5SDimitry Andric } 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 4220b57cec5SDimitry Andric unsigned OpNo, 4230b57cec5SDimitry Andric const char *ExtraCode, 4240b57cec5SDimitry Andric raw_ostream &OS) { 4250b57cec5SDimitry Andric // The current approach to inline asm is that "r" constraints are expressed 4260b57cec5SDimitry Andric // as local indices, rather than values on the operand stack. This simplifies 4270b57cec5SDimitry Andric // using "r" as it eliminates the need to push and pop the values in a 4280b57cec5SDimitry Andric // particular order, however it also makes it impossible to have an "m" 4290b57cec5SDimitry Andric // constraint. So we don't support it. 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); 4320b57cec5SDimitry Andric } 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric // Force static initialization. 435480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmPrinter() { 4360b57cec5SDimitry Andric RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32()); 4370b57cec5SDimitry Andric RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64()); 4380b57cec5SDimitry Andric } 439