Path: blob/main/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
35266 views
//===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file contains a printer that converts from our internal10/// representation of machine-dependent LLVM code to the WebAssembly assembly11/// language.12///13//===----------------------------------------------------------------------===//1415#include "WebAssemblyAsmPrinter.h"16#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"17#include "MCTargetDesc/WebAssemblyTargetStreamer.h"18#include "TargetInfo/WebAssemblyTargetInfo.h"19#include "Utils/WebAssemblyTypeUtilities.h"20#include "WebAssembly.h"21#include "WebAssemblyMCInstLower.h"22#include "WebAssemblyMachineFunctionInfo.h"23#include "WebAssemblyRegisterInfo.h"24#include "WebAssemblyRuntimeLibcallSignatures.h"25#include "WebAssemblyTargetMachine.h"26#include "WebAssemblyUtilities.h"27#include "llvm/ADT/MapVector.h"28#include "llvm/ADT/SmallSet.h"29#include "llvm/ADT/StringExtras.h"30#include "llvm/Analysis/ValueTracking.h"31#include "llvm/BinaryFormat/Wasm.h"32#include "llvm/CodeGen/Analysis.h"33#include "llvm/CodeGen/AsmPrinter.h"34#include "llvm/CodeGen/MachineConstantPool.h"35#include "llvm/CodeGen/MachineInstr.h"36#include "llvm/CodeGen/MachineModuleInfoImpls.h"37#include "llvm/IR/DataLayout.h"38#include "llvm/IR/DebugInfoMetadata.h"39#include "llvm/IR/GlobalVariable.h"40#include "llvm/IR/Metadata.h"41#include "llvm/IR/Module.h"42#include "llvm/MC/MCContext.h"43#include "llvm/MC/MCSectionWasm.h"44#include "llvm/MC/MCStreamer.h"45#include "llvm/MC/MCSymbol.h"46#include "llvm/MC/MCSymbolWasm.h"47#include "llvm/MC/TargetRegistry.h"48#include "llvm/Support/Debug.h"49#include "llvm/Support/raw_ostream.h"5051using namespace llvm;5253#define DEBUG_TYPE "asm-printer"5455extern cl::opt<bool> WasmKeepRegisters;5657//===----------------------------------------------------------------------===//58// Helpers.59//===----------------------------------------------------------------------===//6061MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {62const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();63const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);64for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16,65MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64, MVT::v8f16})66if (TRI->isTypeLegalForClass(*TRC, T))67return T;68LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo);69llvm_unreachable("Unknown register type");70return MVT::Other;71}7273std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {74Register RegNo = MO.getReg();75assert(RegNo.isVirtual() &&76"Unlowered physical register encountered during assembly printing");77assert(!MFI->isVRegStackified(RegNo));78unsigned WAReg = MFI->getWAReg(RegNo);79assert(WAReg != WebAssembly::UnusedReg);80return '$' + utostr(WAReg);81}8283WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {84MCTargetStreamer *TS = OutStreamer->getTargetStreamer();85return static_cast<WebAssemblyTargetStreamer *>(TS);86}8788// Emscripten exception handling helpers89//90// This converts invoke names generated by LowerEmscriptenEHSjLj to real names91// that are expected by JavaScript glue code. The invoke names generated by92// Emscripten JS glue code are based on their argument and return types; for93// example, for a function that takes an i32 and returns nothing, it is94// 'invoke_vi'. But the format of invoke generated by LowerEmscriptenEHSjLj pass95// contains a mangled string generated from their IR types, for example,96// "__invoke_void_%struct.mystruct*_int", because final wasm types are not97// available in the IR pass. So we convert those names to the form that98// Emscripten JS code expects.99//100// Refer to LowerEmscriptenEHSjLj pass for more details.101102// Returns true if the given function name is an invoke name generated by103// LowerEmscriptenEHSjLj pass.104static bool isEmscriptenInvokeName(StringRef Name) {105if (Name.front() == '"' && Name.back() == '"')106Name = Name.substr(1, Name.size() - 2);107return Name.starts_with("__invoke_");108}109110// Returns a character that represents the given wasm value type in invoke111// signatures.112static char getInvokeSig(wasm::ValType VT) {113switch (VT) {114case wasm::ValType::I32:115return 'i';116case wasm::ValType::I64:117return 'j';118case wasm::ValType::F32:119return 'f';120case wasm::ValType::F64:121return 'd';122case wasm::ValType::V128:123return 'V';124case wasm::ValType::FUNCREF:125return 'F';126case wasm::ValType::EXTERNREF:127return 'X';128case wasm::ValType::EXNREF:129return 'E';130default:131llvm_unreachable("Unhandled wasm::ValType enum");132}133}134135// Given the wasm signature, generate the invoke name in the format JS glue code136// expects.137static std::string getEmscriptenInvokeSymbolName(wasm::WasmSignature *Sig) {138assert(Sig->Returns.size() <= 1);139std::string Ret = "invoke_";140if (!Sig->Returns.empty())141for (auto VT : Sig->Returns)142Ret += getInvokeSig(VT);143else144Ret += 'v';145// Invokes' first argument is a pointer to the original function, so skip it146for (unsigned I = 1, E = Sig->Params.size(); I < E; I++)147Ret += getInvokeSig(Sig->Params[I]);148return Ret;149}150151//===----------------------------------------------------------------------===//152// WebAssemblyAsmPrinter Implementation.153//===----------------------------------------------------------------------===//154155MCSymbolWasm *WebAssemblyAsmPrinter::getMCSymbolForFunction(156const Function *F, bool EnableEmEH, wasm::WasmSignature *Sig,157bool &InvokeDetected) {158MCSymbolWasm *WasmSym = nullptr;159if (EnableEmEH && isEmscriptenInvokeName(F->getName())) {160assert(Sig);161InvokeDetected = true;162if (Sig->Returns.size() > 1) {163std::string Msg =164"Emscripten EH/SjLj does not support multivalue returns: " +165std::string(F->getName()) + ": " +166WebAssembly::signatureToString(Sig);167report_fatal_error(Twine(Msg));168}169WasmSym = cast<MCSymbolWasm>(170GetExternalSymbolSymbol(getEmscriptenInvokeSymbolName(Sig)));171} else {172WasmSym = cast<MCSymbolWasm>(getSymbol(F));173}174return WasmSym;175}176177void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {178if (!WebAssembly::isWasmVarAddressSpace(GV->getAddressSpace())) {179AsmPrinter::emitGlobalVariable(GV);180return;181}182183assert(!GV->isThreadLocal());184185MCSymbolWasm *Sym = cast<MCSymbolWasm>(getSymbol(GV));186187if (!Sym->getType()) {188SmallVector<MVT, 1> VTs;189Type *GlobalVT = GV->getValueType();190if (Subtarget) {191// Subtarget is only set when a function is defined, because192// each function can declare a different subtarget. For example,193// on ARM a compilation unit might have a function on ARM and194// another on Thumb. Therefore only if Subtarget is non-null we195// can actually calculate the legal VTs.196const WebAssemblyTargetLowering &TLI = *Subtarget->getTargetLowering();197computeLegalValueVTs(TLI, GV->getParent()->getContext(),198GV->getDataLayout(), GlobalVT, VTs);199}200WebAssembly::wasmSymbolSetType(Sym, GlobalVT, VTs);201}202203emitVisibility(Sym, GV->getVisibility(), !GV->isDeclaration());204emitSymbolType(Sym);205if (GV->hasInitializer()) {206assert(getSymbolPreferLocal(*GV) == Sym);207emitLinkage(GV, Sym);208OutStreamer->emitLabel(Sym);209// TODO: Actually emit the initializer value. Otherwise the global has the210// default value for its type (0, ref.null, etc).211OutStreamer->addBlankLine();212}213}214215MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) {216auto *WasmSym = cast<MCSymbolWasm>(GetExternalSymbolSymbol(Name));217218// May be called multiple times, so early out.219if (WasmSym->getType())220return WasmSym;221222const WebAssemblySubtarget &Subtarget = getSubtarget();223224// Except for certain known symbols, all symbols used by CodeGen are225// functions. It's OK to hardcode knowledge of specific symbols here; this226// method is precisely there for fetching the signatures of known227// Clang-provided symbols.228if (Name == "__stack_pointer" || Name == "__tls_base" ||229Name == "__memory_base" || Name == "__table_base" ||230Name == "__tls_size" || Name == "__tls_align") {231bool Mutable =232Name == "__stack_pointer" || Name == "__tls_base";233WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);234WasmSym->setGlobalType(wasm::WasmGlobalType{235uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64236: wasm::WASM_TYPE_I32),237Mutable});238return WasmSym;239}240241if (Name.starts_with("GCC_except_table")) {242WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA);243return WasmSym;244}245246SmallVector<wasm::ValType, 4> Returns;247SmallVector<wasm::ValType, 4> Params;248if (Name == "__cpp_exception" || Name == "__c_longjmp") {249WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);250// In static linking we define tag symbols in WasmException::endModule().251// But we may have multiple objects to be linked together, each of which252// defines the tag symbols. To resolve them, we declare them as weak. In253// dynamic linking we make tag symbols undefined in the backend, define it254// in JS, and feed them to each importing module.255if (!isPositionIndependent())256WasmSym->setWeak(true);257WasmSym->setExternal(true);258259// Currently both C++ exceptions and C longjmps have a single pointer type260// param. For C++ exceptions it is a pointer to an exception object, and for261// C longjmps it is pointer to a struct that contains a setjmp buffer and a262// longjmp return value. We may consider using multiple value parameters for263// longjmps later when multivalue support is ready.264wasm::ValType AddrType =265Subtarget.hasAddr64() ? wasm::ValType::I64 : wasm::ValType::I32;266Params.push_back(AddrType);267} else { // Function symbols268WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);269WebAssembly::getLibcallSignature(Subtarget, Name, Returns, Params);270}271auto Signature = OutContext.createWasmSignature();272Signature->Returns = std::move(Returns);273Signature->Params = std::move(Params);274WasmSym->setSignature(Signature);275276return WasmSym;277}278279void WebAssemblyAsmPrinter::emitSymbolType(const MCSymbolWasm *Sym) {280std::optional<wasm::WasmSymbolType> WasmTy = Sym->getType();281if (!WasmTy)282return;283284switch (*WasmTy) {285case wasm::WASM_SYMBOL_TYPE_GLOBAL:286getTargetStreamer()->emitGlobalType(Sym);287break;288case wasm::WASM_SYMBOL_TYPE_TAG:289getTargetStreamer()->emitTagType(Sym);290break;291case wasm::WASM_SYMBOL_TYPE_TABLE:292getTargetStreamer()->emitTableType(Sym);293break;294default:295break; // We only handle globals, tags and tables here296}297}298299void WebAssemblyAsmPrinter::emitDecls(const Module &M) {300if (signaturesEmitted)301return;302signaturesEmitted = true;303304// Normally symbols for globals get discovered as the MI gets lowered,305// but we need to know about them ahead of time. This will however,306// only find symbols that have been used. Unused symbols from globals will307// not be found here.308MachineModuleInfoWasm &MMIW = MMI->getObjFileInfo<MachineModuleInfoWasm>();309for (StringRef Name : MMIW.MachineSymbolsUsed) {310auto *WasmSym = cast<MCSymbolWasm>(getOrCreateWasmSymbol(Name));311if (WasmSym->isFunction()) {312// TODO(wvo): is there any case where this overlaps with the call to313// emitFunctionType in the loop below?314getTargetStreamer()->emitFunctionType(WasmSym);315}316}317318for (auto &It : OutContext.getSymbols()) {319// Emit .globaltype, .tagtype, or .tabletype declarations for extern320// declarations, i.e. those that have only been declared (but not defined)321// in the current module322auto Sym = cast_or_null<MCSymbolWasm>(It.getValue().Symbol);323if (Sym && !Sym->isDefined())324emitSymbolType(Sym);325}326327DenseSet<MCSymbol *> InvokeSymbols;328for (const auto &F : M) {329if (F.isIntrinsic())330continue;331332// Emit function type info for all functions. This will emit duplicate333// information for defined functions (which already have function type334// info emitted alongside their definition), but this is necessary in335// order to enable the single-pass WebAssemblyAsmTypeCheck to succeed.336SmallVector<MVT, 4> Results;337SmallVector<MVT, 4> Params;338computeSignatureVTs(F.getFunctionType(), &F, F, TM, Params, Results);339// At this point these MCSymbols may or may not have been created already340// and thus also contain a signature, but we need to get the signature341// anyway here in case it is an invoke that has not yet been created. We342// will discard it later if it turns out not to be necessary.343auto Signature = signatureFromMVTs(OutContext, Results, Params);344bool InvokeDetected = false;345auto *Sym = getMCSymbolForFunction(346&F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj,347Signature, InvokeDetected);348349// Multiple functions can be mapped to the same invoke symbol. For350// example, two IR functions '__invoke_void_i8*' and '__invoke_void_i32'351// are both mapped to '__invoke_vi'. We keep them in a set once we emit an352// Emscripten EH symbol so we don't emit the same symbol twice.353if (InvokeDetected && !InvokeSymbols.insert(Sym).second)354continue;355356Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);357if (!Sym->getSignature()) {358Sym->setSignature(Signature);359}360361getTargetStreamer()->emitFunctionType(Sym);362363if (F.hasFnAttribute("wasm-import-module")) {364StringRef Name =365F.getFnAttribute("wasm-import-module").getValueAsString();366Sym->setImportModule(OutContext.allocateString(Name));367getTargetStreamer()->emitImportModule(Sym, Name);368}369if (F.hasFnAttribute("wasm-import-name")) {370// If this is a converted Emscripten EH/SjLj symbol, we shouldn't use371// the original function name but the converted symbol name.372StringRef Name =373InvokeDetected374? Sym->getName()375: F.getFnAttribute("wasm-import-name").getValueAsString();376Sym->setImportName(OutContext.allocateString(Name));377getTargetStreamer()->emitImportName(Sym, Name);378}379380if (F.hasFnAttribute("wasm-export-name")) {381auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));382StringRef Name = F.getFnAttribute("wasm-export-name").getValueAsString();383Sym->setExportName(OutContext.allocateString(Name));384getTargetStreamer()->emitExportName(Sym, Name);385}386}387}388389void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {390// This is required to emit external declarations (like .functypes) when391// no functions are defined in the compilation unit and therefore,392// emitDecls() is not called until now.393emitDecls(M);394395// When a function's address is taken, a TABLE_INDEX relocation is emitted396// against the function symbol at the use site. However the relocation397// doesn't explicitly refer to the table. In the future we may want to398// define a new kind of reloc against both the function and the table, so399// that the linker can see that the function symbol keeps the table alive,400// but for now manually mark the table as live.401for (const auto &F : M) {402if (!F.isIntrinsic() && F.hasAddressTaken()) {403MCSymbolWasm *FunctionTable =404WebAssembly::getOrCreateFunctionTableSymbol(OutContext, Subtarget);405OutStreamer->emitSymbolAttribute(FunctionTable, MCSA_NoDeadStrip);406break;407}408}409410for (const auto &G : M.globals()) {411if (!G.hasInitializer() && G.hasExternalLinkage() &&412!WebAssembly::isWasmVarAddressSpace(G.getAddressSpace()) &&413G.getValueType()->isSized()) {414uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());415OutStreamer->emitELFSize(getSymbol(&G),416MCConstantExpr::create(Size, OutContext));417}418}419420if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) {421for (const Metadata *MD : Named->operands()) {422const auto *Tuple = dyn_cast<MDTuple>(MD);423if (!Tuple || Tuple->getNumOperands() != 2)424continue;425const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0));426const MDString *Contents = dyn_cast<MDString>(Tuple->getOperand(1));427if (!Name || !Contents)428continue;429430OutStreamer->pushSection();431std::string SectionName = (".custom_section." + Name->getString()).str();432MCSectionWasm *MySection =433OutContext.getWasmSection(SectionName, SectionKind::getMetadata());434OutStreamer->switchSection(MySection);435OutStreamer->emitBytes(Contents->getString());436OutStreamer->popSection();437}438}439440EmitProducerInfo(M);441EmitTargetFeatures(M);442EmitFunctionAttributes(M);443}444445void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {446llvm::SmallVector<std::pair<std::string, std::string>, 4> Languages;447if (const NamedMDNode *Debug = M.getNamedMetadata("llvm.dbg.cu")) {448llvm::SmallSet<StringRef, 4> SeenLanguages;449for (size_t I = 0, E = Debug->getNumOperands(); I < E; ++I) {450const auto *CU = cast<DICompileUnit>(Debug->getOperand(I));451StringRef Language = dwarf::LanguageString(CU->getSourceLanguage());452Language.consume_front("DW_LANG_");453if (SeenLanguages.insert(Language).second)454Languages.emplace_back(Language.str(), "");455}456}457458llvm::SmallVector<std::pair<std::string, std::string>, 4> Tools;459if (const NamedMDNode *Ident = M.getNamedMetadata("llvm.ident")) {460llvm::SmallSet<StringRef, 4> SeenTools;461for (size_t I = 0, E = Ident->getNumOperands(); I < E; ++I) {462const auto *S = cast<MDString>(Ident->getOperand(I)->getOperand(0));463std::pair<StringRef, StringRef> Field = S->getString().split("version");464StringRef Name = Field.first.trim();465StringRef Version = Field.second.trim();466if (SeenTools.insert(Name).second)467Tools.emplace_back(Name.str(), Version.str());468}469}470471int FieldCount = int(!Languages.empty()) + int(!Tools.empty());472if (FieldCount != 0) {473MCSectionWasm *Producers = OutContext.getWasmSection(474".custom_section.producers", SectionKind::getMetadata());475OutStreamer->pushSection();476OutStreamer->switchSection(Producers);477OutStreamer->emitULEB128IntValue(FieldCount);478for (auto &Producers : {std::make_pair("language", &Languages),479std::make_pair("processed-by", &Tools)}) {480if (Producers.second->empty())481continue;482OutStreamer->emitULEB128IntValue(strlen(Producers.first));483OutStreamer->emitBytes(Producers.first);484OutStreamer->emitULEB128IntValue(Producers.second->size());485for (auto &Producer : *Producers.second) {486OutStreamer->emitULEB128IntValue(Producer.first.size());487OutStreamer->emitBytes(Producer.first);488OutStreamer->emitULEB128IntValue(Producer.second.size());489OutStreamer->emitBytes(Producer.second);490}491}492OutStreamer->popSection();493}494}495496void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) {497struct FeatureEntry {498uint8_t Prefix;499std::string Name;500};501502// Read target features and linkage policies from module metadata503SmallVector<FeatureEntry, 4> EmittedFeatures;504auto EmitFeature = [&](std::string Feature) {505std::string MDKey = (StringRef("wasm-feature-") + Feature).str();506Metadata *Policy = M.getModuleFlag(MDKey);507if (Policy == nullptr)508return;509510FeatureEntry Entry;511Entry.Prefix = 0;512Entry.Name = Feature;513514if (auto *MD = cast<ConstantAsMetadata>(Policy))515if (auto *I = cast<ConstantInt>(MD->getValue()))516Entry.Prefix = I->getZExtValue();517518// Silently ignore invalid metadata519if (Entry.Prefix != wasm::WASM_FEATURE_PREFIX_USED &&520Entry.Prefix != wasm::WASM_FEATURE_PREFIX_REQUIRED &&521Entry.Prefix != wasm::WASM_FEATURE_PREFIX_DISALLOWED)522return;523524EmittedFeatures.push_back(Entry);525};526527for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {528EmitFeature(KV.Key);529}530// This pseudo-feature tells the linker whether shared memory would be safe531EmitFeature("shared-mem");532533// This is an "architecture", not a "feature", but we emit it as such for534// the benefit of tools like Binaryen and consistency with other producers.535// FIXME: Subtarget is null here, so can't Subtarget->hasAddr64() ?536if (M.getDataLayout().getPointerSize() == 8) {537// Can't use EmitFeature since "wasm-feature-memory64" is not a module538// flag.539EmittedFeatures.push_back({wasm::WASM_FEATURE_PREFIX_USED, "memory64"});540}541542if (EmittedFeatures.size() == 0)543return;544545// Emit features and linkage policies into the "target_features" section546MCSectionWasm *FeaturesSection = OutContext.getWasmSection(547".custom_section.target_features", SectionKind::getMetadata());548OutStreamer->pushSection();549OutStreamer->switchSection(FeaturesSection);550551OutStreamer->emitULEB128IntValue(EmittedFeatures.size());552for (auto &F : EmittedFeatures) {553OutStreamer->emitIntValue(F.Prefix, 1);554OutStreamer->emitULEB128IntValue(F.Name.size());555OutStreamer->emitBytes(F.Name);556}557558OutStreamer->popSection();559}560561void WebAssemblyAsmPrinter::EmitFunctionAttributes(Module &M) {562auto V = M.getNamedGlobal("llvm.global.annotations");563if (!V)564return;565566// Group all the custom attributes by name.567MapVector<StringRef, SmallVector<MCSymbol *, 4>> CustomSections;568const ConstantArray *CA = cast<ConstantArray>(V->getOperand(0));569for (Value *Op : CA->operands()) {570auto *CS = cast<ConstantStruct>(Op);571// The first field is a pointer to the annotated variable.572Value *AnnotatedVar = CS->getOperand(0)->stripPointerCasts();573// Only annotated functions are supported for now.574if (!isa<Function>(AnnotatedVar))575continue;576auto *F = cast<Function>(AnnotatedVar);577578// The second field is a pointer to a global annotation string.579auto *GV = cast<GlobalVariable>(CS->getOperand(1)->stripPointerCasts());580StringRef AnnotationString;581getConstantStringInfo(GV, AnnotationString);582auto *Sym = cast<MCSymbolWasm>(getSymbol(F));583CustomSections[AnnotationString].push_back(Sym);584}585586// Emit a custom section for each unique attribute.587for (const auto &[Name, Symbols] : CustomSections) {588MCSectionWasm *CustomSection = OutContext.getWasmSection(589".custom_section.llvm.func_attr.annotate." + Name, SectionKind::getMetadata());590OutStreamer->pushSection();591OutStreamer->switchSection(CustomSection);592593for (auto &Sym : Symbols) {594OutStreamer->emitValue(595MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_WASM_FUNCINDEX,596OutContext),5974);598}599OutStreamer->popSection();600}601}602603void WebAssemblyAsmPrinter::emitConstantPool() {604emitDecls(*MMI->getModule());605assert(MF->getConstantPool()->getConstants().empty() &&606"WebAssembly disables constant pools");607}608609void WebAssemblyAsmPrinter::emitJumpTableInfo() {610// Nothing to do; jump tables are incorporated into the instruction stream.611}612613void WebAssemblyAsmPrinter::emitFunctionBodyStart() {614const Function &F = MF->getFunction();615SmallVector<MVT, 1> ResultVTs;616SmallVector<MVT, 4> ParamVTs;617computeSignatureVTs(F.getFunctionType(), &F, F, TM, ParamVTs, ResultVTs);618619auto Signature = signatureFromMVTs(OutContext, ResultVTs, ParamVTs);620auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym);621WasmSym->setSignature(Signature);622WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);623624getTargetStreamer()->emitFunctionType(WasmSym);625626// Emit the function index.627if (MDNode *Idx = F.getMetadata("wasm.index")) {628assert(Idx->getNumOperands() == 1);629630getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant(631cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));632}633634SmallVector<wasm::ValType, 16> Locals;635valTypesFromMVTs(MFI->getLocals(), Locals);636getTargetStreamer()->emitLocal(Locals);637638AsmPrinter::emitFunctionBodyStart();639}640641void WebAssemblyAsmPrinter::emitInstruction(const MachineInstr *MI) {642LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');643WebAssembly_MC::verifyInstructionPredicates(MI->getOpcode(),644Subtarget->getFeatureBits());645646switch (MI->getOpcode()) {647case WebAssembly::ARGUMENT_i32:648case WebAssembly::ARGUMENT_i32_S:649case WebAssembly::ARGUMENT_i64:650case WebAssembly::ARGUMENT_i64_S:651case WebAssembly::ARGUMENT_f32:652case WebAssembly::ARGUMENT_f32_S:653case WebAssembly::ARGUMENT_f64:654case WebAssembly::ARGUMENT_f64_S:655case WebAssembly::ARGUMENT_v16i8:656case WebAssembly::ARGUMENT_v16i8_S:657case WebAssembly::ARGUMENT_v8i16:658case WebAssembly::ARGUMENT_v8i16_S:659case WebAssembly::ARGUMENT_v4i32:660case WebAssembly::ARGUMENT_v4i32_S:661case WebAssembly::ARGUMENT_v2i64:662case WebAssembly::ARGUMENT_v2i64_S:663case WebAssembly::ARGUMENT_v4f32:664case WebAssembly::ARGUMENT_v4f32_S:665case WebAssembly::ARGUMENT_v2f64:666case WebAssembly::ARGUMENT_v2f64_S:667case WebAssembly::ARGUMENT_v8f16:668case WebAssembly::ARGUMENT_v8f16_S:669// These represent values which are live into the function entry, so there's670// no instruction to emit.671break;672case WebAssembly::FALLTHROUGH_RETURN: {673// These instructions represent the implicit return at the end of a674// function body.675if (isVerbose()) {676OutStreamer->AddComment("fallthrough-return");677OutStreamer->addBlankLine();678}679break;680}681case WebAssembly::COMPILER_FENCE:682// This is a compiler barrier that prevents instruction reordering during683// backend compilation, and should not be emitted.684break;685default: {686WebAssemblyMCInstLower MCInstLowering(OutContext, *this);687MCInst TmpInst;688MCInstLowering.lower(MI, TmpInst);689EmitToStreamer(*OutStreamer, TmpInst);690break;691}692}693}694695bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,696unsigned OpNo,697const char *ExtraCode,698raw_ostream &OS) {699// First try the generic code, which knows about modifiers like 'c' and 'n'.700if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))701return false;702703if (!ExtraCode) {704const MachineOperand &MO = MI->getOperand(OpNo);705switch (MO.getType()) {706case MachineOperand::MO_Immediate:707OS << MO.getImm();708return false;709case MachineOperand::MO_Register:710// FIXME: only opcode that still contains registers, as required by711// MachineInstr::getDebugVariable().712assert(MI->getOpcode() == WebAssembly::INLINEASM);713OS << regToString(MO);714return false;715case MachineOperand::MO_GlobalAddress:716PrintSymbolOperand(MO, OS);717return false;718case MachineOperand::MO_ExternalSymbol:719GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI);720printOffset(MO.getOffset(), OS);721return false;722case MachineOperand::MO_MachineBasicBlock:723MO.getMBB()->getSymbol()->print(OS, MAI);724return false;725default:726break;727}728}729730return true;731}732733bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,734unsigned OpNo,735const char *ExtraCode,736raw_ostream &OS) {737// The current approach to inline asm is that "r" constraints are expressed738// as local indices, rather than values on the operand stack. This simplifies739// using "r" as it eliminates the need to push and pop the values in a740// particular order, however it also makes it impossible to have an "m"741// constraint. So we don't support it.742743return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);744}745746// Force static initialization.747extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmPrinter() {748RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32());749RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64());750}751752753