brintos

brintos / llvm-project-archived public Read only

0
0
Text · 28.1 KiB · 526420b Raw
761 lines · cpp
1//===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file contains a printer that converts from our internal11/// representation of machine-dependent LLVM code to the WebAssembly assembly12/// language.13///14//===----------------------------------------------------------------------===//15 16#include "WebAssemblyAsmPrinter.h"17#include "MCTargetDesc/WebAssemblyMCAsmInfo.h"18#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"19#include "MCTargetDesc/WebAssemblyTargetStreamer.h"20#include "TargetInfo/WebAssemblyTargetInfo.h"21#include "Utils/WebAssemblyTypeUtilities.h"22#include "WebAssembly.h"23#include "WebAssemblyMCInstLower.h"24#include "WebAssemblyMachineFunctionInfo.h"25#include "WebAssemblyRegisterInfo.h"26#include "WebAssemblyRuntimeLibcallSignatures.h"27#include "WebAssemblyTargetMachine.h"28#include "WebAssemblyUtilities.h"29#include "llvm/ADT/MapVector.h"30#include "llvm/ADT/SmallSet.h"31#include "llvm/ADT/StringExtras.h"32#include "llvm/Analysis/ValueTracking.h"33#include "llvm/BinaryFormat/Wasm.h"34#include "llvm/CodeGen/Analysis.h"35#include "llvm/CodeGen/AsmPrinter.h"36#include "llvm/CodeGen/MachineConstantPool.h"37#include "llvm/CodeGen/MachineInstr.h"38#include "llvm/CodeGen/MachineModuleInfoImpls.h"39#include "llvm/IR/DataLayout.h"40#include "llvm/IR/DebugInfoMetadata.h"41#include "llvm/IR/GlobalVariable.h"42#include "llvm/IR/Metadata.h"43#include "llvm/IR/Module.h"44#include "llvm/MC/MCContext.h"45#include "llvm/MC/MCSectionWasm.h"46#include "llvm/MC/MCStreamer.h"47#include "llvm/MC/MCSymbol.h"48#include "llvm/MC/MCSymbolWasm.h"49#include "llvm/MC/TargetRegistry.h"50#include "llvm/Support/Compiler.h"51#include "llvm/Support/Debug.h"52#include "llvm/Support/raw_ostream.h"53 54using namespace llvm;55 56#define DEBUG_TYPE "asm-printer"57 58extern cl::opt<bool> WasmKeepRegisters;59 60//===----------------------------------------------------------------------===//61// Helpers.62//===----------------------------------------------------------------------===//63 64MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {65  const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();66  const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);67  for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16,68                MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64, MVT::v8f16})69    if (TRI->isTypeLegalForClass(*TRC, T))70      return T;71  LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo);72  llvm_unreachable("Unknown register type");73  return MVT::Other;74}75 76std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {77  Register RegNo = MO.getReg();78  assert(RegNo.isVirtual() &&79         "Unlowered physical register encountered during assembly printing");80  assert(!MFI->isVRegStackified(RegNo));81  unsigned WAReg = MFI->getWAReg(RegNo);82  assert(WAReg != WebAssembly::UnusedReg);83  return '$' + utostr(WAReg);84}85 86WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {87  MCTargetStreamer *TS = OutStreamer->getTargetStreamer();88  return static_cast<WebAssemblyTargetStreamer *>(TS);89}90 91// Emscripten exception handling helpers92//93// This converts invoke names generated by LowerEmscriptenEHSjLj to real names94// that are expected by JavaScript glue code. The invoke names generated by95// Emscripten JS glue code are based on their argument and return types; for96// example, for a function that takes an i32 and returns nothing, it is97// 'invoke_vi'. But the format of invoke generated by LowerEmscriptenEHSjLj pass98// contains a mangled string generated from their IR types, for example,99// "__invoke_void_%struct.mystruct*_int", because final wasm types are not100// available in the IR pass. So we convert those names to the form that101// Emscripten JS code expects.102//103// Refer to LowerEmscriptenEHSjLj pass for more details.104 105// Returns true if the given function name is an invoke name generated by106// LowerEmscriptenEHSjLj pass.107static bool isEmscriptenInvokeName(StringRef Name) {108  if (Name.front() == '"' && Name.back() == '"')109    Name = Name.substr(1, Name.size() - 2);110  return Name.starts_with("__invoke_");111}112 113// Returns a character that represents the given wasm value type in invoke114// signatures.115static char getInvokeSig(wasm::ValType VT) {116  switch (VT) {117  case wasm::ValType::I32:118    return 'i';119  case wasm::ValType::I64:120    return 'j';121  case wasm::ValType::F32:122    return 'f';123  case wasm::ValType::F64:124    return 'd';125  case wasm::ValType::V128:126    return 'V';127  case wasm::ValType::FUNCREF:128    return 'F';129  case wasm::ValType::EXTERNREF:130    return 'X';131  case wasm::ValType::EXNREF:132    return 'E';133  default:134    llvm_unreachable("Unhandled wasm::ValType enum");135  }136}137 138// Given the wasm signature, generate the invoke name in the format JS glue code139// expects.140static std::string getEmscriptenInvokeSymbolName(wasm::WasmSignature *Sig) {141  assert(Sig->Returns.size() <= 1);142  std::string Ret = "invoke_";143  if (!Sig->Returns.empty())144    for (auto VT : Sig->Returns)145      Ret += getInvokeSig(VT);146  else147    Ret += 'v';148  // Invokes' first argument is a pointer to the original function, so skip it149  for (unsigned I = 1, E = Sig->Params.size(); I < E; I++)150    Ret += getInvokeSig(Sig->Params[I]);151  return Ret;152}153 154//===----------------------------------------------------------------------===//155// WebAssemblyAsmPrinter Implementation.156//===----------------------------------------------------------------------===//157 158MCSymbolWasm *WebAssemblyAsmPrinter::getMCSymbolForFunction(159    const Function *F, wasm::WasmSignature *Sig, bool &InvokeDetected) {160  MCSymbolWasm *WasmSym = nullptr;161 162  const bool EnableEmEH =163      WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj;164  if (EnableEmEH && isEmscriptenInvokeName(F->getName())) {165    assert(Sig);166    InvokeDetected = true;167    if (Sig->Returns.size() > 1) {168      std::string Msg =169          "Emscripten EH/SjLj does not support multivalue returns: " +170          std::string(F->getName()) + ": " +171          WebAssembly::signatureToString(Sig);172      report_fatal_error(Twine(Msg));173    }174    WasmSym = static_cast<MCSymbolWasm *>(175        GetExternalSymbolSymbol(getEmscriptenInvokeSymbolName(Sig)));176  } else {177    WasmSym = static_cast<MCSymbolWasm *>(getSymbol(F));178  }179  return WasmSym;180}181 182void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {183  if (!WebAssembly::isWasmVarAddressSpace(GV->getAddressSpace())) {184    AsmPrinter::emitGlobalVariable(GV);185    return;186  }187 188  assert(!GV->isThreadLocal());189  auto *Sym = static_cast<MCSymbolWasm *>(getSymbol(GV));190  if (!Sym->getType()) {191    SmallVector<MVT, 1> VTs;192    Type *GlobalVT = GV->getValueType();193    if (Subtarget) {194      // Subtarget is only set when a function is defined, because195      // each function can declare a different subtarget. For example,196      // on ARM a compilation unit might have a function on ARM and197      // another on Thumb. Therefore only if Subtarget is non-null we198      // can actually calculate the legal VTs.199      const WebAssemblyTargetLowering &TLI = *Subtarget->getTargetLowering();200      computeLegalValueVTs(TLI, GV->getParent()->getContext(),201                           GV->getDataLayout(), GlobalVT, VTs);202    }203    WebAssembly::wasmSymbolSetType(Sym, GlobalVT, VTs);204  }205 206  emitVisibility(Sym, GV->getVisibility(), !GV->isDeclaration());207  emitSymbolType(Sym);208  if (GV->hasInitializer()) {209    assert(getSymbolPreferLocal(*GV) == Sym);210    emitLinkage(GV, Sym);211    OutStreamer->emitLabel(Sym);212    // TODO: Actually emit the initializer value.  Otherwise the global has the213    // default value for its type (0, ref.null, etc).214    OutStreamer->addBlankLine();215  }216}217 218MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) {219  auto *WasmSym = static_cast<MCSymbolWasm *>(GetExternalSymbolSymbol(Name));220  // May be called multiple times, so early out.221  if (WasmSym->getType())222    return WasmSym;223 224  const WebAssemblySubtarget &Subtarget = getSubtarget();225 226  // Except for certain known symbols, all symbols used by CodeGen are227  // functions. It's OK to hardcode knowledge of specific symbols here; this228  // method is precisely there for fetching the signatures of known229  // Clang-provided symbols.230  if (Name == "__stack_pointer" || Name == "__tls_base" ||231      Name == "__memory_base" || Name == "__table_base" ||232      Name == "__tls_size" || Name == "__tls_align") {233    bool Mutable =234        Name == "__stack_pointer" || Name == "__tls_base";235    WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);236    WasmSym->setGlobalType(wasm::WasmGlobalType{237        uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64238                                      : wasm::WASM_TYPE_I32),239        Mutable});240    return WasmSym;241  }242 243  if (Name.starts_with("GCC_except_table")) {244    WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA);245    return WasmSym;246  }247 248  SmallVector<wasm::ValType, 4> Returns;249  SmallVector<wasm::ValType, 4> Params;250  if (Name == "__cpp_exception" || Name == "__c_longjmp") {251    WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);252    WasmSym->setExternal(true);253 254    // Currently both C++ exceptions and C longjmps have a single pointer type255    // param. For C++ exceptions it is a pointer to an exception object, and for256    // C longjmps it is pointer to a struct that contains a setjmp buffer and a257    // longjmp return value. We may consider using multiple value parameters for258    // longjmps later when multivalue support is ready.259    wasm::ValType AddrType =260        Subtarget.hasAddr64() ? wasm::ValType::I64 : wasm::ValType::I32;261    Params.push_back(AddrType);262  } else { // Function symbols263    WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);264    WebAssembly::getLibcallSignature(Subtarget, Name, Returns, Params);265  }266  auto Signature = OutContext.createWasmSignature();267  Signature->Returns = std::move(Returns);268  Signature->Params = std::move(Params);269  WasmSym->setSignature(Signature);270 271  return WasmSym;272}273 274void WebAssemblyAsmPrinter::emitSymbolType(const MCSymbolWasm *Sym) {275  std::optional<wasm::WasmSymbolType> WasmTy = Sym->getType();276  if (!WasmTy)277    return;278 279  switch (*WasmTy) {280  case wasm::WASM_SYMBOL_TYPE_GLOBAL:281    getTargetStreamer()->emitGlobalType(Sym);282    break;283  case wasm::WASM_SYMBOL_TYPE_TAG:284    getTargetStreamer()->emitTagType(Sym);285    break;286  case wasm::WASM_SYMBOL_TYPE_TABLE:287    getTargetStreamer()->emitTableType(Sym);288    break;289  default:290    break; // We only handle globals, tags and tables here291  }292}293 294void WebAssemblyAsmPrinter::emitDecls(const Module &M) {295  if (signaturesEmitted)296    return;297  signaturesEmitted = true;298 299  // Normally symbols for globals get discovered as the MI gets lowered,300  // but we need to know about them ahead of time. This will however,301  // only find symbols that have been used. Unused symbols from globals will302  // not be found here.303  MachineModuleInfoWasm &MMIW = MMI->getObjFileInfo<MachineModuleInfoWasm>();304  for (StringRef Name : MMIW.MachineSymbolsUsed) {305    auto *WasmSym = static_cast<MCSymbolWasm *>(getOrCreateWasmSymbol(Name));306    if (WasmSym->isFunction()) {307      // TODO(wvo): is there any case where this overlaps with the call to308      // emitFunctionType in the loop below?309      getTargetStreamer()->emitFunctionType(WasmSym);310    }311  }312 313  for (auto &It : OutContext.getSymbols()) {314    // Emit .globaltype, .tagtype, or .tabletype declarations for extern315    // declarations, i.e. those that have only been declared (but not defined)316    // in the current module317    auto Sym = static_cast<MCSymbolWasm *>(It.getValue().Symbol);318    if (Sym && !Sym->isDefined())319      emitSymbolType(Sym);320  }321 322  DenseSet<MCSymbol *> InvokeSymbols;323  for (const auto &F : M) {324    if (F.isIntrinsic())325      continue;326 327    // Emit function type info for all functions. This will emit duplicate328    // information for defined functions (which already have function type329    // info emitted alongside their definition), but this is necessary in330    // order to enable the single-pass WebAssemblyAsmTypeCheck to succeed.331    SmallVector<MVT, 4> Results;332    SmallVector<MVT, 4> Params;333    computeSignatureVTs(F.getFunctionType(), &F, F, TM, Params, Results);334    // At this point these MCSymbols may or may not have been created already335    // and thus also contain a signature, but we need to get the signature336    // anyway here in case it is an invoke that has not yet been created. We337    // will discard it later if it turns out not to be necessary.338    auto Signature = signatureFromMVTs(OutContext, Results, Params);339    bool InvokeDetected = false;340    auto *Sym = getMCSymbolForFunction(&F, Signature, InvokeDetected);341 342    // Multiple functions can be mapped to the same invoke symbol. For343    // example, two IR functions '__invoke_void_i8*' and '__invoke_void_i32'344    // are both mapped to '__invoke_vi'. We keep them in a set once we emit an345    // Emscripten EH symbol so we don't emit the same symbol twice.346    if (InvokeDetected && !InvokeSymbols.insert(Sym).second)347      continue;348 349    Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);350    if (!Sym->getSignature()) {351      Sym->setSignature(Signature);352    }353 354    getTargetStreamer()->emitFunctionType(Sym);355 356    if (F.hasFnAttribute("wasm-import-module")) {357      StringRef Name =358          F.getFnAttribute("wasm-import-module").getValueAsString();359      Sym->setImportModule(OutContext.allocateString(Name));360      getTargetStreamer()->emitImportModule(Sym, Name);361    }362    if (F.hasFnAttribute("wasm-import-name")) {363      // If this is a converted Emscripten EH/SjLj symbol, we shouldn't use364      // the original function name but the converted symbol name.365      StringRef Name =366          InvokeDetected367              ? Sym->getName()368              : F.getFnAttribute("wasm-import-name").getValueAsString();369      Sym->setImportName(OutContext.allocateString(Name));370      getTargetStreamer()->emitImportName(Sym, Name);371    }372 373    if (F.hasFnAttribute("wasm-export-name")) {374      auto *Sym = static_cast<MCSymbolWasm *>(getSymbol(&F));375      StringRef Name = F.getFnAttribute("wasm-export-name").getValueAsString();376      Sym->setExportName(OutContext.allocateString(Name));377      getTargetStreamer()->emitExportName(Sym, Name);378    }379  }380}381 382void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {383  // This is required to emit external declarations (like .functypes) when384  // no functions are defined in the compilation unit and therefore,385  // emitDecls() is not called until now.386  emitDecls(M);387 388  // When a function's address is taken, a TABLE_INDEX relocation is emitted389  // against the function symbol at the use site.  However the relocation390  // doesn't explicitly refer to the table.  In the future we may want to391  // define a new kind of reloc against both the function and the table, so392  // that the linker can see that the function symbol keeps the table alive,393  // but for now manually mark the table as live.394  for (const auto &F : M) {395    if (!F.isIntrinsic() && F.hasAddressTaken()) {396      MCSymbolWasm *FunctionTable =397          WebAssembly::getOrCreateFunctionTableSymbol(OutContext, Subtarget);398      OutStreamer->emitSymbolAttribute(FunctionTable, MCSA_NoDeadStrip);399      break;400    }401  }402 403  for (const auto &G : M.globals()) {404    if (!G.hasInitializer() && G.hasExternalLinkage() &&405        !WebAssembly::isWasmVarAddressSpace(G.getAddressSpace()) &&406        G.getValueType()->isSized()) {407      uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());408      OutStreamer->emitELFSize(getSymbol(&G),409                               MCConstantExpr::create(Size, OutContext));410    }411  }412 413  if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) {414    for (const Metadata *MD : Named->operands()) {415      const auto *Tuple = dyn_cast<MDTuple>(MD);416      if (!Tuple || Tuple->getNumOperands() != 2)417        continue;418      const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0));419      const MDString *Contents = dyn_cast<MDString>(Tuple->getOperand(1));420      if (!Name || !Contents)421        continue;422 423      OutStreamer->pushSection();424      std::string SectionName = (".custom_section." + Name->getString()).str();425      MCSectionWasm *MySection =426          OutContext.getWasmSection(SectionName, SectionKind::getMetadata());427      OutStreamer->switchSection(MySection);428      OutStreamer->emitBytes(Contents->getString());429      OutStreamer->popSection();430    }431  }432 433  EmitProducerInfo(M);434  EmitTargetFeatures(M);435  EmitFunctionAttributes(M);436}437 438void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {439  llvm::SmallVector<std::pair<std::string, std::string>, 4> Languages;440  if (const NamedMDNode *Debug = M.getNamedMetadata("llvm.dbg.cu")) {441    llvm::SmallSet<StringRef, 4> SeenLanguages;442    for (size_t I = 0, E = Debug->getNumOperands(); I < E; ++I) {443      const auto *CU = cast<DICompileUnit>(Debug->getOperand(I));444      StringRef Language =445          dwarf::LanguageString(CU->getSourceLanguage().getUnversionedName());446 447      Language.consume_front("DW_LANG_");448      if (SeenLanguages.insert(Language).second)449        Languages.emplace_back(Language.str(), "");450    }451  }452 453  llvm::SmallVector<std::pair<std::string, std::string>, 4> Tools;454  if (const NamedMDNode *Ident = M.getNamedMetadata("llvm.ident")) {455    llvm::SmallSet<StringRef, 4> SeenTools;456    for (size_t I = 0, E = Ident->getNumOperands(); I < E; ++I) {457      const auto *S = cast<MDString>(Ident->getOperand(I)->getOperand(0));458      std::pair<StringRef, StringRef> Field = S->getString().split("version");459      StringRef Name = Field.first.trim();460      StringRef Version = Field.second.trim();461      if (SeenTools.insert(Name).second)462        Tools.emplace_back(Name.str(), Version.str());463    }464  }465 466  int FieldCount = int(!Languages.empty()) + int(!Tools.empty());467  if (FieldCount != 0) {468    MCSectionWasm *Producers = OutContext.getWasmSection(469        ".custom_section.producers", SectionKind::getMetadata());470    OutStreamer->pushSection();471    OutStreamer->switchSection(Producers);472    OutStreamer->emitULEB128IntValue(FieldCount);473    for (auto &Producers : {std::make_pair("language", &Languages),474            std::make_pair("processed-by", &Tools)}) {475      if (Producers.second->empty())476        continue;477      OutStreamer->emitULEB128IntValue(strlen(Producers.first));478      OutStreamer->emitBytes(Producers.first);479      OutStreamer->emitULEB128IntValue(Producers.second->size());480      for (auto &Producer : *Producers.second) {481        OutStreamer->emitULEB128IntValue(Producer.first.size());482        OutStreamer->emitBytes(Producer.first);483        OutStreamer->emitULEB128IntValue(Producer.second.size());484        OutStreamer->emitBytes(Producer.second);485      }486    }487    OutStreamer->popSection();488  }489}490 491void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) {492  struct FeatureEntry {493    uint8_t Prefix;494    std::string Name;495  };496 497  // Read target features and linkage policies from module metadata498  SmallVector<FeatureEntry, 4> EmittedFeatures;499  auto EmitFeature = [&](std::string Feature) {500    std::string MDKey = (StringRef("wasm-feature-") + Feature).str();501    Metadata *Policy = M.getModuleFlag(MDKey);502    if (Policy == nullptr)503      return;504 505    FeatureEntry Entry;506    Entry.Prefix = 0;507    Entry.Name = Feature;508 509    if (auto *MD = cast<ConstantAsMetadata>(Policy))510      if (auto *I = cast<ConstantInt>(MD->getValue()))511        Entry.Prefix = I->getZExtValue();512 513    // Silently ignore invalid metadata514    if (Entry.Prefix != wasm::WASM_FEATURE_PREFIX_USED &&515        Entry.Prefix != wasm::WASM_FEATURE_PREFIX_DISALLOWED)516      return;517 518    EmittedFeatures.push_back(Entry);519  };520 521  for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {522    EmitFeature(KV.Key);523  }524  // This pseudo-feature tells the linker whether shared memory would be safe525  EmitFeature("shared-mem");526 527  // This is an "architecture", not a "feature", but we emit it as such for528  // the benefit of tools like Binaryen and consistency with other producers.529  // FIXME: Subtarget is null here, so can't Subtarget->hasAddr64() ?530  if (M.getDataLayout().getPointerSize() == 8) {531    // Can't use EmitFeature since "wasm-feature-memory64" is not a module532    // flag.533    EmittedFeatures.push_back({wasm::WASM_FEATURE_PREFIX_USED, "memory64"});534  }535 536  if (EmittedFeatures.size() == 0)537    return;538 539  // Emit features and linkage policies into the "target_features" section540  MCSectionWasm *FeaturesSection = OutContext.getWasmSection(541      ".custom_section.target_features", SectionKind::getMetadata());542  OutStreamer->pushSection();543  OutStreamer->switchSection(FeaturesSection);544 545  OutStreamer->emitULEB128IntValue(EmittedFeatures.size());546  for (auto &F : EmittedFeatures) {547    OutStreamer->emitIntValue(F.Prefix, 1);548    OutStreamer->emitULEB128IntValue(F.Name.size());549    OutStreamer->emitBytes(F.Name);550  }551 552  OutStreamer->popSection();553}554 555void WebAssemblyAsmPrinter::EmitFunctionAttributes(Module &M) {556  auto V = M.getNamedGlobal("llvm.global.annotations");557  if (!V)558    return;559 560  // Group all the custom attributes by name.561  MapVector<StringRef, SmallVector<MCSymbol *, 4>> CustomSections;562  const ConstantArray *CA = cast<ConstantArray>(V->getOperand(0));563  for (Value *Op : CA->operands()) {564    auto *CS = cast<ConstantStruct>(Op);565    // The first field is a pointer to the annotated variable.566    Value *AnnotatedVar = CS->getOperand(0)->stripPointerCasts();567    // Only annotated functions are supported for now.568    if (!isa<Function>(AnnotatedVar))569      continue;570    auto *F = cast<Function>(AnnotatedVar);571 572    // The second field is a pointer to a global annotation string.573    auto *GV = cast<GlobalVariable>(CS->getOperand(1)->stripPointerCasts());574    StringRef AnnotationString;575    getConstantStringInfo(GV, AnnotationString);576    auto *Sym = static_cast<MCSymbolWasm *>(getSymbol(F));577    CustomSections[AnnotationString].push_back(Sym);578  }579 580  // Emit a custom section for each unique attribute.581  for (const auto &[Name, Symbols] : CustomSections) {582    MCSectionWasm *CustomSection = OutContext.getWasmSection(583        ".custom_section.llvm.func_attr.annotate." + Name, SectionKind::getMetadata());584    OutStreamer->pushSection();585    OutStreamer->switchSection(CustomSection);586 587    for (auto &Sym : Symbols) {588      OutStreamer->emitValue(589          MCSymbolRefExpr::create(Sym, WebAssembly::S_FUNCINDEX, OutContext),590          4);591    }592    OutStreamer->popSection();593  }594}595 596void WebAssemblyAsmPrinter::emitConstantPool() {597  emitDecls(*MMI->getModule());598  assert(MF->getConstantPool()->getConstants().empty() &&599         "WebAssembly disables constant pools");600}601 602void WebAssemblyAsmPrinter::emitJumpTableInfo() {603  // Nothing to do; jump tables are incorporated into the instruction stream.604}605 606void WebAssemblyAsmPrinter::emitFunctionBodyStart() {607  const Function &F = MF->getFunction();608  SmallVector<MVT, 1> ResultVTs;609  SmallVector<MVT, 4> ParamVTs;610  computeSignatureVTs(F.getFunctionType(), &F, F, TM, ParamVTs, ResultVTs);611 612  auto Signature = signatureFromMVTs(OutContext, ResultVTs, ParamVTs);613  auto *WasmSym = static_cast<MCSymbolWasm *>(CurrentFnSym);614  WasmSym->setSignature(Signature);615  WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);616 617  getTargetStreamer()->emitFunctionType(WasmSym);618 619  // Emit the function index.620  if (MDNode *Idx = F.getMetadata("wasm.index")) {621    assert(Idx->getNumOperands() == 1);622 623    getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant(624        cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));625  }626 627  SmallVector<wasm::ValType, 16> Locals;628  valTypesFromMVTs(MFI->getLocals(), Locals);629  getTargetStreamer()->emitLocal(Locals);630 631  AsmPrinter::emitFunctionBodyStart();632}633 634void WebAssemblyAsmPrinter::emitInstruction(const MachineInstr *MI) {635  LLVM_DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');636  WebAssembly_MC::verifyInstructionPredicates(MI->getOpcode(),637                                              Subtarget->getFeatureBits());638 639  switch (MI->getOpcode()) {640  case WebAssembly::ARGUMENT_i32:641  case WebAssembly::ARGUMENT_i32_S:642  case WebAssembly::ARGUMENT_i64:643  case WebAssembly::ARGUMENT_i64_S:644  case WebAssembly::ARGUMENT_f32:645  case WebAssembly::ARGUMENT_f32_S:646  case WebAssembly::ARGUMENT_f64:647  case WebAssembly::ARGUMENT_f64_S:648  case WebAssembly::ARGUMENT_v16i8:649  case WebAssembly::ARGUMENT_v16i8_S:650  case WebAssembly::ARGUMENT_v8i16:651  case WebAssembly::ARGUMENT_v8i16_S:652  case WebAssembly::ARGUMENT_v4i32:653  case WebAssembly::ARGUMENT_v4i32_S:654  case WebAssembly::ARGUMENT_v2i64:655  case WebAssembly::ARGUMENT_v2i64_S:656  case WebAssembly::ARGUMENT_v4f32:657  case WebAssembly::ARGUMENT_v4f32_S:658  case WebAssembly::ARGUMENT_v2f64:659  case WebAssembly::ARGUMENT_v2f64_S:660  case WebAssembly::ARGUMENT_v8f16:661  case WebAssembly::ARGUMENT_v8f16_S:662    // These represent values which are live into the function entry, so there's663    // no instruction to emit.664    break;665  case WebAssembly::FALLTHROUGH_RETURN: {666    // These instructions represent the implicit return at the end of a667    // function body.668    if (isVerbose()) {669      OutStreamer->AddComment("fallthrough-return");670      OutStreamer->addBlankLine();671    }672    break;673  }674  case WebAssembly::COMPILER_FENCE:675    // This is a compiler barrier that prevents instruction reordering during676    // backend compilation, and should not be emitted.677    break;678  case WebAssembly::CATCH:679  case WebAssembly::CATCH_S:680  case WebAssembly::CATCH_REF:681  case WebAssembly::CATCH_REF_S:682  case WebAssembly::CATCH_ALL:683  case WebAssembly::CATCH_ALL_S:684  case WebAssembly::CATCH_ALL_REF:685  case WebAssembly::CATCH_ALL_REF_S:686    // These are pseudo instructions to represent catch clauses in try_table687    // instruction to simulate block return values.688    break;689  default: {690    WebAssemblyMCInstLower MCInstLowering(OutContext, *this);691    MCInst TmpInst;692    MCInstLowering.lower(MI, TmpInst);693    EmitToStreamer(*OutStreamer, TmpInst);694    break;695  }696  }697}698 699bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,700                                            unsigned OpNo,701                                            const char *ExtraCode,702                                            raw_ostream &OS) {703  // First try the generic code, which knows about modifiers like 'c' and 'n'.704  if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))705    return false;706 707  if (!ExtraCode) {708    const MachineOperand &MO = MI->getOperand(OpNo);709    switch (MO.getType()) {710    case MachineOperand::MO_Immediate:711      OS << MO.getImm();712      return false;713    case MachineOperand::MO_Register:714      // FIXME: only opcode that still contains registers, as required by715      // MachineInstr::getDebugVariable().716      assert(MI->getOpcode() == WebAssembly::INLINEASM);717      OS << regToString(MO);718      return false;719    case MachineOperand::MO_GlobalAddress:720      PrintSymbolOperand(MO, OS);721      return false;722    case MachineOperand::MO_ExternalSymbol:723      GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI);724      printOffset(MO.getOffset(), OS);725      return false;726    case MachineOperand::MO_MachineBasicBlock:727      MO.getMBB()->getSymbol()->print(OS, MAI);728      return false;729    default:730      break;731    }732  }733 734  return true;735}736 737bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,738                                                  unsigned OpNo,739                                                  const char *ExtraCode,740                                                  raw_ostream &OS) {741  // The current approach to inline asm is that "r" constraints are expressed742  // as local indices, rather than values on the operand stack. This simplifies743  // using "r" as it eliminates the need to push and pop the values in a744  // particular order, however it also makes it impossible to have an "m"745  // constraint. So we don't support it.746 747  return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);748}749 750char WebAssemblyAsmPrinter::ID = 0;751 752INITIALIZE_PASS(WebAssemblyAsmPrinter, "webassembly-asm-printer",753                "WebAssembly Assmebly Printer", false, false)754 755// Force static initialization.756extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void757LLVMInitializeWebAssemblyAsmPrinter() {758  RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32());759  RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64());760}761