1*0b57cec5SDimitry Andric //===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric /// 9*0b57cec5SDimitry Andric /// \file 10*0b57cec5SDimitry Andric /// This file contains a printer that converts from our internal 11*0b57cec5SDimitry Andric /// representation of machine-dependent LLVM code to the WebAssembly assembly 12*0b57cec5SDimitry Andric /// language. 13*0b57cec5SDimitry Andric /// 14*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 15*0b57cec5SDimitry Andric 16*0b57cec5SDimitry Andric #include "WebAssemblyAsmPrinter.h" 17*0b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyInstPrinter.h" 18*0b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 19*0b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyTargetStreamer.h" 20*0b57cec5SDimitry Andric #include "TargetInfo/WebAssemblyTargetInfo.h" 21*0b57cec5SDimitry Andric #include "WebAssembly.h" 22*0b57cec5SDimitry Andric #include "WebAssemblyMCInstLower.h" 23*0b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 24*0b57cec5SDimitry Andric #include "WebAssemblyRegisterInfo.h" 25*0b57cec5SDimitry Andric #include "WebAssemblyTargetMachine.h" 26*0b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h" 27*0b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 28*0b57cec5SDimitry Andric #include "llvm/BinaryFormat/Wasm.h" 29*0b57cec5SDimitry Andric #include "llvm/CodeGen/Analysis.h" 30*0b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h" 31*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 32*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 33*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfoImpls.h" 34*0b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 35*0b57cec5SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 36*0b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 37*0b57cec5SDimitry Andric #include "llvm/IR/Metadata.h" 38*0b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 39*0b57cec5SDimitry Andric #include "llvm/MC/MCSectionWasm.h" 40*0b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 41*0b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 42*0b57cec5SDimitry Andric #include "llvm/MC/MCSymbolWasm.h" 43*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 44*0b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h" 45*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric using namespace llvm; 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer" 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric extern cl::opt<bool> WasmKeepRegisters; 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 54*0b57cec5SDimitry Andric // Helpers. 55*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const { 58*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); 59*0b57cec5SDimitry Andric const TargetRegisterClass *TRC = MRI->getRegClass(RegNo); 60*0b57cec5SDimitry Andric for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16, 61*0b57cec5SDimitry Andric MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64}) 62*0b57cec5SDimitry Andric if (TRI->isTypeLegalForClass(*TRC, T)) 63*0b57cec5SDimitry Andric return T; 64*0b57cec5SDimitry Andric LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo); 65*0b57cec5SDimitry Andric llvm_unreachable("Unknown register type"); 66*0b57cec5SDimitry Andric return MVT::Other; 67*0b57cec5SDimitry Andric } 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) { 70*0b57cec5SDimitry Andric unsigned RegNo = MO.getReg(); 71*0b57cec5SDimitry Andric assert(TargetRegisterInfo::isVirtualRegister(RegNo) && 72*0b57cec5SDimitry Andric "Unlowered physical register encountered during assembly printing"); 73*0b57cec5SDimitry Andric assert(!MFI->isVRegStackified(RegNo)); 74*0b57cec5SDimitry Andric unsigned WAReg = MFI->getWAReg(RegNo); 75*0b57cec5SDimitry Andric assert(WAReg != WebAssemblyFunctionInfo::UnusedReg); 76*0b57cec5SDimitry Andric return '$' + utostr(WAReg); 77*0b57cec5SDimitry Andric } 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() { 80*0b57cec5SDimitry Andric MCTargetStreamer *TS = OutStreamer->getTargetStreamer(); 81*0b57cec5SDimitry Andric return static_cast<WebAssemblyTargetStreamer *>(TS); 82*0b57cec5SDimitry Andric } 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 85*0b57cec5SDimitry Andric // WebAssemblyAsmPrinter Implementation. 86*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { 89*0b57cec5SDimitry Andric for (auto &It : OutContext.getSymbols()) { 90*0b57cec5SDimitry Andric // Emit a .globaltype and .eventtype declaration. 91*0b57cec5SDimitry Andric auto Sym = cast<MCSymbolWasm>(It.getValue()); 92*0b57cec5SDimitry Andric if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL) 93*0b57cec5SDimitry Andric getTargetStreamer()->emitGlobalType(Sym); 94*0b57cec5SDimitry Andric else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT) 95*0b57cec5SDimitry Andric getTargetStreamer()->emitEventType(Sym); 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric for (const auto &F : M) { 99*0b57cec5SDimitry Andric // Emit function type info for all undefined functions 100*0b57cec5SDimitry Andric if (F.isDeclarationForLinker() && !F.isIntrinsic()) { 101*0b57cec5SDimitry Andric SmallVector<MVT, 4> Results; 102*0b57cec5SDimitry Andric SmallVector<MVT, 4> Params; 103*0b57cec5SDimitry Andric computeSignatureVTs(F.getFunctionType(), F, TM, Params, Results); 104*0b57cec5SDimitry Andric auto *Sym = cast<MCSymbolWasm>(getSymbol(&F)); 105*0b57cec5SDimitry Andric Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 106*0b57cec5SDimitry Andric if (!Sym->getSignature()) { 107*0b57cec5SDimitry Andric auto Signature = signatureFromMVTs(Results, Params); 108*0b57cec5SDimitry Andric Sym->setSignature(Signature.get()); 109*0b57cec5SDimitry Andric addSignature(std::move(Signature)); 110*0b57cec5SDimitry Andric } 111*0b57cec5SDimitry Andric // FIXME: this was originally intended for post-linking and was only used 112*0b57cec5SDimitry Andric // for imports that were only called indirectly (i.e. s2wasm could not 113*0b57cec5SDimitry Andric // infer the type from a call). With object files it applies to all 114*0b57cec5SDimitry Andric // imports. so fix the names and the tests, or rethink how import 115*0b57cec5SDimitry Andric // delcarations work in asm files. 116*0b57cec5SDimitry Andric getTargetStreamer()->emitFunctionType(Sym); 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric if (TM.getTargetTriple().isOSBinFormatWasm() && 119*0b57cec5SDimitry Andric F.hasFnAttribute("wasm-import-module")) { 120*0b57cec5SDimitry Andric StringRef Name = 121*0b57cec5SDimitry Andric F.getFnAttribute("wasm-import-module").getValueAsString(); 122*0b57cec5SDimitry Andric Sym->setImportModule(Name); 123*0b57cec5SDimitry Andric getTargetStreamer()->emitImportModule(Sym, Name); 124*0b57cec5SDimitry Andric } 125*0b57cec5SDimitry Andric if (TM.getTargetTriple().isOSBinFormatWasm() && 126*0b57cec5SDimitry Andric F.hasFnAttribute("wasm-import-name")) { 127*0b57cec5SDimitry Andric StringRef Name = 128*0b57cec5SDimitry Andric F.getFnAttribute("wasm-import-name").getValueAsString(); 129*0b57cec5SDimitry Andric Sym->setImportName(Name); 130*0b57cec5SDimitry Andric getTargetStreamer()->emitImportName(Sym, Name); 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric } 134*0b57cec5SDimitry Andric 135*0b57cec5SDimitry Andric for (const auto &G : M.globals()) { 136*0b57cec5SDimitry Andric if (!G.hasInitializer() && G.hasExternalLinkage()) { 137*0b57cec5SDimitry Andric if (G.getValueType()->isSized()) { 138*0b57cec5SDimitry Andric uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType()); 139*0b57cec5SDimitry Andric OutStreamer->emitELFSize(getSymbol(&G), 140*0b57cec5SDimitry Andric MCConstantExpr::create(Size, OutContext)); 141*0b57cec5SDimitry Andric } 142*0b57cec5SDimitry Andric } 143*0b57cec5SDimitry Andric } 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) { 146*0b57cec5SDimitry Andric for (const Metadata *MD : Named->operands()) { 147*0b57cec5SDimitry Andric const auto *Tuple = dyn_cast<MDTuple>(MD); 148*0b57cec5SDimitry Andric if (!Tuple || Tuple->getNumOperands() != 2) 149*0b57cec5SDimitry Andric continue; 150*0b57cec5SDimitry Andric const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0)); 151*0b57cec5SDimitry Andric const MDString *Contents = dyn_cast<MDString>(Tuple->getOperand(1)); 152*0b57cec5SDimitry Andric if (!Name || !Contents) 153*0b57cec5SDimitry Andric continue; 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric OutStreamer->PushSection(); 156*0b57cec5SDimitry Andric std::string SectionName = (".custom_section." + Name->getString()).str(); 157*0b57cec5SDimitry Andric MCSectionWasm *MySection = 158*0b57cec5SDimitry Andric OutContext.getWasmSection(SectionName, SectionKind::getMetadata()); 159*0b57cec5SDimitry Andric OutStreamer->SwitchSection(MySection); 160*0b57cec5SDimitry Andric OutStreamer->EmitBytes(Contents->getString()); 161*0b57cec5SDimitry Andric OutStreamer->PopSection(); 162*0b57cec5SDimitry Andric } 163*0b57cec5SDimitry Andric } 164*0b57cec5SDimitry Andric 165*0b57cec5SDimitry Andric EmitProducerInfo(M); 166*0b57cec5SDimitry Andric EmitTargetFeatures(M); 167*0b57cec5SDimitry Andric } 168*0b57cec5SDimitry Andric 169*0b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) { 170*0b57cec5SDimitry Andric llvm::SmallVector<std::pair<std::string, std::string>, 4> Languages; 171*0b57cec5SDimitry Andric if (const NamedMDNode *Debug = M.getNamedMetadata("llvm.dbg.cu")) { 172*0b57cec5SDimitry Andric llvm::SmallSet<StringRef, 4> SeenLanguages; 173*0b57cec5SDimitry Andric for (size_t I = 0, E = Debug->getNumOperands(); I < E; ++I) { 174*0b57cec5SDimitry Andric const auto *CU = cast<DICompileUnit>(Debug->getOperand(I)); 175*0b57cec5SDimitry Andric StringRef Language = dwarf::LanguageString(CU->getSourceLanguage()); 176*0b57cec5SDimitry Andric Language.consume_front("DW_LANG_"); 177*0b57cec5SDimitry Andric if (SeenLanguages.insert(Language).second) 178*0b57cec5SDimitry Andric Languages.emplace_back(Language.str(), ""); 179*0b57cec5SDimitry Andric } 180*0b57cec5SDimitry Andric } 181*0b57cec5SDimitry Andric 182*0b57cec5SDimitry Andric llvm::SmallVector<std::pair<std::string, std::string>, 4> Tools; 183*0b57cec5SDimitry Andric if (const NamedMDNode *Ident = M.getNamedMetadata("llvm.ident")) { 184*0b57cec5SDimitry Andric llvm::SmallSet<StringRef, 4> SeenTools; 185*0b57cec5SDimitry Andric for (size_t I = 0, E = Ident->getNumOperands(); I < E; ++I) { 186*0b57cec5SDimitry Andric const auto *S = cast<MDString>(Ident->getOperand(I)->getOperand(0)); 187*0b57cec5SDimitry Andric std::pair<StringRef, StringRef> Field = S->getString().split("version"); 188*0b57cec5SDimitry Andric StringRef Name = Field.first.trim(); 189*0b57cec5SDimitry Andric StringRef Version = Field.second.trim(); 190*0b57cec5SDimitry Andric if (SeenTools.insert(Name).second) 191*0b57cec5SDimitry Andric Tools.emplace_back(Name.str(), Version.str()); 192*0b57cec5SDimitry Andric } 193*0b57cec5SDimitry Andric } 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric int FieldCount = int(!Languages.empty()) + int(!Tools.empty()); 196*0b57cec5SDimitry Andric if (FieldCount != 0) { 197*0b57cec5SDimitry Andric MCSectionWasm *Producers = OutContext.getWasmSection( 198*0b57cec5SDimitry Andric ".custom_section.producers", SectionKind::getMetadata()); 199*0b57cec5SDimitry Andric OutStreamer->PushSection(); 200*0b57cec5SDimitry Andric OutStreamer->SwitchSection(Producers); 201*0b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(FieldCount); 202*0b57cec5SDimitry Andric for (auto &Producers : {std::make_pair("language", &Languages), 203*0b57cec5SDimitry Andric std::make_pair("processed-by", &Tools)}) { 204*0b57cec5SDimitry Andric if (Producers.second->empty()) 205*0b57cec5SDimitry Andric continue; 206*0b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(strlen(Producers.first)); 207*0b57cec5SDimitry Andric OutStreamer->EmitBytes(Producers.first); 208*0b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(Producers.second->size()); 209*0b57cec5SDimitry Andric for (auto &Producer : *Producers.second) { 210*0b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(Producer.first.size()); 211*0b57cec5SDimitry Andric OutStreamer->EmitBytes(Producer.first); 212*0b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(Producer.second.size()); 213*0b57cec5SDimitry Andric OutStreamer->EmitBytes(Producer.second); 214*0b57cec5SDimitry Andric } 215*0b57cec5SDimitry Andric } 216*0b57cec5SDimitry Andric OutStreamer->PopSection(); 217*0b57cec5SDimitry Andric } 218*0b57cec5SDimitry Andric } 219*0b57cec5SDimitry Andric 220*0b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) { 221*0b57cec5SDimitry Andric struct FeatureEntry { 222*0b57cec5SDimitry Andric uint8_t Prefix; 223*0b57cec5SDimitry Andric StringRef Name; 224*0b57cec5SDimitry Andric }; 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric // Read target features and linkage policies from module metadata 227*0b57cec5SDimitry Andric SmallVector<FeatureEntry, 4> EmittedFeatures; 228*0b57cec5SDimitry Andric for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { 229*0b57cec5SDimitry Andric std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str(); 230*0b57cec5SDimitry Andric Metadata *Policy = M.getModuleFlag(MDKey); 231*0b57cec5SDimitry Andric if (Policy == nullptr) 232*0b57cec5SDimitry Andric continue; 233*0b57cec5SDimitry Andric 234*0b57cec5SDimitry Andric FeatureEntry Entry; 235*0b57cec5SDimitry Andric Entry.Prefix = 0; 236*0b57cec5SDimitry Andric Entry.Name = KV.Key; 237*0b57cec5SDimitry Andric 238*0b57cec5SDimitry Andric if (auto *MD = cast<ConstantAsMetadata>(Policy)) 239*0b57cec5SDimitry Andric if (auto *I = cast<ConstantInt>(MD->getValue())) 240*0b57cec5SDimitry Andric Entry.Prefix = I->getZExtValue(); 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric // Silently ignore invalid metadata 243*0b57cec5SDimitry Andric if (Entry.Prefix != wasm::WASM_FEATURE_PREFIX_USED && 244*0b57cec5SDimitry Andric Entry.Prefix != wasm::WASM_FEATURE_PREFIX_REQUIRED && 245*0b57cec5SDimitry Andric Entry.Prefix != wasm::WASM_FEATURE_PREFIX_DISALLOWED) 246*0b57cec5SDimitry Andric continue; 247*0b57cec5SDimitry Andric 248*0b57cec5SDimitry Andric EmittedFeatures.push_back(Entry); 249*0b57cec5SDimitry Andric } 250*0b57cec5SDimitry Andric 251*0b57cec5SDimitry Andric if (EmittedFeatures.size() == 0) 252*0b57cec5SDimitry Andric return; 253*0b57cec5SDimitry Andric 254*0b57cec5SDimitry Andric // Emit features and linkage policies into the "target_features" section 255*0b57cec5SDimitry Andric MCSectionWasm *FeaturesSection = OutContext.getWasmSection( 256*0b57cec5SDimitry Andric ".custom_section.target_features", SectionKind::getMetadata()); 257*0b57cec5SDimitry Andric OutStreamer->PushSection(); 258*0b57cec5SDimitry Andric OutStreamer->SwitchSection(FeaturesSection); 259*0b57cec5SDimitry Andric 260*0b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(EmittedFeatures.size()); 261*0b57cec5SDimitry Andric for (auto &F : EmittedFeatures) { 262*0b57cec5SDimitry Andric OutStreamer->EmitIntValue(F.Prefix, 1); 263*0b57cec5SDimitry Andric OutStreamer->EmitULEB128IntValue(F.Name.size()); 264*0b57cec5SDimitry Andric OutStreamer->EmitBytes(F.Name); 265*0b57cec5SDimitry Andric } 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric OutStreamer->PopSection(); 268*0b57cec5SDimitry Andric } 269*0b57cec5SDimitry Andric 270*0b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitConstantPool() { 271*0b57cec5SDimitry Andric assert(MF->getConstantPool()->getConstants().empty() && 272*0b57cec5SDimitry Andric "WebAssembly disables constant pools"); 273*0b57cec5SDimitry Andric } 274*0b57cec5SDimitry Andric 275*0b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitJumpTableInfo() { 276*0b57cec5SDimitry Andric // Nothing to do; jump tables are incorporated into the instruction stream. 277*0b57cec5SDimitry Andric } 278*0b57cec5SDimitry Andric 279*0b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { 280*0b57cec5SDimitry Andric const Function &F = MF->getFunction(); 281*0b57cec5SDimitry Andric SmallVector<MVT, 1> ResultVTs; 282*0b57cec5SDimitry Andric SmallVector<MVT, 4> ParamVTs; 283*0b57cec5SDimitry Andric computeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs); 284*0b57cec5SDimitry Andric auto Signature = signatureFromMVTs(ResultVTs, ParamVTs); 285*0b57cec5SDimitry Andric auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym); 286*0b57cec5SDimitry Andric WasmSym->setSignature(Signature.get()); 287*0b57cec5SDimitry Andric addSignature(std::move(Signature)); 288*0b57cec5SDimitry Andric WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 289*0b57cec5SDimitry Andric 290*0b57cec5SDimitry Andric // FIXME: clean up how params and results are emitted (use signatures) 291*0b57cec5SDimitry Andric getTargetStreamer()->emitFunctionType(WasmSym); 292*0b57cec5SDimitry Andric 293*0b57cec5SDimitry Andric // Emit the function index. 294*0b57cec5SDimitry Andric if (MDNode *Idx = F.getMetadata("wasm.index")) { 295*0b57cec5SDimitry Andric assert(Idx->getNumOperands() == 1); 296*0b57cec5SDimitry Andric 297*0b57cec5SDimitry Andric getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant( 298*0b57cec5SDimitry Andric cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue())); 299*0b57cec5SDimitry Andric } 300*0b57cec5SDimitry Andric 301*0b57cec5SDimitry Andric SmallVector<wasm::ValType, 16> Locals; 302*0b57cec5SDimitry Andric valTypesFromMVTs(MFI->getLocals(), Locals); 303*0b57cec5SDimitry Andric getTargetStreamer()->emitLocal(Locals); 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric AsmPrinter::EmitFunctionBodyStart(); 306*0b57cec5SDimitry Andric } 307*0b57cec5SDimitry Andric 308*0b57cec5SDimitry Andric void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { 309*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n'); 310*0b57cec5SDimitry Andric 311*0b57cec5SDimitry Andric switch (MI->getOpcode()) { 312*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i32: 313*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i32_S: 314*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i64: 315*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_i64_S: 316*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f32: 317*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f32_S: 318*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f64: 319*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_f64_S: 320*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v16i8: 321*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v16i8_S: 322*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v8i16: 323*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v8i16_S: 324*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4i32: 325*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4i32_S: 326*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2i64: 327*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2i64_S: 328*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4f32: 329*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v4f32_S: 330*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2f64: 331*0b57cec5SDimitry Andric case WebAssembly::ARGUMENT_v2f64_S: 332*0b57cec5SDimitry Andric // These represent values which are live into the function entry, so there's 333*0b57cec5SDimitry Andric // no instruction to emit. 334*0b57cec5SDimitry Andric break; 335*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_I32: 336*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_I32_S: 337*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_I64: 338*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_I64_S: 339*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_F32: 340*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_F32_S: 341*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_F64: 342*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_F64_S: 343*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v16i8: 344*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v16i8_S: 345*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v8i16: 346*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v8i16_S: 347*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v4i32: 348*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v4i32_S: 349*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v2i64: 350*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v2i64_S: 351*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v4f32: 352*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v4f32_S: 353*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v2f64: 354*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_v2f64_S: { 355*0b57cec5SDimitry Andric // These instructions represent the implicit return at the end of a 356*0b57cec5SDimitry Andric // function body. Always pops one value off the stack. 357*0b57cec5SDimitry Andric if (isVerbose()) { 358*0b57cec5SDimitry Andric OutStreamer->AddComment("fallthrough-return-value"); 359*0b57cec5SDimitry Andric OutStreamer->AddBlankLine(); 360*0b57cec5SDimitry Andric } 361*0b57cec5SDimitry Andric break; 362*0b57cec5SDimitry Andric } 363*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_VOID: 364*0b57cec5SDimitry Andric case WebAssembly::FALLTHROUGH_RETURN_VOID_S: 365*0b57cec5SDimitry Andric // This instruction represents the implicit return at the end of a 366*0b57cec5SDimitry Andric // function body with no return value. 367*0b57cec5SDimitry Andric if (isVerbose()) { 368*0b57cec5SDimitry Andric OutStreamer->AddComment("fallthrough-return-void"); 369*0b57cec5SDimitry Andric OutStreamer->AddBlankLine(); 370*0b57cec5SDimitry Andric } 371*0b57cec5SDimitry Andric break; 372*0b57cec5SDimitry Andric case WebAssembly::COMPILER_FENCE: 373*0b57cec5SDimitry Andric // This is a compiler barrier that prevents instruction reordering during 374*0b57cec5SDimitry Andric // backend compilation, and should not be emitted. 375*0b57cec5SDimitry Andric break; 376*0b57cec5SDimitry Andric case WebAssembly::EXTRACT_EXCEPTION_I32: 377*0b57cec5SDimitry Andric case WebAssembly::EXTRACT_EXCEPTION_I32_S: 378*0b57cec5SDimitry Andric // These are pseudo instructions that simulates popping values from stack. 379*0b57cec5SDimitry Andric // We print these only when we have -wasm-keep-registers on for assembly 380*0b57cec5SDimitry Andric // readability. 381*0b57cec5SDimitry Andric if (!WasmKeepRegisters) 382*0b57cec5SDimitry Andric break; 383*0b57cec5SDimitry Andric LLVM_FALLTHROUGH; 384*0b57cec5SDimitry Andric default: { 385*0b57cec5SDimitry Andric WebAssemblyMCInstLower MCInstLowering(OutContext, *this); 386*0b57cec5SDimitry Andric MCInst TmpInst; 387*0b57cec5SDimitry Andric MCInstLowering.lower(MI, TmpInst); 388*0b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst); 389*0b57cec5SDimitry Andric break; 390*0b57cec5SDimitry Andric } 391*0b57cec5SDimitry Andric } 392*0b57cec5SDimitry Andric } 393*0b57cec5SDimitry Andric 394*0b57cec5SDimitry Andric bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI, 395*0b57cec5SDimitry Andric unsigned OpNo, 396*0b57cec5SDimitry Andric const char *ExtraCode, 397*0b57cec5SDimitry Andric raw_ostream &OS) { 398*0b57cec5SDimitry Andric // First try the generic code, which knows about modifiers like 'c' and 'n'. 399*0b57cec5SDimitry Andric if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) 400*0b57cec5SDimitry Andric return false; 401*0b57cec5SDimitry Andric 402*0b57cec5SDimitry Andric if (!ExtraCode) { 403*0b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNo); 404*0b57cec5SDimitry Andric switch (MO.getType()) { 405*0b57cec5SDimitry Andric case MachineOperand::MO_Immediate: 406*0b57cec5SDimitry Andric OS << MO.getImm(); 407*0b57cec5SDimitry Andric return false; 408*0b57cec5SDimitry Andric case MachineOperand::MO_Register: 409*0b57cec5SDimitry Andric // FIXME: only opcode that still contains registers, as required by 410*0b57cec5SDimitry Andric // MachineInstr::getDebugVariable(). 411*0b57cec5SDimitry Andric assert(MI->getOpcode() == WebAssembly::INLINEASM); 412*0b57cec5SDimitry Andric OS << regToString(MO); 413*0b57cec5SDimitry Andric return false; 414*0b57cec5SDimitry Andric case MachineOperand::MO_GlobalAddress: 415*0b57cec5SDimitry Andric PrintSymbolOperand(MO, OS); 416*0b57cec5SDimitry Andric return false; 417*0b57cec5SDimitry Andric case MachineOperand::MO_ExternalSymbol: 418*0b57cec5SDimitry Andric GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI); 419*0b57cec5SDimitry Andric printOffset(MO.getOffset(), OS); 420*0b57cec5SDimitry Andric return false; 421*0b57cec5SDimitry Andric case MachineOperand::MO_MachineBasicBlock: 422*0b57cec5SDimitry Andric MO.getMBB()->getSymbol()->print(OS, MAI); 423*0b57cec5SDimitry Andric return false; 424*0b57cec5SDimitry Andric default: 425*0b57cec5SDimitry Andric break; 426*0b57cec5SDimitry Andric } 427*0b57cec5SDimitry Andric } 428*0b57cec5SDimitry Andric 429*0b57cec5SDimitry Andric return true; 430*0b57cec5SDimitry Andric } 431*0b57cec5SDimitry Andric 432*0b57cec5SDimitry Andric bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 433*0b57cec5SDimitry Andric unsigned OpNo, 434*0b57cec5SDimitry Andric const char *ExtraCode, 435*0b57cec5SDimitry Andric raw_ostream &OS) { 436*0b57cec5SDimitry Andric // The current approach to inline asm is that "r" constraints are expressed 437*0b57cec5SDimitry Andric // as local indices, rather than values on the operand stack. This simplifies 438*0b57cec5SDimitry Andric // using "r" as it eliminates the need to push and pop the values in a 439*0b57cec5SDimitry Andric // particular order, however it also makes it impossible to have an "m" 440*0b57cec5SDimitry Andric // constraint. So we don't support it. 441*0b57cec5SDimitry Andric 442*0b57cec5SDimitry Andric return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); 443*0b57cec5SDimitry Andric } 444*0b57cec5SDimitry Andric 445*0b57cec5SDimitry Andric // Force static initialization. 446*0b57cec5SDimitry Andric extern "C" void LLVMInitializeWebAssemblyAsmPrinter() { 447*0b57cec5SDimitry Andric RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32()); 448*0b57cec5SDimitry Andric RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64()); 449*0b57cec5SDimitry Andric } 450