diff --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h --- a/lld/wasm/InputFiles.h +++ b/lld/wasm/InputFiles.h @@ -98,7 +98,6 @@ const WasmSection *CodeSection = nullptr; const WasmSection *DataSection = nullptr; - const WasmSection *ProducersSection = nullptr; // Maps input type indices to output type indices std::vector TypeMap; diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -239,8 +239,6 @@ CustomSections.emplace_back(make(Section, this)); CustomSections.back()->setRelocations(Section.Relocations); CustomSectionsByIndex[SectionIndex] = CustomSections.back(); - if (Section.Name == "producers") - ProducersSection = &Section; } SectionIndex++; } diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -20,6 +20,7 @@ #include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/BinaryFormat/Wasm.h" @@ -66,6 +67,7 @@ void createCtorFunction(); void calculateInitFunctions(); void assignIndexes(); + void calculateTargetFeatures(); void calculateImports(); void calculateExports(); void calculateCustomSections(); @@ -97,6 +99,7 @@ void createLinkingSection(); void createNameSection(); void createProducersSection(); + void createTargetFeaturesSection(); void writeHeader(); void writeSections(); @@ -127,6 +130,7 @@ llvm::StringMap> CustomSectionMapping; llvm::StringMap CustomSectionSymbols; + llvm::SmallSet TargetFeatures; // Elements that are used to construct the final output std::string Header; @@ -339,7 +343,7 @@ // These custom sections are known the linker and synthesized rather than // blindly copied if (Name == "linking" || Name == "name" || Name == "producers" || - Name.startswith("reloc.")) + Name == "target_features" || Name.startswith("reloc.")) continue; // .. or it is a debug section if (StripDebug && Name.startswith(".debug_")) @@ -694,6 +698,23 @@ } } +void Writer::createTargetFeaturesSection() { + if (TargetFeatures.size() == 0) + return; + + SmallVector Emitted(TargetFeatures.begin(), + TargetFeatures.end()); + std::sort(Emitted.begin(), Emitted.end()); + SyntheticSection *Section = + createSyntheticSection(WASM_SEC_CUSTOM, "target_features"); + auto &OS = Section->getStream(); + writeUleb128(OS, Emitted.size(), "feature count"); + for (auto &Feature : Emitted) { + writeU8(OS, WASM_FEATURE_PREFIX_USED, "feature used prefix"); + writeStr(OS, Feature, "feature name"); + } +} + void Writer::writeHeader() { memcpy(Buffer->getBufferStart(), Header.data(), Header.size()); } @@ -837,8 +858,10 @@ if (!Config->StripDebug && !Config->StripAll) createNameSection(); - if (!Config->StripAll) + if (!Config->StripAll) { createProducersSection(); + createTargetFeaturesSection(); + } for (OutputSection *S : OutputSections) { S->setOffset(FileSize); @@ -847,6 +870,48 @@ } } +void Writer::calculateTargetFeatures() { + SmallSet Required; + SmallSet Disallowed; + + // Find the sets of used, required, and disallowed features + for (ObjFile *File : Symtab->ObjectFiles) { + for (auto &Feature : File->getWasmObj()->getTargetFeatures()) { + switch (Feature.Prefix) { + case WASM_FEATURE_PREFIX_USED: + TargetFeatures.insert(Feature.Name); + break; + case WASM_FEATURE_PREFIX_REQUIRED: + TargetFeatures.insert(Feature.Name); + Required.insert(Feature.Name); + break; + case WASM_FEATURE_PREFIX_DISALLOWED: + Disallowed.insert(Feature.Name); + break; + default: + error("Unrecognized feature policy prefix " + + std::to_string(Feature.Prefix)); + } + } + } + + // Validate the required and disallowed constraints for each file + for (ObjFile *File : Symtab->ObjectFiles) { + SmallSet ObjectFeatures; + for (auto &Feature : File->getWasmObj()->getTargetFeatures()) { + if (Feature.Prefix == WASM_FEATURE_PREFIX_DISALLOWED) + continue; + ObjectFeatures.insert(Feature.Name); + if (Disallowed.count(Feature.Name)) + error("Target feature \"" + Feature.Name + "\" is disallowed"); + } + for (auto &Feature : Required) { + if (!ObjectFeatures.count(Feature)) + error(Twine("Missing required target feature \"") + Feature + "\""); + } + } +} + void Writer::calculateImports() { for (Symbol *Sym : Symtab->getSymbols()) { if (!Sym->isUndefined()) @@ -1199,6 +1264,8 @@ if (!Config->Pic) TableBase = 1; + log("-- calculateTargetFeatures"); + calculateTargetFeatures(); log("-- calculateImports"); calculateImports(); log("-- assignIndexes"); diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -48,6 +48,11 @@ std::vector> SDKs; }; +struct WasmFeatureEntry { + uint8_t Prefix; + std::string Name; +}; + struct WasmExport { StringRef Name; uint8_t Kind; @@ -253,6 +258,13 @@ WASM_SEGMENT_HAS_MEMINDEX = 0x02, }; +// Feature policy prefixes used in the custom "target_features" section +enum : uint8_t { + WASM_FEATURE_PREFIX_USED = '+', + WASM_FEATURE_PREFIX_REQUIRED = '=', + WASM_FEATURE_PREFIX_DISALLOWED = '-', +}; + // Kind codes used in the custom "name" section enum : unsigned { WASM_NAMES_FUNCTION = 0x1, diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -130,6 +130,9 @@ const wasm::WasmDylinkInfo &dylinkInfo() const { return DylinkInfo; } const wasm::WasmProducerInfo &getProducerInfo() const { return ProducerInfo; } + ArrayRef getTargetFeatures() const { + return TargetFeatures; + } ArrayRef types() const { return Signatures; } ArrayRef functionTypes() const { return FunctionTypes; } ArrayRef imports() const { return Imports; } @@ -252,12 +255,14 @@ Error parseLinkingSectionSymtab(ReadContext &Ctx); Error parseLinkingSectionComdat(ReadContext &Ctx); Error parseProducersSection(ReadContext &Ctx); + Error parseTargetFeaturesSection(ReadContext &Ctx); Error parseRelocSection(StringRef Name, ReadContext &Ctx); wasm::WasmObjectHeader Header; std::vector Sections; wasm::WasmDylinkInfo DylinkInfo; wasm::WasmProducerInfo ProducerInfo; + std::vector TargetFeatures; std::vector Signatures; std::vector FunctionTypes; std::vector Tables; @@ -318,6 +323,8 @@ WASM_SEC_ORDER_NAME, // "producers" section must appear after "name" section. WASM_SEC_ORDER_PRODUCERS, + // "target_features" section must appear after producers section + WASM_SEC_ORDER_TARGET_FEATURES, // Must be last WASM_NUM_SEC_ORDERS diff --git a/llvm/include/llvm/ObjectYAML/WasmYAML.h b/llvm/include/llvm/ObjectYAML/WasmYAML.h --- a/llvm/include/llvm/ObjectYAML/WasmYAML.h +++ b/llvm/include/llvm/ObjectYAML/WasmYAML.h @@ -38,6 +38,7 @@ LLVM_YAML_STRONG_TYPEDEF(uint32_t, SegmentFlags) LLVM_YAML_STRONG_TYPEDEF(uint32_t, LimitFlags) LLVM_YAML_STRONG_TYPEDEF(uint32_t, ComdatKind) +LLVM_YAML_STRONG_TYPEDEF(uint32_t, FeaturePolicyPrefix) struct FileHeader { yaml::Hex32 Version; @@ -128,6 +129,11 @@ std::string Version; }; +struct FeatureEntry { + FeaturePolicyPrefix Prefix; + std::string Name; +}; + struct SegmentInfo { uint32_t Index; StringRef Name; @@ -242,6 +248,17 @@ std::vector SDKs; }; +struct TargetFeaturesSection : CustomSection { + TargetFeaturesSection() : CustomSection("target_features") {} + + static bool classof(const Section *S) { + auto C = dyn_cast(S); + return C && C->Name == "target_features"; + } + + std::vector Features; +}; + struct TypeSection : Section { TypeSection() : Section(wasm::WASM_SEC_TYPE) {} @@ -385,6 +402,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Relocation) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::NameEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ProducerEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::FeatureEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SegmentInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SymbolInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::InitFunction) @@ -467,6 +485,14 @@ static void mapping(IO &IO, WasmYAML::ProducerEntry &ProducerEntry); }; +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, WasmYAML::FeaturePolicyPrefix &Prefix); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, WasmYAML::FeatureEntry &FeatureEntry); +}; + template <> struct MappingTraits { static void mapping(IO &IO, WasmYAML::SegmentInfo &SegmentInfo); }; diff --git a/llvm/lib/MC/MCParser/WasmAsmParser.cpp b/llvm/lib/MC/MCParser/WasmAsmParser.cpp --- a/llvm/lib/MC/MCParser/WasmAsmParser.cpp +++ b/llvm/lib/MC/MCParser/WasmAsmParser.cpp @@ -135,9 +135,10 @@ SectionKind Kind; }; static SectionType SectionTypes[] = { - { ".text", SectionKind::getText() }, - { ".rodata", SectionKind::getReadOnly() }, - { ".data", SectionKind::getData() }, + {".text", SectionKind::getText()}, + {".rodata", SectionKind::getReadOnly()}, + {".data", SectionKind::getData()}, + {".custom_section", SectionKind::getMetadata()}, // TODO: add more types. }; for (size_t I = 0; I < sizeof(SectionTypes) / sizeof(SectionType); I++) { diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -250,6 +250,7 @@ // section. std::vector CustomSections; std::unique_ptr ProducersSection; + std::unique_ptr TargetFeaturesSection; // Relocations for fixing up references in the custom sections. DenseMap> CustomSectionsRelocations; @@ -291,6 +292,7 @@ DataLocations.clear(); CustomSections.clear(); ProducersSection.reset(); + TargetFeaturesSection.reset(); CustomSectionsRelocations.clear(); SignatureIndices.clear(); Signatures.clear(); @@ -1286,11 +1288,16 @@ Twine(SectionName)); } - // Separate out the producers section + // Separate out the producers and target features sections if (Name == "producers") { ProducersSection = llvm::make_unique(Name, &Section); continue; } + if (Name == "target_features") { + TargetFeaturesSection = + llvm::make_unique(Name, &Section); + continue; + } CustomSections.emplace_back(Name, &Section); } @@ -1593,6 +1600,8 @@ writeCustomRelocSections(); if (ProducersSection) writeCustomSection(*ProducersSection, Asm, Layout); + if (TargetFeaturesSection) + writeCustomSection(*TargetFeaturesSection, Asm, Layout); // TODO: Translate the .comment section to the output. return W.OS.tell() - StartOffset; diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -674,7 +674,7 @@ } Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) { - llvm::SmallSet FieldsSeen; + llvm::SmallSet FieldsSeen; uint32_t Fields = readVaruint32(Ctx); for (size_t I = 0; I < Fields; ++I) { StringRef FieldName = readString(Ctx); @@ -714,6 +714,36 @@ return Error::success(); } +Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) { + llvm::SmallSet FeaturesSeen; + uint32_t FeatureCount = readVaruint32(Ctx); + for (size_t I = 0; I < FeatureCount; ++I) { + wasm::WasmFeatureEntry Feature; + Feature.Prefix = readUint8(Ctx); + switch (Feature.Prefix) { + case wasm::WASM_FEATURE_PREFIX_USED: + case wasm::WASM_FEATURE_PREFIX_REQUIRED: + case wasm::WASM_FEATURE_PREFIX_DISALLOWED: + break; + default: + return make_error("Unknown feature policy prefix", + object_error::parse_failed); + } + Feature.Name = readString(Ctx); + if (!FeaturesSeen.insert(Feature.Name).second) + return make_error( + "Target features section contains repeated feature \"" + + Feature.Name + "\"", + object_error::parse_failed); + TargetFeatures.push_back(Feature); + } + if (Ctx.Ptr != Ctx.End) + return make_error( + "Target features section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { uint32_t SectionIndex = readVaruint32(Ctx); if (SectionIndex >= Sections.size()) @@ -815,6 +845,9 @@ } else if (Sec.Name == "producers") { if (Error Err = parseProducersSection(Ctx)) return Err; + } else if (Sec.Name == "target_features") { + if (Error Err = parseTargetFeaturesSection(Ctx)) + return Err; } else if (Sec.Name.startswith("reloc.")) { if (Error Err = parseRelocSection(Sec.Name, Ctx)) return Err; @@ -1527,6 +1560,7 @@ .StartsWith("reloc.", WASM_SEC_ORDER_RELOC) .Case("name", WASM_SEC_ORDER_NAME) .Case("producers", WASM_SEC_ORDER_PRODUCERS) + .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES) .Default(WASM_SEC_ORDER_NONE); case wasm::WASM_SEC_TYPE: return WASM_SEC_ORDER_TYPE; @@ -1562,28 +1596,36 @@ // Represents the edges in a directed graph where any node B reachable from node // A is not allowed to appear before A in the section ordering, but may appear // afterward. -int WasmSectionOrderChecker::DisallowedPredecessors[WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = { - {}, // WASM_SEC_ORDER_NONE - {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT}, // WASM_SEC_ORDER_TYPE, - {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION}, // WASM_SEC_ORDER_IMPORT, - {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE}, // WASM_SEC_ORDER_FUNCTION, - {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY}, // WASM_SEC_ORDER_TABLE, - {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_GLOBAL}, // WASM_SEC_ORDER_MEMORY, - {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EVENT}, // WASM_SEC_ORDER_GLOBAL, - {WASM_SEC_ORDER_EVENT, WASM_SEC_ORDER_EXPORT}, // WASM_SEC_ORDER_EVENT, - {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START}, // WASM_SEC_ORDER_EXPORT, - {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM}, // WASM_SEC_ORDER_START, - {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT}, // WASM_SEC_ORDER_ELEM, - {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE}, // WASM_SEC_ORDER_DATACOUNT, - {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA}, // WASM_SEC_ORDER_CODE, - {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING}, // WASM_SEC_ORDER_DATA, - - // Custom Sections - {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE}, // WASM_SEC_ORDER_DYLINK, - {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME}, // WASM_SEC_ORDER_LINKING, - {}, // WASM_SEC_ORDER_RELOC (can be repeated), - {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS}, // WASM_SEC_ORDER_NAME, - {WASM_SEC_ORDER_PRODUCERS}, // WASM_SEC_ORDER_PRODUCERS, +int WasmSectionOrderChecker::DisallowedPredecessors + [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = { + {}, // WASM_SEC_ORDER_NONE + {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT}, // WASM_SEC_ORDER_TYPE, + {WASM_SEC_ORDER_IMPORT, + WASM_SEC_ORDER_FUNCTION}, // WASM_SEC_ORDER_IMPORT, + {WASM_SEC_ORDER_FUNCTION, + WASM_SEC_ORDER_TABLE}, // WASM_SEC_ORDER_FUNCTION, + {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY}, // WASM_SEC_ORDER_TABLE, + {WASM_SEC_ORDER_MEMORY, + WASM_SEC_ORDER_GLOBAL}, // WASM_SEC_ORDER_MEMORY, + {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EVENT}, // WASM_SEC_ORDER_GLOBAL, + {WASM_SEC_ORDER_EVENT, WASM_SEC_ORDER_EXPORT}, // WASM_SEC_ORDER_EVENT, + {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START}, // WASM_SEC_ORDER_EXPORT, + {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM}, // WASM_SEC_ORDER_START, + {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT}, // WASM_SEC_ORDER_ELEM, + {WASM_SEC_ORDER_DATACOUNT, + WASM_SEC_ORDER_CODE}, // WASM_SEC_ORDER_DATACOUNT, + {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA}, // WASM_SEC_ORDER_CODE, + {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING}, // WASM_SEC_ORDER_DATA, + + // Custom Sections + {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE}, // WASM_SEC_ORDER_DYLINK, + {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, + WASM_SEC_ORDER_NAME}, // WASM_SEC_ORDER_LINKING, + {}, // WASM_SEC_ORDER_RELOC (can be repeated), + {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS}, // WASM_SEC_ORDER_NAME, + {WASM_SEC_ORDER_PRODUCERS, + WASM_SEC_ORDER_TARGET_FEATURES}, // WASM_SEC_ORDER_PRODUCERS, + {WASM_SEC_ORDER_TARGET_FEATURES} // WASM_SEC_ORDER_TARGET_FEATURES }; bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID, diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -81,6 +81,11 @@ IO.mapOptional("SDKs", Section.SDKs); } +static void sectionMapping(IO &IO, WasmYAML::TargetFeaturesSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("Features", Section.Features); +} + static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) { commonSectionMapping(IO, Section); IO.mapRequired("Name", Section.Name); @@ -180,6 +185,10 @@ if (!IO.outputting()) Section.reset(new WasmYAML::ProducersSection()); sectionMapping(IO, *cast(Section.get())); + } else if (SectionName == "target_features") { + if (!IO.outputting()) + Section.reset(new WasmYAML::TargetFeaturesSection()); + sectionMapping(IO, *cast(Section.get())); } else { if (!IO.outputting()) Section.reset(new WasmYAML::CustomSection(SectionName)); @@ -310,6 +319,21 @@ IO.mapRequired("Version", ProducerEntry.Version); } +void ScalarEnumerationTraits::enumeration( + IO &IO, WasmYAML::FeaturePolicyPrefix &Kind) { +#define ECase(X) IO.enumCase(Kind, #X, wasm::WASM_FEATURE_PREFIX_##X); + ECase(USED); + ECase(REQUIRED); + ECase(DISALLOWED); +#undef ECase +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::FeatureEntry &FeatureEntry) { + IO.mapRequired("Prefix", FeatureEntry.Prefix); + IO.mapRequired("Name", FeatureEntry.Name); +} + void MappingTraits::mapping( IO &IO, WasmYAML::SegmentInfo &SegmentInfo) { IO.mapRequired("Index", SegmentInfo.Index); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h @@ -59,6 +59,7 @@ void EmitEndOfAsmFile(Module &M) override; void EmitProducerInfo(Module &M); + void EmitTargetFeatures(); void EmitJumpTableInfo() override; void EmitConstantPool() override; void EmitFunctionBodyStart() override; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -21,6 +21,7 @@ #include "WebAssemblyMCInstLower.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblyRegisterInfo.h" +#include "WebAssemblyTargetMachine.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/CodeGen/Analysis.h" @@ -159,6 +160,7 @@ } EmitProducerInfo(M); + EmitTargetFeatures(); } void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) { @@ -212,6 +214,65 @@ } } +void WebAssemblyAsmPrinter::EmitTargetFeatures() { + static const std::pair FeaturePairs[] = { + {WebAssembly::FeatureAtomics, "atomics"}, + {WebAssembly::FeatureBulkMemory, "bulk-memory"}, + {WebAssembly::FeatureExceptionHandling, "exception-handling"}, + {WebAssembly::FeatureNontrappingFPToInt, "nontrapping-fptoint"}, + {WebAssembly::FeatureSignExt, "sign-ext"}, + {WebAssembly::FeatureSIMD128, "simd128"}, + }; + + struct FeatureEntry { + enum : uint8_t { + Used = '+', + Required = '=', + Disallowed = '-', + } Prefix; + StringRef Name; + }; + + FeatureBitset UsedFeatures = + static_cast(TM).getUsedFeatures(); + + // Calculate the features and linkage policies to emit + SmallVector EmittedFeatures; + for (auto &F : FeaturePairs) { + FeatureEntry Entry; + Entry.Name = F.second; + if (F.first == WebAssembly::FeatureAtomics) { + // "atomics" is special: code compiled without atomics may have had its + // atomics lowered to nonatomic operations. Such code would be dangerous + // to mix with proper atomics, so it is always Required or Disallowed. + Entry.Prefix = UsedFeatures[F.first] ? FeatureEntry::Required + : FeatureEntry::Disallowed; + EmittedFeatures.push_back(Entry); + } else { + // Other features are marked Used or not mentioned + if (UsedFeatures[F.first]) { + Entry.Prefix = FeatureEntry::Used; + EmittedFeatures.push_back(Entry); + } + } + } + + // 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() { assert(MF->getConstantPool()->getConstants().empty() && "WebAssembly disables constant pools"); diff --git a/llvm/test/MC/WebAssembly/array-fill.ll b/llvm/test/MC/WebAssembly/array-fill.ll --- a/llvm/test/MC/WebAssembly/array-fill.ll +++ b/llvm/test/MC/WebAssembly/array-fill.ll @@ -24,4 +24,8 @@ ; CHECK-NEXT: Name: .data ; CHECK-NEXT: Alignment: 0 ; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: atomics ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/assembler-binary.ll b/llvm/test/MC/WebAssembly/assembler-binary.ll --- a/llvm/test/MC/WebAssembly/assembler-binary.ll +++ b/llvm/test/MC/WebAssembly/assembler-binary.ll @@ -87,4 +87,8 @@ ; CHECK-NEXT: Name: bar ; CHECK-NEXT: Flags: [ UNDEFINED ] ; CHECK-NEXT: Function: 0 +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: atomics ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/bss.ll b/llvm/test/MC/WebAssembly/bss.ll --- a/llvm/test/MC/WebAssembly/bss.ll +++ b/llvm/test/MC/WebAssembly/bss.ll @@ -78,4 +78,8 @@ ; CHECK-NEXT: Name: .bss.bar ; CHECK-NEXT: Alignment: 0 ; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: atomics ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/comdat.ll b/llvm/test/MC/WebAssembly/comdat.ll --- a/llvm/test/MC/WebAssembly/comdat.ll +++ b/llvm/test/MC/WebAssembly/comdat.ll @@ -119,4 +119,8 @@ ; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Kind: DATA ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: atomics ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/debug-info.ll b/llvm/test/MC/WebAssembly/debug-info.ll --- a/llvm/test/MC/WebAssembly/debug-info.ll +++ b/llvm/test/MC/WebAssembly/debug-info.ll @@ -130,6 +130,12 @@ ; CHECK-NEXT: Offset: 1021 ; CHECK-NEXT: Name: producers ; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 10 +; CHECK-NEXT: Offset: 1114 +; CHECK-NEXT: Name: target_features +; CHECK-NEXT: } ; CHECK-NEXT:] ; CHECK-NEXT:Relocations [ ; CHECK-NEXT: Section (6) DATA { diff --git a/llvm/test/MC/WebAssembly/explicit-sections.ll b/llvm/test/MC/WebAssembly/explicit-sections.ll --- a/llvm/test/MC/WebAssembly/explicit-sections.ll +++ b/llvm/test/MC/WebAssembly/explicit-sections.ll @@ -70,4 +70,8 @@ ; CHECK-NEXT: Name: .sec2 ; CHECK-NEXT: Alignment: 3 ; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: atomics ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll --- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll +++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll @@ -181,4 +181,8 @@ ; CHECK-NEXT: Symbol: 10 ; CHECK-NEXT: - Priority: 65535 ; CHECK-NEXT: Symbol: 7 +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: atomics ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/visibility.ll b/llvm/test/MC/WebAssembly/visibility.ll --- a/llvm/test/MC/WebAssembly/visibility.ll +++ b/llvm/test/MC/WebAssembly/visibility.ll @@ -25,4 +25,8 @@ ; CHECK-NEXT: Name: hiddenVis ; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] ; CHECK-NEXT: Function: 1 +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: atomics ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/weak-alias.ll b/llvm/test/MC/WebAssembly/weak-alias.ll --- a/llvm/test/MC/WebAssembly/weak-alias.ll +++ b/llvm/test/MC/WebAssembly/weak-alias.ll @@ -207,6 +207,10 @@ ; CHECK-NEXT: Name: .data.alias_address ; CHECK-NEXT: Alignment: 3 ; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: atomics ; CHECK-NEXT: ... ; CHECK-SYMS: SYMBOL TABLE: diff --git a/llvm/test/MC/WebAssembly/weak.ll b/llvm/test/MC/WebAssembly/weak.ll --- a/llvm/test/MC/WebAssembly/weak.ll +++ b/llvm/test/MC/WebAssembly/weak.ll @@ -30,4 +30,8 @@ ; CHECK-NEXT: Kind: DATA ; CHECK-NEXT: Name: weak_external_data ; CHECK-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ] +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Features: +; CHECK-NEXT: - Prefix: DISALLOWED +; CHECK-NEXT: Name: atomics ; CHECK-NEXT: ... diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp --- a/llvm/tools/obj2yaml/wasm2yaml.cpp +++ b/llvm/tools/obj2yaml/wasm2yaml.cpp @@ -155,6 +155,16 @@ ProducersSec->SDKs.push_back(Producer); } CustomSec = std::move(ProducersSec); + } else if (WasmSec.Name == "target_features") { + std::unique_ptr TargetFeaturesSec = + make_unique(); + for (auto &E : Obj.getTargetFeatures()) { + WasmYAML::FeatureEntry Feature; + Feature.Prefix = E.Prefix; + Feature.Name = E.Name; + TargetFeaturesSec->Features.push_back(Feature); + } + CustomSec = std::move(TargetFeaturesSec); } else { CustomSec = make_unique(WasmSec.Name); } diff --git a/llvm/tools/yaml2obj/yaml2wasm.cpp b/llvm/tools/yaml2obj/yaml2wasm.cpp --- a/llvm/tools/yaml2obj/yaml2wasm.cpp +++ b/llvm/tools/yaml2obj/yaml2wasm.cpp @@ -49,6 +49,8 @@ int writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section); int writeSectionContent(raw_ostream &OS, WasmYAML::ProducersSection &Section); + int writeSectionContent(raw_ostream &OS, + WasmYAML::TargetFeaturesSection &Section); WasmYAML::Object &Obj; uint32_t NumImportedFunctions = 0; uint32_t NumImportedGlobals = 0; @@ -279,6 +281,18 @@ return 0; } +int WasmWriter::writeSectionContent(raw_ostream &OS, + WasmYAML::TargetFeaturesSection &Section) { + writeStringRef(Section.Name, OS); + encodeULEB128(Section.Features.size(), OS); + for (auto &E : Section.Features) { + writeUint8(OS, E.Prefix); + encodeULEB128(E.Name.size(), OS); + writeStringRef(E.Name, OS); + } + return 0; +} + int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::CustomSection &Section) { if (auto S = dyn_cast(&Section)) {