summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2019-03-20 20:26:45 +0000
committerThomas Lively <tlively@google.com>2019-03-20 20:26:45 +0000
commitf6f4f84378ea07e8cb976631dd82079c027d7cf4 (patch)
treee31f1f14a9922b236f9f15b897610e961b22eb38
parente0941cb32650849aa8a7bba92ae95a359c424266 (diff)
downloadbcm5719-llvm-f6f4f84378ea07e8cb976631dd82079c027d7cf4.tar.gz
bcm5719-llvm-f6f4f84378ea07e8cb976631dd82079c027d7cf4.zip
[WebAssembly] Target features section
Summary: Implements a new target features section in assembly and object files that records what features are used, required, and disallowed in WebAssembly objects. The linker uses this information to ensure that all objects participating in a link are feature-compatible and records the set of used features in the output binary for use by optimizers and other tools later in the toolchain. The "atomics" feature is always required or disallowed to prevent linking code with stripped atomics into multithreaded binaries. Other features are marked used if they are enabled globally or on any function in a module. Future CLs will add linker flags for ignoring feature compatibility checks and for specifying the set of allowed features, implement using the presence of the "atomics" feature to control the type of memory and segments in the linked binary, and add front-end flags for relaxing the linkage policy for atomics. Reviewers: aheejin, sbc100, dschuff Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D59173 llvm-svn: 356610
-rw-r--r--lld/test/wasm/Inputs/disallow-feature-foo.yaml13
-rw-r--r--lld/test/wasm/Inputs/no-feature-foo.yaml11
-rw-r--r--lld/test/wasm/Inputs/require-feature-foo.yaml13
-rw-r--r--lld/test/wasm/Inputs/use-feature-foo.yaml13
-rw-r--r--lld/test/wasm/target-feature-disallowed.yaml44
-rw-r--r--lld/test/wasm/target-feature-required.yaml42
-rw-r--r--lld/test/wasm/target-feature-used.yaml58
-rw-r--r--lld/wasm/InputFiles.cpp2
-rw-r--r--lld/wasm/InputFiles.h1
-rw-r--r--lld/wasm/Writer.cpp71
-rw-r--r--llvm/include/llvm/BinaryFormat/Wasm.h12
-rw-r--r--llvm/include/llvm/Object/Wasm.h7
-rw-r--r--llvm/include/llvm/ObjectYAML/WasmYAML.h26
-rw-r--r--llvm/lib/MC/MCParser/WasmAsmParser.cpp7
-rw-r--r--llvm/lib/MC/WasmObjectWriter.cpp11
-rw-r--r--llvm/lib/Object/WasmObjectFile.cpp37
-rw-r--r--llvm/lib/ObjectYAML/WasmYAML.cpp25
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp58
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h1
-rw-r--r--llvm/test/CodeGen/WebAssembly/target-features.ll67
-rw-r--r--llvm/test/MC/WebAssembly/array-fill.ll5
-rw-r--r--llvm/test/MC/WebAssembly/assembler-binary.ll5
-rw-r--r--llvm/test/MC/WebAssembly/bss.ll5
-rw-r--r--llvm/test/MC/WebAssembly/comdat.ll5
-rw-r--r--llvm/test/MC/WebAssembly/debug-info.ll6
-rw-r--r--llvm/test/MC/WebAssembly/explicit-sections.ll5
-rw-r--r--llvm/test/MC/WebAssembly/global-ctor-dtor.ll5
-rw-r--r--llvm/test/MC/WebAssembly/visibility.ll5
-rw-r--r--llvm/test/MC/WebAssembly/weak-alias.ll5
-rw-r--r--llvm/test/MC/WebAssembly/weak.ll5
-rw-r--r--llvm/test/ObjectYAML/wasm/target-features-section.yaml25
-rw-r--r--llvm/tools/obj2yaml/wasm2yaml.cpp10
-rw-r--r--llvm/tools/yaml2obj/yaml2wasm.cpp16
33 files changed, 611 insertions, 10 deletions
diff --git a/lld/test/wasm/Inputs/disallow-feature-foo.yaml b/lld/test/wasm/Inputs/disallow-feature-foo.yaml
new file mode 100644
index 00000000000..f4f987ef090
--- /dev/null
+++ b/lld/test/wasm/Inputs/disallow-feature-foo.yaml
@@ -0,0 +1,13 @@
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: CUSTOM
+ Name: linking
+ Version: 2
+ - Type: CUSTOM
+ Name: target_features
+ Features:
+ - Prefix: DISALLOWED
+ Name: "foo"
+...
diff --git a/lld/test/wasm/Inputs/no-feature-foo.yaml b/lld/test/wasm/Inputs/no-feature-foo.yaml
new file mode 100644
index 00000000000..6456d042707
--- /dev/null
+++ b/lld/test/wasm/Inputs/no-feature-foo.yaml
@@ -0,0 +1,11 @@
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: CUSTOM
+ Name: linking
+ Version: 2
+ - Type: CUSTOM
+ Name: target_features
+ Features: [ ]
+...
diff --git a/lld/test/wasm/Inputs/require-feature-foo.yaml b/lld/test/wasm/Inputs/require-feature-foo.yaml
new file mode 100644
index 00000000000..cf42b79fa4b
--- /dev/null
+++ b/lld/test/wasm/Inputs/require-feature-foo.yaml
@@ -0,0 +1,13 @@
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: CUSTOM
+ Name: linking
+ Version: 2
+ - Type: CUSTOM
+ Name: target_features
+ Features:
+ - Prefix: REQUIRED
+ Name: "foo"
+...
diff --git a/lld/test/wasm/Inputs/use-feature-foo.yaml b/lld/test/wasm/Inputs/use-feature-foo.yaml
new file mode 100644
index 00000000000..0d1203454c0
--- /dev/null
+++ b/lld/test/wasm/Inputs/use-feature-foo.yaml
@@ -0,0 +1,13 @@
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: CUSTOM
+ Name: linking
+ Version: 2
+ - Type: CUSTOM
+ Name: target_features
+ Features:
+ - Prefix: USED
+ Name: "foo"
+...
diff --git a/lld/test/wasm/target-feature-disallowed.yaml b/lld/test/wasm/target-feature-disallowed.yaml
new file mode 100644
index 00000000000..9a94f0d1f10
--- /dev/null
+++ b/lld/test/wasm/target-feature-disallowed.yaml
@@ -0,0 +1,44 @@
+# RUN: yaml2obj %s -o %t1.o
+
+# RUN: yaml2obj %S/Inputs/disallow-feature-foo.yaml -o %t.disallowed.o
+# RUN: wasm-ld --no-entry -o - %t1.o %t.disallowed.o | obj2yaml | FileCheck %s --check-prefix DISALLOWED
+
+# RUN: yaml2obj %S/Inputs/no-feature-foo.yaml -o %t.none.o
+# RUN: wasm-ld --no-entry -o - %t1.o %t.none.o | obj2yaml | FileCheck %s --check-prefix NONE
+
+# Check that the following combinations of feature linkage policies
+# give the expected results:
+#
+# DISALLOWED x DISALLOWED => NONE
+# DISALLOWED x NONE => NONE
+
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: CUSTOM
+ Name: linking
+ Version: 2
+ - Type: CUSTOM
+ Name: target_features
+ Features:
+ - Prefix: DISALLOWED
+ Name: "foo"
+ # included so output has target features section
+ - Prefix: USED
+ Name: "bar"
+...
+
+# DISALLOWED: - Type: CUSTOM
+# DISALLOWED-NEXT: Name: target_features
+# DISALLOWED-NEXT: Features:
+# DISALLOWED-NEXT: - Prefix: USED
+# DISALLOWED-NEXT: Name: bar
+# DISALLOWED-NEXT: ...
+
+# NONE: - Type: CUSTOM
+# NONE-NEXT: Name: target_features
+# NONE-NEXT: Features:
+# NONE-NEXT: - Prefix: USED
+# NONE-NEXT: Name: bar
+# NONE-NEXT: ...
diff --git a/lld/test/wasm/target-feature-required.yaml b/lld/test/wasm/target-feature-required.yaml
new file mode 100644
index 00000000000..68df45c194a
--- /dev/null
+++ b/lld/test/wasm/target-feature-required.yaml
@@ -0,0 +1,42 @@
+# RUN: yaml2obj %s -o %t1.o
+
+# RUN: yaml2obj %S/Inputs/require-feature-foo.yaml -o %t.required.o
+# RUN: wasm-ld --no-entry -o - %t1.o %t.required.o | obj2yaml | FileCheck %s --check-prefix REQUIRED
+
+# RUN: yaml2obj %S/Inputs/disallow-feature-foo.yaml -o %t.disallowed.o
+# RUN: not wasm-ld --no-entry -o - %t1.o %t.disallowed.o 2>&1 | FileCheck %s --check-prefix DISALLOWED
+
+# RUN: yaml2obj %S/Inputs/no-feature-foo.yaml -o %t.none.o
+# RUN: not wasm-ld --no-entry -o - %t1.o %t.none.o 2>&1 | FileCheck %s --check-prefix NONE
+
+# Check that the following combinations of feature linkage policies
+# give the expected results:
+#
+# REQUIRED x REQUIRED => USED
+# REQUIRED x DISALLOWED => Error
+# REQUIRED x NONE => Error
+
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: CUSTOM
+ Name: linking
+ Version: 2
+ - Type: CUSTOM
+ Name: target_features
+ Features:
+ - Prefix: REQUIRED
+ Name: "foo"
+...
+
+# REQUIRED: - Type: CUSTOM
+# REQUIRED-NEXT: Name: target_features
+# REQUIRED-NEXT: Features:
+# REQUIRED-NEXT: - Prefix: USED
+# REQUIRED-NEXT: Name: foo
+# REQUIRED-NEXT: ...
+
+# DISALLOWED: Target feature "foo" is disallowed
+
+# NONE: Missing required target feature "foo"
diff --git a/lld/test/wasm/target-feature-used.yaml b/lld/test/wasm/target-feature-used.yaml
new file mode 100644
index 00000000000..6a353991f54
--- /dev/null
+++ b/lld/test/wasm/target-feature-used.yaml
@@ -0,0 +1,58 @@
+# RUN: yaml2obj %s -o %t1.o
+
+# RUN: yaml2obj %S/Inputs/use-feature-foo.yaml -o %t.used.o
+# RUN: wasm-ld --no-entry -o - %t1.o %t.used.o | obj2yaml | FileCheck %s --check-prefix USED
+
+# RUN: yaml2obj %S/Inputs/require-feature-foo.yaml -o %t.required.o
+# RUN: wasm-ld --no-entry -o - %t1.o %t.required.o | obj2yaml | FileCheck %s --check-prefix REQUIRED
+
+# RUN: yaml2obj %S/Inputs/disallow-feature-foo.yaml -o %t.disallowed.o
+# RUN: not wasm-ld --no-entry -o - %t1.o %t.disallowed.o 2>&1 | FileCheck %s --check-prefix DISALLOWED
+
+# RUN: yaml2obj %S/Inputs/no-feature-foo.yaml -o %t.none.o
+# RUN: wasm-ld --no-entry -o - %t1.o %t.none.o | obj2yaml | FileCheck %s --check-prefix NONE
+
+# Check that the following combinations of feature linkage policies
+# give the expected results:
+#
+# USED x USED => USED
+# USED x REQUIRED => USED
+# USED x DISALLOWED => Error
+# USED x NONE => USED
+
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: CUSTOM
+ Name: linking
+ Version: 2
+ - Type: CUSTOM
+ Name: target_features
+ Features:
+ - Prefix: USED
+ Name: "foo"
+...
+
+# USED: - Type: CUSTOM
+# USED-NEXT: Name: target_features
+# USED-NEXT: Features:
+# USED-NEXT: - Prefix: USED
+# USED-NEXT: Name: foo
+# USED-NEXT: ...
+
+# REQUIRED: - Type: CUSTOM
+# REQUIRED-NEXT: Name: target_features
+# REQUIRED-NEXT: Features:
+# REQUIRED-NEXT: - Prefix: USED
+# REQUIRED-NEXT: Name: foo
+# REQUIRED-NEXT: ...
+
+# DISALLOWED: Target feature "foo" is disallowed
+
+# NONE: - Type: CUSTOM
+# NONE-NEXT: Name: target_features
+# NONE-NEXT: Features:
+# NONE-NEXT: - Prefix: USED
+# NONE-NEXT: Name: foo
+# NONE-NEXT: ...
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 5c9ae60e543..b43cab7fd38 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -244,8 +244,6 @@ void ObjFile::parse() {
CustomSections.emplace_back(make<InputSection>(Section, this));
CustomSections.back()->setRelocations(Section.Relocations);
CustomSectionsByIndex[SectionIndex] = CustomSections.back();
- if (Section.Name == "producers")
- ProducersSection = &Section;
}
SectionIndex++;
}
diff --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h
index 1f44f5b5ec3..0913725b854 100644
--- a/lld/wasm/InputFiles.h
+++ b/lld/wasm/InputFiles.h
@@ -99,7 +99,6 @@ public:
const WasmSection *CodeSection = nullptr;
const WasmSection *DataSection = nullptr;
- const WasmSection *ProducersSection = nullptr;
// Maps input type indices to output type indices
std::vector<uint32_t> TypeMap;
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 96c473629cf..897908a5ad0 100644
--- 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"
@@ -68,6 +69,7 @@ private:
void calculateInitFunctions();
void processRelocations(InputChunk *Chunk);
void assignIndexes();
+ void calculateTargetFeatures();
void calculateImports();
void calculateExports();
void calculateCustomSections();
@@ -99,6 +101,7 @@ private:
void createLinkingSection();
void createNameSection();
void createProducersSection();
+ void createTargetFeaturesSection();
void writeHeader();
void writeSections();
@@ -129,6 +132,7 @@ private:
llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
llvm::StringMap<SectionSymbol *> CustomSectionSymbols;
+ llvm::SmallSet<std::string, 8> TargetFeatures;
// Elements that are used to construct the final output
std::string Header;
@@ -344,7 +348,7 @@ void Writer::calculateCustomSections() {
// 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_"))
@@ -701,6 +705,23 @@ void Writer::createProducersSection() {
}
}
+void Writer::createTargetFeaturesSection() {
+ if (TargetFeatures.size() == 0)
+ return;
+
+ SmallVector<std::string, 8> 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());
}
@@ -844,8 +865,10 @@ void Writer::createSections() {
if (!Config->StripDebug && !Config->StripAll)
createNameSection();
- if (!Config->StripAll)
+ if (!Config->StripAll) {
createProducersSection();
+ createTargetFeaturesSection();
+ }
for (OutputSection *S : OutputSections) {
S->setOffset(FileSize);
@@ -854,6 +877,48 @@ void Writer::createSections() {
}
}
+void Writer::calculateTargetFeatures() {
+ SmallSet<std::string, 8> Required;
+ SmallSet<std::string, 8> 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<std::string, 8> 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())
@@ -1225,6 +1290,8 @@ void Writer::run() {
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
index 7848be1cbfa..443c2a5d2c6 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -48,6 +48,11 @@ struct WasmProducerInfo {
std::vector<std::pair<std::string, std::string>> SDKs;
};
+struct WasmFeatureEntry {
+ uint8_t Prefix;
+ std::string Name;
+};
+
struct WasmExport {
StringRef Name;
uint8_t Kind;
@@ -253,6 +258,13 @@ enum : unsigned {
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
index e3d1e24bdbc..02220dbcf0f 100644
--- a/llvm/include/llvm/Object/Wasm.h
+++ b/llvm/include/llvm/Object/Wasm.h
@@ -130,6 +130,9 @@ public:
const wasm::WasmDylinkInfo &dylinkInfo() const { return DylinkInfo; }
const wasm::WasmProducerInfo &getProducerInfo() const { return ProducerInfo; }
+ ArrayRef<wasm::WasmFeatureEntry> getTargetFeatures() const {
+ return TargetFeatures;
+ }
ArrayRef<wasm::WasmSignature> types() const { return Signatures; }
ArrayRef<uint32_t> functionTypes() const { return FunctionTypes; }
ArrayRef<wasm::WasmImport> imports() const { return Imports; }
@@ -252,12 +255,14 @@ private:
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<WasmSection> Sections;
wasm::WasmDylinkInfo DylinkInfo;
wasm::WasmProducerInfo ProducerInfo;
+ std::vector<wasm::WasmFeatureEntry> TargetFeatures;
std::vector<wasm::WasmSignature> Signatures;
std::vector<uint32_t> FunctionTypes;
std::vector<wasm::WasmTable> Tables;
@@ -318,6 +323,8 @@ public:
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
index 1d69d78e613..60ed1aae1bd 100644
--- a/llvm/include/llvm/ObjectYAML/WasmYAML.h
+++ b/llvm/include/llvm/ObjectYAML/WasmYAML.h
@@ -38,6 +38,7 @@ LLVM_YAML_STRONG_TYPEDEF(uint32_t, SymbolKind)
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 @@ struct ProducerEntry {
std::string Version;
};
+struct FeatureEntry {
+ FeaturePolicyPrefix Prefix;
+ std::string Name;
+};
+
struct SegmentInfo {
uint32_t Index;
StringRef Name;
@@ -242,6 +248,17 @@ struct ProducersSection : CustomSection {
std::vector<ProducerEntry> SDKs;
};
+struct TargetFeaturesSection : CustomSection {
+ TargetFeaturesSection() : CustomSection("target_features") {}
+
+ static bool classof(const Section *S) {
+ auto C = dyn_cast<CustomSection>(S);
+ return C && C->Name == "target_features";
+ }
+
+ std::vector<FeatureEntry> Features;
+};
+
struct TypeSection : Section {
TypeSection() : Section(wasm::WASM_SEC_TYPE) {}
@@ -385,6 +402,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::LocalDecl)
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 @@ template <> struct MappingTraits<WasmYAML::ProducerEntry> {
static void mapping(IO &IO, WasmYAML::ProducerEntry &ProducerEntry);
};
+template <> struct ScalarEnumerationTraits<WasmYAML::FeaturePolicyPrefix> {
+ static void enumeration(IO &IO, WasmYAML::FeaturePolicyPrefix &Prefix);
+};
+
+template <> struct MappingTraits<WasmYAML::FeatureEntry> {
+ static void mapping(IO &IO, WasmYAML::FeatureEntry &FeatureEntry);
+};
+
template <> struct MappingTraits<WasmYAML::SegmentInfo> {
static void mapping(IO &IO, WasmYAML::SegmentInfo &SegmentInfo);
};
diff --git a/llvm/lib/MC/MCParser/WasmAsmParser.cpp b/llvm/lib/MC/MCParser/WasmAsmParser.cpp
index 197e9052566..1054b871052 100644
--- a/llvm/lib/MC/MCParser/WasmAsmParser.cpp
+++ b/llvm/lib/MC/MCParser/WasmAsmParser.cpp
@@ -135,9 +135,10 @@ public:
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
index e82ed5898b4..0014b695b90 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -250,6 +250,7 @@ class WasmObjectWriter : public MCObjectWriter {
// section.
std::vector<WasmCustomSection> CustomSections;
std::unique_ptr<WasmCustomSection> ProducersSection;
+ std::unique_ptr<WasmCustomSection> TargetFeaturesSection;
// Relocations for fixing up references in the custom sections.
DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>>
CustomSectionsRelocations;
@@ -291,6 +292,7 @@ private:
DataLocations.clear();
CustomSections.clear();
ProducersSection.reset();
+ TargetFeaturesSection.reset();
CustomSectionsRelocations.clear();
SignatureIndices.clear();
Signatures.clear();
@@ -1286,11 +1288,16 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
Twine(SectionName));
}
- // Separate out the producers section
+ // Separate out the producers and target features sections
if (Name == "producers") {
ProducersSection = llvm::make_unique<WasmCustomSection>(Name, &Section);
continue;
}
+ if (Name == "target_features") {
+ TargetFeaturesSection =
+ llvm::make_unique<WasmCustomSection>(Name, &Section);
+ continue;
+ }
CustomSections.emplace_back(Name, &Section);
}
@@ -1593,6 +1600,8 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
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
index 2ff2c555d5e..14b17bcfa5e 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -715,6 +715,36 @@ Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
return Error::success();
}
+Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
+ llvm::SmallSet<std::string, 8> 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<GenericBinaryError>("Unknown feature policy prefix",
+ object_error::parse_failed);
+ }
+ Feature.Name = readString(Ctx);
+ if (!FeaturesSeen.insert(Feature.Name).second)
+ return make_error<GenericBinaryError>(
+ "Target features section contains repeated feature \"" +
+ Feature.Name + "\"",
+ object_error::parse_failed);
+ TargetFeatures.push_back(Feature);
+ }
+ if (Ctx.Ptr != Ctx.End)
+ return make_error<GenericBinaryError>(
+ "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())
@@ -816,6 +846,9 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
} 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;
@@ -1528,6 +1561,7 @@ int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
.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;
@@ -1584,7 +1618,8 @@ int WasmSectionOrderChecker::DisallowedPredecessors[WASM_NUM_SEC_ORDERS][WASM_NU
{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,
+ {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
index 1865dcf7aa6..3841c5b7712 100644
--- a/llvm/lib/ObjectYAML/WasmYAML.cpp
+++ b/llvm/lib/ObjectYAML/WasmYAML.cpp
@@ -81,6 +81,12 @@ static void sectionMapping(IO &IO, WasmYAML::ProducersSection &Section) {
IO.mapOptional("SDKs", Section.SDKs);
}
+static void sectionMapping(IO &IO, WasmYAML::TargetFeaturesSection &Section) {
+ commonSectionMapping(IO, Section);
+ IO.mapRequired("Name", Section.Name);
+ IO.mapRequired("Features", Section.Features);
+}
+
static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) {
commonSectionMapping(IO, Section);
IO.mapRequired("Name", Section.Name);
@@ -180,6 +186,10 @@ void MappingTraits<std::unique_ptr<WasmYAML::Section>>::mapping(
if (!IO.outputting())
Section.reset(new WasmYAML::ProducersSection());
sectionMapping(IO, *cast<WasmYAML::ProducersSection>(Section.get()));
+ } else if (SectionName == "target_features") {
+ if (!IO.outputting())
+ Section.reset(new WasmYAML::TargetFeaturesSection());
+ sectionMapping(IO, *cast<WasmYAML::TargetFeaturesSection>(Section.get()));
} else {
if (!IO.outputting())
Section.reset(new WasmYAML::CustomSection(SectionName));
@@ -310,6 +320,21 @@ void MappingTraits<WasmYAML::ProducerEntry>::mapping(
IO.mapRequired("Version", ProducerEntry.Version);
}
+void ScalarEnumerationTraits<WasmYAML::FeaturePolicyPrefix>::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<WasmYAML::FeatureEntry>::mapping(
+ IO &IO, WasmYAML::FeatureEntry &FeatureEntry) {
+ IO.mapRequired("Prefix", FeatureEntry.Prefix);
+ IO.mapRequired("Name", FeatureEntry.Name);
+}
+
void MappingTraits<WasmYAML::SegmentInfo>::mapping(
IO &IO, WasmYAML::SegmentInfo &SegmentInfo) {
IO.mapRequired("Index", SegmentInfo.Index);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index b0a80b0ca79..c8a53ebd4cc 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -21,8 +21,10 @@
#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"
@@ -159,6 +161,7 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
}
EmitProducerInfo(M);
+ EmitTargetFeatures();
}
void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
@@ -212,6 +215,61 @@ void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
}
}
+void WebAssemblyAsmPrinter::EmitTargetFeatures() {
+ static const std::pair<unsigned, const char *> 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 {
+ uint8_t Prefix;
+ StringRef Name;
+ };
+
+ FeatureBitset UsedFeatures =
+ static_cast<WebAssemblyTargetMachine &>(TM).getUsedFeatures();
+
+ // Calculate the features and linkage policies to emit
+ SmallVector<FeatureEntry, 4> 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] ? wasm::WASM_FEATURE_PREFIX_REQUIRED
+ : wasm::WASM_FEATURE_PREFIX_DISALLOWED;
+ EmittedFeatures.push_back(Entry);
+ } else {
+ // Other features are marked Used or not mentioned
+ if (UsedFeatures[F.first]) {
+ Entry.Prefix = wasm::WASM_FEATURE_PREFIX_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/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
index 579cc9a493e..35e7d8d0f66 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
@@ -59,6 +59,7 @@ public:
void EmitEndOfAsmFile(Module &M) override;
void EmitProducerInfo(Module &M);
+ void EmitTargetFeatures();
void EmitJumpTableInfo() override;
void EmitConstantPool() override;
void EmitFunctionBodyStart() override;
diff --git a/llvm/test/CodeGen/WebAssembly/target-features.ll b/llvm/test/CodeGen/WebAssembly/target-features.ll
new file mode 100644
index 00000000000..f262657a56d
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/target-features.ll
@@ -0,0 +1,67 @@
+; RUN: llc < %s | FileCheck %s --check-prefixes CHECK,ATTRS
+; RUN: llc < %s -mattr=+simd128 | FileCheck %s --check-prefixes CHECK,SIMD128
+; RUN; llc < %s -mattr=+atomics | FileCheck %s --check-prefixes CHECK,ATOMICS
+; RUN: llc < %s -mcpu=bleeding-edge | FileCheck %s --check-prefixes CHECK,BLEEDING-EDGE
+
+; Test that codegen emits target features from the command line or
+; function attributes correctly.
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @foo() #0 {
+ ret void
+}
+
+define void @bar() #1 {
+ ret void
+}
+
+attributes #0 = { "target-features"="+sign-ext" }
+attributes #1 = { "target-features"="+nontrapping-fptoint" }
+
+; CHECK-LABEL: .custom_section.target_features,"",@
+
+; -atomics, +sign_ext
+; ATTRS-NEXT: .int8 3
+; ATTRS-NEXT: .int8 45
+; ATTRS-NEXT: .int8 7
+; ATTRS-NEXT: .ascii "atomics"
+; ATTRS-NEXT: .int8 43
+; ATTRS-NEXT: .int8 19
+; ATTRS-NEXT: .ascii "nontrapping-fptoint"
+; ATTRS-NEXT: .int8 43
+; ATTRS-NEXT: int8 8
+; ATTRS-NEXT: .ascii "sign-ext"
+
+; -atomics, +simd128
+; SIMD128-NEXT: .int8 2
+; SIMD128-NEXT: .int8 45
+; SIMD128-NEXT: .int8 7
+; SIMD128-NEXT: .ascii "atomics"
+; SIMD128-NEXT: .int8 43
+; SIMD128-NEXT: .int8 7
+; SIMD128-NEXT: .ascii "simd128"
+
+; =atomics
+; ATOMICS-NEXT: .int8 1
+; ATOMICS-NEXT: .int8 61
+; ATOMICS-NEXT: .int8 7
+; ATOMICS-NEXT: .ascii "atomics"
+
+; =atomics, +nontrapping-fptoint, +sign-ext, +simd128
+; BLEEDING-EDGE-NEXT: .int8 4
+; BLEEDING-EDGE-NEXT: .int8 61
+; BLEEDING-EDGE-NEXT: .int8 7
+; BLEEDING-EDGE-NEXT: .ascii "atomics"
+; BLEEDING-EDGE-NEXT: .int8 43
+; BLEEDING-EDGE-NEXT: .int8 19
+; BLEEDING-EDGE-NEXT: .ascii "nontrapping-fptoint"
+; BLEEDING-EDGE-NEXT: .int8 43
+; BLEEDING-EDGE-NEXT: .int8 8
+; BLEEDING-EDGE-NEXT: .ascii "sign-ext"
+; BLEEDING-EDGE-NEXT: .int8 43
+; BLEEDING-EDGE-NEXT: .int8 7
+; BLEEDING-EDGE-NEXT: .ascii "simd128"
+
+; CHECK-NEXT: .text
diff --git a/llvm/test/MC/WebAssembly/array-fill.ll b/llvm/test/MC/WebAssembly/array-fill.ll
index 61cdb91368c..9e2eba4a3f2 100644
--- a/llvm/test/MC/WebAssembly/array-fill.ll
+++ b/llvm/test/MC/WebAssembly/array-fill.ll
@@ -24,4 +24,9 @@ target triple = "wasm32-unknown-unknown"
; CHECK-NEXT: Name: .data
; CHECK-NEXT: Alignment: 0
; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: target_features
+; 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
index 3683d63e435..d838320aeed 100644
--- a/llvm/test/MC/WebAssembly/assembler-binary.ll
+++ b/llvm/test/MC/WebAssembly/assembler-binary.ll
@@ -87,4 +87,9 @@ entry:
; CHECK-NEXT: Name: bar
; CHECK-NEXT: Flags: [ UNDEFINED ]
; CHECK-NEXT: Function: 0
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: target_features
+; 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
index b3d95a161d1..de8b9f88ec3 100644
--- a/llvm/test/MC/WebAssembly/bss.ll
+++ b/llvm/test/MC/WebAssembly/bss.ll
@@ -78,4 +78,9 @@ target triple = "wasm32-unknown-unknown"
; CHECK-NEXT: Name: .bss.bar
; CHECK-NEXT: Alignment: 0
; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: target_features
+; 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
index 18905890776..0327a8bed3f 100644
--- a/llvm/test/MC/WebAssembly/comdat.ll
+++ b/llvm/test/MC/WebAssembly/comdat.ll
@@ -119,4 +119,9 @@ define linkonce_odr i32 @sharedFn() #1 comdat($sharedComdat) {
; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Kind: DATA
; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: target_features
+; 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
index fe4a4cf6983..f76bba93c9b 100644
--- 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
index b94190f8143..f43189ad247 100644
--- a/llvm/test/MC/WebAssembly/explicit-sections.ll
+++ b/llvm/test/MC/WebAssembly/explicit-sections.ll
@@ -70,4 +70,9 @@ target triple = "wasm32-unknown-unknown"
; CHECK-NEXT: Name: .sec2
; CHECK-NEXT: Alignment: 3
; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: target_features
+; 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
index df7ff92acff..9b384e3ad0f 100644
--- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll
+++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll
@@ -181,4 +181,9 @@ declare void @func3()
; CHECK-NEXT: Symbol: 10
; CHECK-NEXT: - Priority: 65535
; CHECK-NEXT: Symbol: 7
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: target_features
+; 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
index 5bb757b28f1..63b46ebf2e0 100644
--- a/llvm/test/MC/WebAssembly/visibility.ll
+++ b/llvm/test/MC/WebAssembly/visibility.ll
@@ -25,4 +25,9 @@ entry:
; CHECK-NEXT: Name: hiddenVis
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
; CHECK-NEXT: Function: 1
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: target_features
+; 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
index 7abdc79b569..cf5783a017e 100644
--- a/llvm/test/MC/WebAssembly/weak-alias.ll
+++ b/llvm/test/MC/WebAssembly/weak-alias.ll
@@ -207,6 +207,11 @@ entry:
; CHECK-NEXT: Name: .data.alias_address
; CHECK-NEXT: Alignment: 3
; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: target_features
+; 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
index 6a94ee627b6..2278f97c89d 100644
--- a/llvm/test/MC/WebAssembly/weak.ll
+++ b/llvm/test/MC/WebAssembly/weak.ll
@@ -30,4 +30,9 @@ entry:
; CHECK-NEXT: Kind: DATA
; CHECK-NEXT: Name: weak_external_data
; CHECK-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ]
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: target_features
+; CHECK-NEXT: Features:
+; CHECK-NEXT: - Prefix: DISALLOWED
+; CHECK-NEXT: Name: atomics
; CHECK-NEXT: ...
diff --git a/llvm/test/ObjectYAML/wasm/target-features-section.yaml b/llvm/test/ObjectYAML/wasm/target-features-section.yaml
new file mode 100644
index 00000000000..22d2645095d
--- /dev/null
+++ b/llvm/test/ObjectYAML/wasm/target-features-section.yaml
@@ -0,0 +1,25 @@
+# RUN: yaml2obj %s | obj2yaml | FileCheck %s
+--- !WASM
+FileHeader:
+ Version: 0x00000001
+Sections:
+ - Type: CUSTOM
+ Name: target_features
+ Features:
+ - Prefix: USED
+ Name: "foo"
+ - Prefix: REQUIRED
+ Name: "bar"
+ - Prefix: DISALLOWED
+ Name: ""
+...
+# CHECK-LABEL: Sections:
+# CHECK-NEXT: - Type: CUSTOM
+# CHECK-NEXT: Name: target_features
+# CHECK-NEXT: Features:
+# CHECK-NEXT: - Prefix: USED
+# CHECK-NEXT: Name: foo
+# CHECK-NEXT: - Prefix: REQUIRED
+# CHECK-NEXT: Name: bar
+# CHECK-NEXT: - Prefix: DISALLOWED
+# CHECK-NEXT: Name: ''
diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp
index b6eef9cf9fb..eacbe621e0e 100644
--- a/llvm/tools/obj2yaml/wasm2yaml.cpp
+++ b/llvm/tools/obj2yaml/wasm2yaml.cpp
@@ -155,6 +155,16 @@ WasmDumper::dumpCustomSection(const WasmSection &WasmSec) {
ProducersSec->SDKs.push_back(Producer);
}
CustomSec = std::move(ProducersSec);
+ } else if (WasmSec.Name == "target_features") {
+ std::unique_ptr<WasmYAML::TargetFeaturesSection> TargetFeaturesSec =
+ make_unique<WasmYAML::TargetFeaturesSection>();
+ 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<WasmYAML::CustomSection>(WasmSec.Name);
}
diff --git a/llvm/tools/yaml2obj/yaml2wasm.cpp b/llvm/tools/yaml2obj/yaml2wasm.cpp
index fcbcb8a40d5..322ac0117ba 100644
--- a/llvm/tools/yaml2obj/yaml2wasm.cpp
+++ b/llvm/tools/yaml2obj/yaml2wasm.cpp
@@ -49,6 +49,8 @@ private:
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;
@@ -280,6 +282,17 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
}
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);
+ writeStringRef(E.Name, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
WasmYAML::CustomSection &Section) {
if (auto S = dyn_cast<WasmYAML::DylinkSection>(&Section)) {
if (auto Err = writeSectionContent(OS, *S))
@@ -293,6 +306,9 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
} else if (auto S = dyn_cast<WasmYAML::ProducersSection>(&Section)) {
if (auto Err = writeSectionContent(OS, *S))
return Err;
+ } else if (auto S = dyn_cast<WasmYAML::TargetFeaturesSection>(&Section)) {
+ if (auto Err = writeSectionContent(OS, *S))
+ return Err;
} else {
writeStringRef(Section.Name, OS);
Section.Payload.writeAsBinary(OS);
OpenPOWER on IntegriCloud