[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
This commit is contained in:
parent
e0941cb326
commit
f6f4f84378
|
@ -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"
|
||||||
|
...
|
|
@ -0,0 +1,11 @@
|
||||||
|
--- !WASM
|
||||||
|
FileHeader:
|
||||||
|
Version: 0x00000001
|
||||||
|
Sections:
|
||||||
|
- Type: CUSTOM
|
||||||
|
Name: linking
|
||||||
|
Version: 2
|
||||||
|
- Type: CUSTOM
|
||||||
|
Name: target_features
|
||||||
|
Features: [ ]
|
||||||
|
...
|
|
@ -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"
|
||||||
|
...
|
|
@ -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"
|
||||||
|
...
|
|
@ -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: ...
|
|
@ -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"
|
|
@ -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: ...
|
|
@ -244,8 +244,6 @@ void ObjFile::parse() {
|
||||||
CustomSections.emplace_back(make<InputSection>(Section, this));
|
CustomSections.emplace_back(make<InputSection>(Section, this));
|
||||||
CustomSections.back()->setRelocations(Section.Relocations);
|
CustomSections.back()->setRelocations(Section.Relocations);
|
||||||
CustomSectionsByIndex[SectionIndex] = CustomSections.back();
|
CustomSectionsByIndex[SectionIndex] = CustomSections.back();
|
||||||
if (Section.Name == "producers")
|
|
||||||
ProducersSection = &Section;
|
|
||||||
}
|
}
|
||||||
SectionIndex++;
|
SectionIndex++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,6 @@ public:
|
||||||
|
|
||||||
const WasmSection *CodeSection = nullptr;
|
const WasmSection *CodeSection = nullptr;
|
||||||
const WasmSection *DataSection = nullptr;
|
const WasmSection *DataSection = nullptr;
|
||||||
const WasmSection *ProducersSection = nullptr;
|
|
||||||
|
|
||||||
// Maps input type indices to output type indices
|
// Maps input type indices to output type indices
|
||||||
std::vector<uint32_t> TypeMap;
|
std::vector<uint32_t> TypeMap;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "lld/Common/Strings.h"
|
#include "lld/Common/Strings.h"
|
||||||
#include "lld/Common/Threads.h"
|
#include "lld/Common/Threads.h"
|
||||||
#include "llvm/ADT/DenseSet.h"
|
#include "llvm/ADT/DenseSet.h"
|
||||||
|
#include "llvm/ADT/SmallSet.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
#include "llvm/BinaryFormat/Wasm.h"
|
#include "llvm/BinaryFormat/Wasm.h"
|
||||||
|
@ -68,6 +69,7 @@ private:
|
||||||
void calculateInitFunctions();
|
void calculateInitFunctions();
|
||||||
void processRelocations(InputChunk *Chunk);
|
void processRelocations(InputChunk *Chunk);
|
||||||
void assignIndexes();
|
void assignIndexes();
|
||||||
|
void calculateTargetFeatures();
|
||||||
void calculateImports();
|
void calculateImports();
|
||||||
void calculateExports();
|
void calculateExports();
|
||||||
void calculateCustomSections();
|
void calculateCustomSections();
|
||||||
|
@ -99,6 +101,7 @@ private:
|
||||||
void createLinkingSection();
|
void createLinkingSection();
|
||||||
void createNameSection();
|
void createNameSection();
|
||||||
void createProducersSection();
|
void createProducersSection();
|
||||||
|
void createTargetFeaturesSection();
|
||||||
|
|
||||||
void writeHeader();
|
void writeHeader();
|
||||||
void writeSections();
|
void writeSections();
|
||||||
|
@ -129,6 +132,7 @@ private:
|
||||||
|
|
||||||
llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
|
llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
|
||||||
llvm::StringMap<SectionSymbol *> CustomSectionSymbols;
|
llvm::StringMap<SectionSymbol *> CustomSectionSymbols;
|
||||||
|
llvm::SmallSet<std::string, 8> TargetFeatures;
|
||||||
|
|
||||||
// Elements that are used to construct the final output
|
// Elements that are used to construct the final output
|
||||||
std::string Header;
|
std::string Header;
|
||||||
|
@ -344,7 +348,7 @@ void Writer::calculateCustomSections() {
|
||||||
// These custom sections are known the linker and synthesized rather than
|
// These custom sections are known the linker and synthesized rather than
|
||||||
// blindly copied
|
// blindly copied
|
||||||
if (Name == "linking" || Name == "name" || Name == "producers" ||
|
if (Name == "linking" || Name == "name" || Name == "producers" ||
|
||||||
Name.startswith("reloc."))
|
Name == "target_features" || Name.startswith("reloc."))
|
||||||
continue;
|
continue;
|
||||||
// .. or it is a debug section
|
// .. or it is a debug section
|
||||||
if (StripDebug && Name.startswith(".debug_"))
|
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() {
|
void Writer::writeHeader() {
|
||||||
memcpy(Buffer->getBufferStart(), Header.data(), Header.size());
|
memcpy(Buffer->getBufferStart(), Header.data(), Header.size());
|
||||||
}
|
}
|
||||||
|
@ -844,8 +865,10 @@ void Writer::createSections() {
|
||||||
if (!Config->StripDebug && !Config->StripAll)
|
if (!Config->StripDebug && !Config->StripAll)
|
||||||
createNameSection();
|
createNameSection();
|
||||||
|
|
||||||
if (!Config->StripAll)
|
if (!Config->StripAll) {
|
||||||
createProducersSection();
|
createProducersSection();
|
||||||
|
createTargetFeaturesSection();
|
||||||
|
}
|
||||||
|
|
||||||
for (OutputSection *S : OutputSections) {
|
for (OutputSection *S : OutputSections) {
|
||||||
S->setOffset(FileSize);
|
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() {
|
void Writer::calculateImports() {
|
||||||
for (Symbol *Sym : Symtab->getSymbols()) {
|
for (Symbol *Sym : Symtab->getSymbols()) {
|
||||||
if (!Sym->isUndefined())
|
if (!Sym->isUndefined())
|
||||||
|
@ -1225,6 +1290,8 @@ void Writer::run() {
|
||||||
if (!Config->Pic)
|
if (!Config->Pic)
|
||||||
TableBase = 1;
|
TableBase = 1;
|
||||||
|
|
||||||
|
log("-- calculateTargetFeatures");
|
||||||
|
calculateTargetFeatures();
|
||||||
log("-- calculateImports");
|
log("-- calculateImports");
|
||||||
calculateImports();
|
calculateImports();
|
||||||
log("-- assignIndexes");
|
log("-- assignIndexes");
|
||||||
|
|
|
@ -48,6 +48,11 @@ struct WasmProducerInfo {
|
||||||
std::vector<std::pair<std::string, std::string>> SDKs;
|
std::vector<std::pair<std::string, std::string>> SDKs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WasmFeatureEntry {
|
||||||
|
uint8_t Prefix;
|
||||||
|
std::string Name;
|
||||||
|
};
|
||||||
|
|
||||||
struct WasmExport {
|
struct WasmExport {
|
||||||
StringRef Name;
|
StringRef Name;
|
||||||
uint8_t Kind;
|
uint8_t Kind;
|
||||||
|
@ -253,6 +258,13 @@ enum : unsigned {
|
||||||
WASM_SEGMENT_HAS_MEMINDEX = 0x02,
|
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
|
// Kind codes used in the custom "name" section
|
||||||
enum : unsigned {
|
enum : unsigned {
|
||||||
WASM_NAMES_FUNCTION = 0x1,
|
WASM_NAMES_FUNCTION = 0x1,
|
||||||
|
|
|
@ -130,6 +130,9 @@ public:
|
||||||
|
|
||||||
const wasm::WasmDylinkInfo &dylinkInfo() const { return DylinkInfo; }
|
const wasm::WasmDylinkInfo &dylinkInfo() const { return DylinkInfo; }
|
||||||
const wasm::WasmProducerInfo &getProducerInfo() const { return ProducerInfo; }
|
const wasm::WasmProducerInfo &getProducerInfo() const { return ProducerInfo; }
|
||||||
|
ArrayRef<wasm::WasmFeatureEntry> getTargetFeatures() const {
|
||||||
|
return TargetFeatures;
|
||||||
|
}
|
||||||
ArrayRef<wasm::WasmSignature> types() const { return Signatures; }
|
ArrayRef<wasm::WasmSignature> types() const { return Signatures; }
|
||||||
ArrayRef<uint32_t> functionTypes() const { return FunctionTypes; }
|
ArrayRef<uint32_t> functionTypes() const { return FunctionTypes; }
|
||||||
ArrayRef<wasm::WasmImport> imports() const { return Imports; }
|
ArrayRef<wasm::WasmImport> imports() const { return Imports; }
|
||||||
|
@ -252,12 +255,14 @@ private:
|
||||||
Error parseLinkingSectionSymtab(ReadContext &Ctx);
|
Error parseLinkingSectionSymtab(ReadContext &Ctx);
|
||||||
Error parseLinkingSectionComdat(ReadContext &Ctx);
|
Error parseLinkingSectionComdat(ReadContext &Ctx);
|
||||||
Error parseProducersSection(ReadContext &Ctx);
|
Error parseProducersSection(ReadContext &Ctx);
|
||||||
|
Error parseTargetFeaturesSection(ReadContext &Ctx);
|
||||||
Error parseRelocSection(StringRef Name, ReadContext &Ctx);
|
Error parseRelocSection(StringRef Name, ReadContext &Ctx);
|
||||||
|
|
||||||
wasm::WasmObjectHeader Header;
|
wasm::WasmObjectHeader Header;
|
||||||
std::vector<WasmSection> Sections;
|
std::vector<WasmSection> Sections;
|
||||||
wasm::WasmDylinkInfo DylinkInfo;
|
wasm::WasmDylinkInfo DylinkInfo;
|
||||||
wasm::WasmProducerInfo ProducerInfo;
|
wasm::WasmProducerInfo ProducerInfo;
|
||||||
|
std::vector<wasm::WasmFeatureEntry> TargetFeatures;
|
||||||
std::vector<wasm::WasmSignature> Signatures;
|
std::vector<wasm::WasmSignature> Signatures;
|
||||||
std::vector<uint32_t> FunctionTypes;
|
std::vector<uint32_t> FunctionTypes;
|
||||||
std::vector<wasm::WasmTable> Tables;
|
std::vector<wasm::WasmTable> Tables;
|
||||||
|
@ -318,6 +323,8 @@ public:
|
||||||
WASM_SEC_ORDER_NAME,
|
WASM_SEC_ORDER_NAME,
|
||||||
// "producers" section must appear after "name" section.
|
// "producers" section must appear after "name" section.
|
||||||
WASM_SEC_ORDER_PRODUCERS,
|
WASM_SEC_ORDER_PRODUCERS,
|
||||||
|
// "target_features" section must appear after producers section
|
||||||
|
WASM_SEC_ORDER_TARGET_FEATURES,
|
||||||
|
|
||||||
// Must be last
|
// Must be last
|
||||||
WASM_NUM_SEC_ORDERS
|
WASM_NUM_SEC_ORDERS
|
||||||
|
|
|
@ -38,6 +38,7 @@ LLVM_YAML_STRONG_TYPEDEF(uint32_t, SymbolKind)
|
||||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, SegmentFlags)
|
LLVM_YAML_STRONG_TYPEDEF(uint32_t, SegmentFlags)
|
||||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, LimitFlags)
|
LLVM_YAML_STRONG_TYPEDEF(uint32_t, LimitFlags)
|
||||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ComdatKind)
|
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ComdatKind)
|
||||||
|
LLVM_YAML_STRONG_TYPEDEF(uint32_t, FeaturePolicyPrefix)
|
||||||
|
|
||||||
struct FileHeader {
|
struct FileHeader {
|
||||||
yaml::Hex32 Version;
|
yaml::Hex32 Version;
|
||||||
|
@ -128,6 +129,11 @@ struct ProducerEntry {
|
||||||
std::string Version;
|
std::string Version;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FeatureEntry {
|
||||||
|
FeaturePolicyPrefix Prefix;
|
||||||
|
std::string Name;
|
||||||
|
};
|
||||||
|
|
||||||
struct SegmentInfo {
|
struct SegmentInfo {
|
||||||
uint32_t Index;
|
uint32_t Index;
|
||||||
StringRef Name;
|
StringRef Name;
|
||||||
|
@ -242,6 +248,17 @@ struct ProducersSection : CustomSection {
|
||||||
std::vector<ProducerEntry> SDKs;
|
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 {
|
struct TypeSection : Section {
|
||||||
TypeSection() : Section(wasm::WASM_SEC_TYPE) {}
|
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::Relocation)
|
||||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::NameEntry)
|
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::NameEntry)
|
||||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ProducerEntry)
|
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::SegmentInfo)
|
||||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SymbolInfo)
|
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SymbolInfo)
|
||||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::InitFunction)
|
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);
|
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> {
|
template <> struct MappingTraits<WasmYAML::SegmentInfo> {
|
||||||
static void mapping(IO &IO, WasmYAML::SegmentInfo &SegmentInfo);
|
static void mapping(IO &IO, WasmYAML::SegmentInfo &SegmentInfo);
|
||||||
};
|
};
|
||||||
|
|
|
@ -135,9 +135,10 @@ public:
|
||||||
SectionKind Kind;
|
SectionKind Kind;
|
||||||
};
|
};
|
||||||
static SectionType SectionTypes[] = {
|
static SectionType SectionTypes[] = {
|
||||||
{ ".text", SectionKind::getText() },
|
{".text", SectionKind::getText()},
|
||||||
{ ".rodata", SectionKind::getReadOnly() },
|
{".rodata", SectionKind::getReadOnly()},
|
||||||
{ ".data", SectionKind::getData() },
|
{".data", SectionKind::getData()},
|
||||||
|
{".custom_section", SectionKind::getMetadata()},
|
||||||
// TODO: add more types.
|
// TODO: add more types.
|
||||||
};
|
};
|
||||||
for (size_t I = 0; I < sizeof(SectionTypes) / sizeof(SectionType); I++) {
|
for (size_t I = 0; I < sizeof(SectionTypes) / sizeof(SectionType); I++) {
|
||||||
|
|
|
@ -250,6 +250,7 @@ class WasmObjectWriter : public MCObjectWriter {
|
||||||
// section.
|
// section.
|
||||||
std::vector<WasmCustomSection> CustomSections;
|
std::vector<WasmCustomSection> CustomSections;
|
||||||
std::unique_ptr<WasmCustomSection> ProducersSection;
|
std::unique_ptr<WasmCustomSection> ProducersSection;
|
||||||
|
std::unique_ptr<WasmCustomSection> TargetFeaturesSection;
|
||||||
// Relocations for fixing up references in the custom sections.
|
// Relocations for fixing up references in the custom sections.
|
||||||
DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>>
|
DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>>
|
||||||
CustomSectionsRelocations;
|
CustomSectionsRelocations;
|
||||||
|
@ -291,6 +292,7 @@ private:
|
||||||
DataLocations.clear();
|
DataLocations.clear();
|
||||||
CustomSections.clear();
|
CustomSections.clear();
|
||||||
ProducersSection.reset();
|
ProducersSection.reset();
|
||||||
|
TargetFeaturesSection.reset();
|
||||||
CustomSectionsRelocations.clear();
|
CustomSectionsRelocations.clear();
|
||||||
SignatureIndices.clear();
|
SignatureIndices.clear();
|
||||||
Signatures.clear();
|
Signatures.clear();
|
||||||
|
@ -1286,11 +1288,16 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||||
Twine(SectionName));
|
Twine(SectionName));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separate out the producers section
|
// Separate out the producers and target features sections
|
||||||
if (Name == "producers") {
|
if (Name == "producers") {
|
||||||
ProducersSection = llvm::make_unique<WasmCustomSection>(Name, &Section);
|
ProducersSection = llvm::make_unique<WasmCustomSection>(Name, &Section);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (Name == "target_features") {
|
||||||
|
TargetFeaturesSection =
|
||||||
|
llvm::make_unique<WasmCustomSection>(Name, &Section);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
CustomSections.emplace_back(Name, &Section);
|
CustomSections.emplace_back(Name, &Section);
|
||||||
}
|
}
|
||||||
|
@ -1593,6 +1600,8 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||||
writeCustomRelocSections();
|
writeCustomRelocSections();
|
||||||
if (ProducersSection)
|
if (ProducersSection)
|
||||||
writeCustomSection(*ProducersSection, Asm, Layout);
|
writeCustomSection(*ProducersSection, Asm, Layout);
|
||||||
|
if (TargetFeaturesSection)
|
||||||
|
writeCustomSection(*TargetFeaturesSection, Asm, Layout);
|
||||||
|
|
||||||
// TODO: Translate the .comment section to the output.
|
// TODO: Translate the .comment section to the output.
|
||||||
return W.OS.tell() - StartOffset;
|
return W.OS.tell() - StartOffset;
|
||||||
|
|
|
@ -715,6 +715,36 @@ Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
|
||||||
return Error::success();
|
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) {
|
Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
|
||||||
uint32_t SectionIndex = readVaruint32(Ctx);
|
uint32_t SectionIndex = readVaruint32(Ctx);
|
||||||
if (SectionIndex >= Sections.size())
|
if (SectionIndex >= Sections.size())
|
||||||
|
@ -816,6 +846,9 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
|
||||||
} else if (Sec.Name == "producers") {
|
} else if (Sec.Name == "producers") {
|
||||||
if (Error Err = parseProducersSection(Ctx))
|
if (Error Err = parseProducersSection(Ctx))
|
||||||
return Err;
|
return Err;
|
||||||
|
} else if (Sec.Name == "target_features") {
|
||||||
|
if (Error Err = parseTargetFeaturesSection(Ctx))
|
||||||
|
return Err;
|
||||||
} else if (Sec.Name.startswith("reloc.")) {
|
} else if (Sec.Name.startswith("reloc.")) {
|
||||||
if (Error Err = parseRelocSection(Sec.Name, Ctx))
|
if (Error Err = parseRelocSection(Sec.Name, Ctx))
|
||||||
return Err;
|
return Err;
|
||||||
|
@ -1528,6 +1561,7 @@ int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
|
||||||
.StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
|
.StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
|
||||||
.Case("name", WASM_SEC_ORDER_NAME)
|
.Case("name", WASM_SEC_ORDER_NAME)
|
||||||
.Case("producers", WASM_SEC_ORDER_PRODUCERS)
|
.Case("producers", WASM_SEC_ORDER_PRODUCERS)
|
||||||
|
.Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
|
||||||
.Default(WASM_SEC_ORDER_NONE);
|
.Default(WASM_SEC_ORDER_NONE);
|
||||||
case wasm::WASM_SEC_TYPE:
|
case wasm::WASM_SEC_TYPE:
|
||||||
return WASM_SEC_ORDER_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_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME}, // WASM_SEC_ORDER_LINKING,
|
||||||
{}, // WASM_SEC_ORDER_RELOC (can be repeated),
|
{}, // WASM_SEC_ORDER_RELOC (can be repeated),
|
||||||
{WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS}, // WASM_SEC_ORDER_NAME,
|
{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,
|
bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
|
||||||
|
|
|
@ -81,6 +81,12 @@ static void sectionMapping(IO &IO, WasmYAML::ProducersSection &Section) {
|
||||||
IO.mapOptional("SDKs", Section.SDKs);
|
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) {
|
static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) {
|
||||||
commonSectionMapping(IO, Section);
|
commonSectionMapping(IO, Section);
|
||||||
IO.mapRequired("Name", Section.Name);
|
IO.mapRequired("Name", Section.Name);
|
||||||
|
@ -180,6 +186,10 @@ void MappingTraits<std::unique_ptr<WasmYAML::Section>>::mapping(
|
||||||
if (!IO.outputting())
|
if (!IO.outputting())
|
||||||
Section.reset(new WasmYAML::ProducersSection());
|
Section.reset(new WasmYAML::ProducersSection());
|
||||||
sectionMapping(IO, *cast<WasmYAML::ProducersSection>(Section.get()));
|
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 {
|
} else {
|
||||||
if (!IO.outputting())
|
if (!IO.outputting())
|
||||||
Section.reset(new WasmYAML::CustomSection(SectionName));
|
Section.reset(new WasmYAML::CustomSection(SectionName));
|
||||||
|
@ -310,6 +320,21 @@ void MappingTraits<WasmYAML::ProducerEntry>::mapping(
|
||||||
IO.mapRequired("Version", ProducerEntry.Version);
|
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(
|
void MappingTraits<WasmYAML::SegmentInfo>::mapping(
|
||||||
IO &IO, WasmYAML::SegmentInfo &SegmentInfo) {
|
IO &IO, WasmYAML::SegmentInfo &SegmentInfo) {
|
||||||
IO.mapRequired("Index", SegmentInfo.Index);
|
IO.mapRequired("Index", SegmentInfo.Index);
|
||||||
|
|
|
@ -21,8 +21,10 @@
|
||||||
#include "WebAssemblyMCInstLower.h"
|
#include "WebAssemblyMCInstLower.h"
|
||||||
#include "WebAssemblyMachineFunctionInfo.h"
|
#include "WebAssemblyMachineFunctionInfo.h"
|
||||||
#include "WebAssemblyRegisterInfo.h"
|
#include "WebAssemblyRegisterInfo.h"
|
||||||
|
#include "WebAssemblyTargetMachine.h"
|
||||||
#include "llvm/ADT/SmallSet.h"
|
#include "llvm/ADT/SmallSet.h"
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
|
#include "llvm/BinaryFormat/Wasm.h"
|
||||||
#include "llvm/CodeGen/Analysis.h"
|
#include "llvm/CodeGen/Analysis.h"
|
||||||
#include "llvm/CodeGen/AsmPrinter.h"
|
#include "llvm/CodeGen/AsmPrinter.h"
|
||||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||||
|
@ -159,6 +161,7 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitProducerInfo(M);
|
EmitProducerInfo(M);
|
||||||
|
EmitTargetFeatures();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
|
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() {
|
void WebAssemblyAsmPrinter::EmitConstantPool() {
|
||||||
assert(MF->getConstantPool()->getConstants().empty() &&
|
assert(MF->getConstantPool()->getConstants().empty() &&
|
||||||
"WebAssembly disables constant pools");
|
"WebAssembly disables constant pools");
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
|
|
||||||
void EmitEndOfAsmFile(Module &M) override;
|
void EmitEndOfAsmFile(Module &M) override;
|
||||||
void EmitProducerInfo(Module &M);
|
void EmitProducerInfo(Module &M);
|
||||||
|
void EmitTargetFeatures();
|
||||||
void EmitJumpTableInfo() override;
|
void EmitJumpTableInfo() override;
|
||||||
void EmitConstantPool() override;
|
void EmitConstantPool() override;
|
||||||
void EmitFunctionBodyStart() override;
|
void EmitFunctionBodyStart() override;
|
||||||
|
|
|
@ -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
|
|
@ -24,4 +24,9 @@ target triple = "wasm32-unknown-unknown"
|
||||||
; CHECK-NEXT: Name: .data
|
; CHECK-NEXT: Name: .data
|
||||||
; CHECK-NEXT: Alignment: 0
|
; CHECK-NEXT: Alignment: 0
|
||||||
; CHECK-NEXT: Flags: [ ]
|
; 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-NEXT: ...
|
||||||
|
|
|
@ -87,4 +87,9 @@ entry:
|
||||||
; CHECK-NEXT: Name: bar
|
; CHECK-NEXT: Name: bar
|
||||||
; CHECK-NEXT: Flags: [ UNDEFINED ]
|
; CHECK-NEXT: Flags: [ UNDEFINED ]
|
||||||
; CHECK-NEXT: Function: 0
|
; 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: ...
|
; CHECK-NEXT: ...
|
||||||
|
|
|
@ -78,4 +78,9 @@ target triple = "wasm32-unknown-unknown"
|
||||||
; CHECK-NEXT: Name: .bss.bar
|
; CHECK-NEXT: Name: .bss.bar
|
||||||
; CHECK-NEXT: Alignment: 0
|
; CHECK-NEXT: Alignment: 0
|
||||||
; CHECK-NEXT: Flags: [ ]
|
; 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-NEXT: ...
|
||||||
|
|
|
@ -119,4 +119,9 @@ define linkonce_odr i32 @sharedFn() #1 comdat($sharedComdat) {
|
||||||
; CHECK-NEXT: Index: 3
|
; CHECK-NEXT: Index: 3
|
||||||
; CHECK-NEXT: - Kind: DATA
|
; CHECK-NEXT: - Kind: DATA
|
||||||
; CHECK-NEXT: Index: 0
|
; 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: ...
|
; CHECK-NEXT: ...
|
||||||
|
|
|
@ -130,6 +130,12 @@
|
||||||
; CHECK-NEXT: Offset: 1021
|
; CHECK-NEXT: Offset: 1021
|
||||||
; CHECK-NEXT: Name: producers
|
; CHECK-NEXT: Name: producers
|
||||||
; CHECK-NEXT: }
|
; 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:]
|
||||||
; CHECK-NEXT:Relocations [
|
; CHECK-NEXT:Relocations [
|
||||||
; CHECK-NEXT: Section (6) DATA {
|
; CHECK-NEXT: Section (6) DATA {
|
||||||
|
|
|
@ -70,4 +70,9 @@ target triple = "wasm32-unknown-unknown"
|
||||||
; CHECK-NEXT: Name: .sec2
|
; CHECK-NEXT: Name: .sec2
|
||||||
; CHECK-NEXT: Alignment: 3
|
; CHECK-NEXT: Alignment: 3
|
||||||
; CHECK-NEXT: Flags: [ ]
|
; 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-NEXT: ...
|
||||||
|
|
|
@ -181,4 +181,9 @@ declare void @func3()
|
||||||
; CHECK-NEXT: Symbol: 10
|
; CHECK-NEXT: Symbol: 10
|
||||||
; CHECK-NEXT: - Priority: 65535
|
; CHECK-NEXT: - Priority: 65535
|
||||||
; CHECK-NEXT: Symbol: 7
|
; 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: ...
|
; CHECK-NEXT: ...
|
||||||
|
|
|
@ -25,4 +25,9 @@ entry:
|
||||||
; CHECK-NEXT: Name: hiddenVis
|
; CHECK-NEXT: Name: hiddenVis
|
||||||
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
|
; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
|
||||||
; CHECK-NEXT: Function: 1
|
; 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: ...
|
; CHECK-NEXT: ...
|
||||||
|
|
|
@ -207,6 +207,11 @@ entry:
|
||||||
; CHECK-NEXT: Name: .data.alias_address
|
; CHECK-NEXT: Name: .data.alias_address
|
||||||
; CHECK-NEXT: Alignment: 3
|
; CHECK-NEXT: Alignment: 3
|
||||||
; CHECK-NEXT: Flags: [ ]
|
; 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-NEXT: ...
|
||||||
|
|
||||||
; CHECK-SYMS: SYMBOL TABLE:
|
; CHECK-SYMS: SYMBOL TABLE:
|
||||||
|
|
|
@ -30,4 +30,9 @@ entry:
|
||||||
; CHECK-NEXT: Kind: DATA
|
; CHECK-NEXT: Kind: DATA
|
||||||
; CHECK-NEXT: Name: weak_external_data
|
; CHECK-NEXT: Name: weak_external_data
|
||||||
; CHECK-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ]
|
; 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: ...
|
; CHECK-NEXT: ...
|
||||||
|
|
|
@ -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: ''
|
|
@ -155,6 +155,16 @@ WasmDumper::dumpCustomSection(const WasmSection &WasmSec) {
|
||||||
ProducersSec->SDKs.push_back(Producer);
|
ProducersSec->SDKs.push_back(Producer);
|
||||||
}
|
}
|
||||||
CustomSec = std::move(ProducersSec);
|
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 {
|
} else {
|
||||||
CustomSec = make_unique<WasmYAML::CustomSection>(WasmSec.Name);
|
CustomSec = make_unique<WasmYAML::CustomSection>(WasmSec.Name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,8 @@ private:
|
||||||
int writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section);
|
int writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section);
|
||||||
int writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section);
|
int writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section);
|
||||||
int writeSectionContent(raw_ostream &OS, WasmYAML::ProducersSection &Section);
|
int writeSectionContent(raw_ostream &OS, WasmYAML::ProducersSection &Section);
|
||||||
|
int writeSectionContent(raw_ostream &OS,
|
||||||
|
WasmYAML::TargetFeaturesSection &Section);
|
||||||
WasmYAML::Object &Obj;
|
WasmYAML::Object &Obj;
|
||||||
uint32_t NumImportedFunctions = 0;
|
uint32_t NumImportedFunctions = 0;
|
||||||
uint32_t NumImportedGlobals = 0;
|
uint32_t NumImportedGlobals = 0;
|
||||||
|
@ -279,6 +281,17 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
|
||||||
return 0;
|
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);
|
||||||
|
writeStringRef(E.Name, OS);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int WasmWriter::writeSectionContent(raw_ostream &OS,
|
int WasmWriter::writeSectionContent(raw_ostream &OS,
|
||||||
WasmYAML::CustomSection &Section) {
|
WasmYAML::CustomSection &Section) {
|
||||||
if (auto S = dyn_cast<WasmYAML::DylinkSection>(&Section)) {
|
if (auto S = dyn_cast<WasmYAML::DylinkSection>(&Section)) {
|
||||||
|
@ -293,6 +306,9 @@ int WasmWriter::writeSectionContent(raw_ostream &OS,
|
||||||
} else if (auto S = dyn_cast<WasmYAML::ProducersSection>(&Section)) {
|
} else if (auto S = dyn_cast<WasmYAML::ProducersSection>(&Section)) {
|
||||||
if (auto Err = writeSectionContent(OS, *S))
|
if (auto Err = writeSectionContent(OS, *S))
|
||||||
return Err;
|
return Err;
|
||||||
|
} else if (auto S = dyn_cast<WasmYAML::TargetFeaturesSection>(&Section)) {
|
||||||
|
if (auto Err = writeSectionContent(OS, *S))
|
||||||
|
return Err;
|
||||||
} else {
|
} else {
|
||||||
writeStringRef(Section.Name, OS);
|
writeStringRef(Section.Name, OS);
|
||||||
Section.Payload.writeAsBinary(OS);
|
Section.Payload.writeAsBinary(OS);
|
||||||
|
|
Loading…
Reference in New Issue