diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp | |
parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) |
Diffstat (limited to 'lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp')
-rw-r--r-- | lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp | 186 |
1 files changed, 150 insertions, 36 deletions
diff --git a/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index c4f03dfa7f9e..7f9d41da3978 100644 --- a/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -1,9 +1,8 @@ //===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// @@ -15,21 +14,27 @@ //===----------------------------------------------------------------------===// #include "WebAssemblyAsmPrinter.h" -#include "InstPrinter/WebAssemblyInstPrinter.h" +#include "MCTargetDesc/WebAssemblyInstPrinter.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "MCTargetDesc/WebAssemblyTargetStreamer.h" +#include "TargetInfo/WebAssemblyTargetInfo.h" #include "WebAssembly.h" #include "WebAssemblyMCInstLower.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblyRegisterInfo.h" +#include "WebAssemblyTargetMachine.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/BinaryFormat/Wasm.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Metadata.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCStreamer.h" @@ -38,10 +43,13 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" + using namespace llvm; #define DEBUG_TYPE "asm-printer" +extern cl::opt<bool> WasmKeepRegisters; + //===----------------------------------------------------------------------===// // Helpers. //===----------------------------------------------------------------------===// @@ -92,11 +100,11 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { if (F.isDeclarationForLinker() && !F.isIntrinsic()) { SmallVector<MVT, 4> Results; SmallVector<MVT, 4> Params; - ComputeSignatureVTs(F.getFunctionType(), F, TM, Params, Results); + computeSignatureVTs(F.getFunctionType(), F, TM, Params, Results); auto *Sym = cast<MCSymbolWasm>(getSymbol(&F)); Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); if (!Sym->getSignature()) { - auto Signature = SignatureFromMVTs(Results, Params); + auto Signature = signatureFromMVTs(Results, Params); Sym->setSignature(Signature.get()); addSignature(std::move(Signature)); } @@ -111,9 +119,16 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { F.hasFnAttribute("wasm-import-module")) { StringRef Name = F.getFnAttribute("wasm-import-module").getValueAsString(); - Sym->setModuleName(Name); + Sym->setImportModule(Name); getTargetStreamer()->emitImportModule(Sym, Name); } + if (TM.getTargetTriple().isOSBinFormatWasm() && + F.hasFnAttribute("wasm-import-name")) { + StringRef Name = + F.getFnAttribute("wasm-import-name").getValueAsString(); + Sym->setImportName(Name); + getTargetStreamer()->emitImportName(Sym, Name); + } } } @@ -129,7 +144,7 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { if (const NamedMDNode *Named = M.getNamedMetadata("wasm.custom_sections")) { for (const Metadata *MD : Named->operands()) { - const MDTuple *Tuple = dyn_cast<MDTuple>(MD); + const auto *Tuple = dyn_cast<MDTuple>(MD); if (!Tuple || Tuple->getNumOperands() != 2) continue; const MDString *Name = dyn_cast<MDString>(Tuple->getOperand(0)); @@ -139,13 +154,117 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { OutStreamer->PushSection(); std::string SectionName = (".custom_section." + Name->getString()).str(); - MCSectionWasm *mySection = + MCSectionWasm *MySection = OutContext.getWasmSection(SectionName, SectionKind::getMetadata()); - OutStreamer->SwitchSection(mySection); + OutStreamer->SwitchSection(MySection); OutStreamer->EmitBytes(Contents->getString()); OutStreamer->PopSection(); } } + + EmitProducerInfo(M); + EmitTargetFeatures(M); +} + +void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) { + llvm::SmallVector<std::pair<std::string, std::string>, 4> Languages; + if (const NamedMDNode *Debug = M.getNamedMetadata("llvm.dbg.cu")) { + llvm::SmallSet<StringRef, 4> SeenLanguages; + for (size_t I = 0, E = Debug->getNumOperands(); I < E; ++I) { + const auto *CU = cast<DICompileUnit>(Debug->getOperand(I)); + StringRef Language = dwarf::LanguageString(CU->getSourceLanguage()); + Language.consume_front("DW_LANG_"); + if (SeenLanguages.insert(Language).second) + Languages.emplace_back(Language.str(), ""); + } + } + + llvm::SmallVector<std::pair<std::string, std::string>, 4> Tools; + if (const NamedMDNode *Ident = M.getNamedMetadata("llvm.ident")) { + llvm::SmallSet<StringRef, 4> SeenTools; + for (size_t I = 0, E = Ident->getNumOperands(); I < E; ++I) { + const auto *S = cast<MDString>(Ident->getOperand(I)->getOperand(0)); + std::pair<StringRef, StringRef> Field = S->getString().split("version"); + StringRef Name = Field.first.trim(); + StringRef Version = Field.second.trim(); + if (SeenTools.insert(Name).second) + Tools.emplace_back(Name.str(), Version.str()); + } + } + + int FieldCount = int(!Languages.empty()) + int(!Tools.empty()); + if (FieldCount != 0) { + MCSectionWasm *Producers = OutContext.getWasmSection( + ".custom_section.producers", SectionKind::getMetadata()); + OutStreamer->PushSection(); + OutStreamer->SwitchSection(Producers); + OutStreamer->EmitULEB128IntValue(FieldCount); + for (auto &Producers : {std::make_pair("language", &Languages), + std::make_pair("processed-by", &Tools)}) { + if (Producers.second->empty()) + continue; + OutStreamer->EmitULEB128IntValue(strlen(Producers.first)); + OutStreamer->EmitBytes(Producers.first); + OutStreamer->EmitULEB128IntValue(Producers.second->size()); + for (auto &Producer : *Producers.second) { + OutStreamer->EmitULEB128IntValue(Producer.first.size()); + OutStreamer->EmitBytes(Producer.first); + OutStreamer->EmitULEB128IntValue(Producer.second.size()); + OutStreamer->EmitBytes(Producer.second); + } + } + OutStreamer->PopSection(); + } +} + +void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) { + struct FeatureEntry { + uint8_t Prefix; + StringRef Name; + }; + + // Read target features and linkage policies from module metadata + SmallVector<FeatureEntry, 4> EmittedFeatures; + for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { + std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str(); + Metadata *Policy = M.getModuleFlag(MDKey); + if (Policy == nullptr) + continue; + + FeatureEntry Entry; + Entry.Prefix = 0; + Entry.Name = KV.Key; + + if (auto *MD = cast<ConstantAsMetadata>(Policy)) + if (auto *I = cast<ConstantInt>(MD->getValue())) + Entry.Prefix = I->getZExtValue(); + + // Silently ignore invalid metadata + if (Entry.Prefix != wasm::WASM_FEATURE_PREFIX_USED && + Entry.Prefix != wasm::WASM_FEATURE_PREFIX_REQUIRED && + Entry.Prefix != wasm::WASM_FEATURE_PREFIX_DISALLOWED) + continue; + + EmittedFeatures.push_back(Entry); + } + + if (EmittedFeatures.size() == 0) + return; + + // Emit features and linkage policies into the "target_features" section + MCSectionWasm *FeaturesSection = OutContext.getWasmSection( + ".custom_section.target_features", SectionKind::getMetadata()); + OutStreamer->PushSection(); + OutStreamer->SwitchSection(FeaturesSection); + + OutStreamer->EmitULEB128IntValue(EmittedFeatures.size()); + for (auto &F : EmittedFeatures) { + OutStreamer->EmitIntValue(F.Prefix, 1); + OutStreamer->EmitULEB128IntValue(F.Name.size()); + OutStreamer->EmitBytes(F.Name); + } + + OutStreamer->PopSection(); } void WebAssemblyAsmPrinter::EmitConstantPool() { @@ -161,8 +280,8 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { const Function &F = MF->getFunction(); SmallVector<MVT, 1> ResultVTs; SmallVector<MVT, 4> ParamVTs; - ComputeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs); - auto Signature = SignatureFromMVTs(ResultVTs, ParamVTs); + computeSignatureVTs(F.getFunctionType(), F, TM, ParamVTs, ResultVTs); + auto Signature = signatureFromMVTs(ResultVTs, ParamVTs); auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym); WasmSym->setSignature(Signature.get()); addSignature(std::move(Signature)); @@ -180,7 +299,7 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { } SmallVector<wasm::ValType, 16> Locals; - ValTypesFromMVTs(MFI->getLocals(), Locals); + valTypesFromMVTs(MFI->getLocals(), Locals); getTargetStreamer()->emitLocal(Locals); AsmPrinter::EmitFunctionBodyStart(); @@ -250,34 +369,34 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { OutStreamer->AddBlankLine(); } break; + case WebAssembly::COMPILER_FENCE: + // This is a compiler barrier that prevents instruction reordering during + // backend compilation, and should not be emitted. + break; + case WebAssembly::EXTRACT_EXCEPTION_I32: + case WebAssembly::EXTRACT_EXCEPTION_I32_S: + // These are pseudo instructions that simulates popping values from stack. + // We print these only when we have -wasm-keep-registers on for assembly + // readability. + if (!WasmKeepRegisters) + break; + LLVM_FALLTHROUGH; default: { WebAssemblyMCInstLower MCInstLowering(OutContext, *this); MCInst TmpInst; - MCInstLowering.Lower(MI, TmpInst); + MCInstLowering.lower(MI, TmpInst); EmitToStreamer(*OutStreamer, TmpInst); break; } } } -const MCExpr *WebAssemblyAsmPrinter::lowerConstant(const Constant *CV) { - if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) - if (GV->getValueType()->isFunctionTy()) { - return MCSymbolRefExpr::create( - getSymbol(GV), MCSymbolRefExpr::VK_WebAssembly_FUNCTION, OutContext); - } - return AsmPrinter::lowerConstant(CV); -} - bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI, - unsigned OpNo, unsigned AsmVariant, + unsigned OpNo, const char *ExtraCode, raw_ostream &OS) { - if (AsmVariant != 0) - report_fatal_error("There are no defined alternate asm variants"); - // First try the generic code, which knows about modifiers like 'c' and 'n'. - if (!AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS)) + if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) return false; if (!ExtraCode) { @@ -293,8 +412,7 @@ bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI, OS << regToString(MO); return false; case MachineOperand::MO_GlobalAddress: - getSymbol(MO.getGlobal())->print(OS, MAI); - printOffset(MO.getOffset(), OS); + PrintSymbolOperand(MO, OS); return false; case MachineOperand::MO_ExternalSymbol: GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI); @@ -313,19 +431,15 @@ bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI, bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS) { - if (AsmVariant != 0) - report_fatal_error("There are no defined alternate asm variants"); - // The current approach to inline asm is that "r" constraints are expressed // as local indices, rather than values on the operand stack. This simplifies // using "r" as it eliminates the need to push and pop the values in a // particular order, however it also makes it impossible to have an "m" // constraint. So we don't support it. - return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant, ExtraCode, OS); + return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); } // Force static initialization. |