[llvm] a5a3659 - [WebAssembly][yaml2obj][obj2yaml] Elem sections for nonzero tables
Andy Wingo via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 5 02:46:01 PST 2021
Author: Andy Wingo
Date: 2021-03-05T11:45:15+01:00
New Revision: a5a3659de788fe4972ac5e91a455add85d037a33
URL: https://github.com/llvm/llvm-project/commit/a5a3659de788fe4972ac5e91a455add85d037a33
DIFF: https://github.com/llvm/llvm-project/commit/a5a3659de788fe4972ac5e91a455add85d037a33.diff
LOG: [WebAssembly][yaml2obj][obj2yaml] Elem sections for nonzero tables
With reference types, tables can have non-zero table numbers. This
commit adds support for element sections against these tables.
Differential Revision: https://reviews.llvm.org/D97923
Added:
llvm/test/ObjectYAML/wasm/multiple-tables.yaml
Modified:
llvm/include/llvm/BinaryFormat/Wasm.h
llvm/include/llvm/Object/Wasm.h
llvm/include/llvm/ObjectYAML/WasmYAML.h
llvm/lib/MC/WasmObjectWriter.cpp
llvm/lib/Object/WasmObjectFile.cpp
llvm/lib/ObjectYAML/WasmEmitter.cpp
llvm/lib/ObjectYAML/WasmYAML.cpp
llvm/tools/obj2yaml/wasm2yaml.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 063c6a3f9449..9c3f2569addc 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -159,7 +159,9 @@ struct WasmDataSegment {
};
struct WasmElemSegment {
- uint32_t TableIndex;
+ uint32_t Flags;
+ uint32_t TableNumber;
+ uint8_t ElemKind;
WasmInitExpr Offset;
std::vector<uint32_t> Functions;
};
@@ -307,6 +309,13 @@ enum : unsigned {
WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02,
};
+enum : unsigned {
+ WASM_ELEM_SEGMENT_IS_PASSIVE = 0x01,
+ WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER = 0x02,
+ WASM_ELEM_SEGMENT_HAS_INIT_EXPRS = 0x04,
+};
+const unsigned WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND = 0x3;
+
// Feature policy prefixes used in the custom "target_features" section
enum : uint8_t {
WASM_FEATURE_PREFIX_USED = '+',
diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h
index f7cd2e622ae3..1e270814546a 100644
--- a/llvm/include/llvm/Object/Wasm.h
+++ b/llvm/include/llvm/Object/Wasm.h
@@ -220,9 +220,9 @@ class WasmObjectFile : public ObjectFile {
bool isValidFunctionIndex(uint32_t Index) const;
bool isDefinedFunctionIndex(uint32_t Index) const;
bool isValidGlobalIndex(uint32_t Index) const;
- bool isValidTableIndex(uint32_t Index) const;
+ bool isValidTableNumber(uint32_t Index) const;
bool isDefinedGlobalIndex(uint32_t Index) const;
- bool isDefinedTableIndex(uint32_t Index) const;
+ bool isDefinedTableNumber(uint32_t Index) const;
bool isValidEventIndex(uint32_t Index) const;
bool isDefinedEventIndex(uint32_t Index) const;
bool isValidFunctionSymbol(uint32_t Index) const;
diff --git a/llvm/include/llvm/ObjectYAML/WasmYAML.h b/llvm/include/llvm/ObjectYAML/WasmYAML.h
index 80f1b4006205..cc5df9674fb1 100644
--- a/llvm/include/llvm/ObjectYAML/WasmYAML.h
+++ b/llvm/include/llvm/ObjectYAML/WasmYAML.h
@@ -63,7 +63,9 @@ struct Export {
};
struct ElemSegment {
- uint32_t TableIndex;
+ uint32_t Flags;
+ uint32_t TableNumber;
+ ValueType ElemKind;
wasm::WasmInitExpr Offset;
std::vector<uint32_t> Functions;
};
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index b2c8c022b5c8..c8bc65467b8c 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -311,7 +311,8 @@ class WasmObjectWriter : public MCObjectWriter {
uint32_t NumElements);
void writeFunctionSection(ArrayRef<WasmFunction> Functions);
void writeExportSection(ArrayRef<wasm::WasmExport> Exports);
- void writeElemSection(ArrayRef<uint32_t> TableElems);
+ void writeElemSection(const MCSymbolWasm *IndirectFunctionTable,
+ ArrayRef<uint32_t> TableElems);
void writeDataCountSection();
uint32_t writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
ArrayRef<WasmFunction> Functions);
@@ -902,21 +903,39 @@ void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
endSection(Section);
}
-void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) {
+void WasmObjectWriter::writeElemSection(
+ const MCSymbolWasm *IndirectFunctionTable, ArrayRef<uint32_t> TableElems) {
if (TableElems.empty())
return;
+ assert(IndirectFunctionTable);
+
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_ELEM);
encodeULEB128(1, W->OS); // number of "segments"
- encodeULEB128(0, W->OS); // the table index
+
+ assert(WasmIndices.count(IndirectFunctionTable));
+ uint32_t TableNumber = WasmIndices.find(IndirectFunctionTable)->second;
+ uint32_t Flags = 0;
+ if (TableNumber)
+ Flags |= wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER;
+ encodeULEB128(Flags, W->OS);
+ if (Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
+ encodeULEB128(TableNumber, W->OS); // the table number
// init expr for starting offset
W->OS << char(wasm::WASM_OPCODE_I32_CONST);
encodeSLEB128(InitialTableOffset, W->OS);
W->OS << char(wasm::WASM_OPCODE_END);
+ if (Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
+ // We only write active function table initializers, for which the elem kind
+ // is specified to be written as 0x00 and interpreted to mean "funcref".
+ const uint8_t ElemKind = 0;
+ W->OS << ElemKind;
+ }
+
encodeULEB128(TableElems.size(), W->OS);
for (uint32_t Elem : TableElems)
encodeULEB128(Elem, W->OS);
@@ -1824,7 +1843,10 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
writeEventSection(Events);
writeGlobalSection(Globals);
writeExportSection(Exports);
- writeElemSection(TableElems);
+ const MCSymbol *IndirectFunctionTable =
+ Asm.getContext().lookupSymbol("__indirect_function_table");
+ writeElemSection(cast_or_null<const MCSymbolWasm>(IndirectFunctionTable),
+ TableElems);
writeDataCountSection();
CodeSectionIndex = writeCodeSection(Asm, Layout, Functions);
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 40f468881edd..7fbb1862e05f 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -598,8 +598,8 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
case wasm::WASM_SYMBOL_TYPE_TABLE:
Info.ElementIndex = readVaruint32(Ctx);
- if (!isValidTableIndex(Info.ElementIndex) ||
- IsDefined != isDefinedTableIndex(Info.ElementIndex))
+ if (!isValidTableNumber(Info.ElementIndex) ||
+ IsDefined != isDefinedTableNumber(Info.ElementIndex))
return make_error<GenericBinaryError>("invalid table symbol index",
object_error::parse_failed);
if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
@@ -608,8 +608,8 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
object_error::parse_failed);
if (IsDefined) {
Info.Name = readString(Ctx);
- unsigned TableIndex = Info.ElementIndex - NumImportedTables;
- wasm::WasmTable &Table = Tables[TableIndex];
+ unsigned TableNumber = Info.ElementIndex - NumImportedTables;
+ wasm::WasmTable &Table = Tables[TableNumber];
TableType = &Table.Type;
if (Table.SymbolName.empty())
Table.SymbolName = Info.Name;
@@ -1220,7 +1220,7 @@ bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
return Index < NumImportedGlobals + Globals.size();
}
-bool WasmObjectFile::isValidTableIndex(uint32_t Index) const {
+bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {
return Index < NumImportedTables + Tables.size();
}
@@ -1228,8 +1228,8 @@ bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
}
-bool WasmObjectFile::isDefinedTableIndex(uint32_t Index) const {
- return Index >= NumImportedTables && isValidTableIndex(Index);
+bool WasmObjectFile::isDefinedTableNumber(uint32_t Index) const {
+ return Index >= NumImportedTables && isValidTableNumber(Index);
}
bool WasmObjectFile::isValidEventIndex(uint32_t Index) const {
@@ -1340,13 +1340,54 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
ElemSegments.reserve(Count);
while (Count--) {
wasm::WasmElemSegment Segment;
- Segment.TableIndex = readVaruint32(Ctx);
- if (Segment.TableIndex != 0) {
- return make_error<GenericBinaryError>("invalid TableIndex",
+ Segment.Flags = readVaruint32(Ctx);
+
+ uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |
+ wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |
+ wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;
+ if (Segment.Flags & ~SupportedFlags)
+ return make_error<GenericBinaryError>(
+ "Unsupported flags for element segment", object_error::parse_failed);
+
+ if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
+ Segment.TableNumber = readVaruint32(Ctx);
+ else
+ Segment.TableNumber = 0;
+ if (!isValidTableNumber(Segment.TableNumber))
+ return make_error<GenericBinaryError>("invalid TableNumber",
object_error::parse_failed);
+
+ if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) {
+ Segment.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
+ Segment.Offset.Value.Int32 = 0;
+ } else {
+ if (Error Err = readInitExpr(Segment.Offset, Ctx))
+ return Err;
}
- if (Error Err = readInitExpr(Segment.Offset, Ctx))
- return Err;
+
+ if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
+ Segment.ElemKind = readUint8(Ctx);
+ if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
+ if (Segment.ElemKind != uint8_t(wasm::ValType::FUNCREF) &&
+ Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF)) {
+ return make_error<GenericBinaryError>("invalid reference type",
+ object_error::parse_failed);
+ }
+ } else {
+ if (Segment.ElemKind != 0)
+ return make_error<GenericBinaryError>("invalid elemtype",
+ object_error::parse_failed);
+ Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
+ }
+ } else {
+ Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
+ }
+
+ if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS)
+ return make_error<GenericBinaryError>(
+ "elem segment init expressions not yet implemented",
+ object_error::parse_failed);
+
uint32_t NumElems = readVaruint32(Ctx);
while (NumElems--) {
Segment.Functions.push_back(readVaruint32(Ctx));
diff --git a/llvm/lib/ObjectYAML/WasmEmitter.cpp b/llvm/lib/ObjectYAML/WasmEmitter.cpp
index 83d4701ed3e6..ce5d624c7a0e 100644
--- a/llvm/lib/ObjectYAML/WasmEmitter.cpp
+++ b/llvm/lib/ObjectYAML/WasmEmitter.cpp
@@ -484,9 +484,24 @@ void WasmWriter::writeSectionContent(raw_ostream &OS,
WasmYAML::ElemSection &Section) {
encodeULEB128(Section.Segments.size(), OS);
for (auto &Segment : Section.Segments) {
- encodeULEB128(Segment.TableIndex, OS);
+ encodeULEB128(Segment.Flags, OS);
+ if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
+ encodeULEB128(Segment.TableNumber, OS);
+
writeInitExpr(OS, Segment.Offset);
+ if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
+ // We only support active function table initializers, for which the elem
+ // kind is specified to be written as 0x00 and interpreted to mean
+ // "funcref".
+ if (Segment.ElemKind != uint32_t(wasm::ValType::FUNCREF)) {
+ reportError("unexpected elemkind: " + Twine(Segment.ElemKind));
+ return;
+ }
+ const uint8_t ElemKind = 0;
+ writeUint8(OS, ElemKind);
+ }
+
encodeULEB128(Segment.Functions.size(), OS);
for (auto &Function : Segment.Functions)
encodeULEB128(Function, OS);
diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp
index b717bb5a560a..7e57df0c370b 100644
--- a/llvm/lib/ObjectYAML/WasmYAML.cpp
+++ b/llvm/lib/ObjectYAML/WasmYAML.cpp
@@ -374,6 +374,14 @@ void MappingTraits<WasmYAML::Limits>::mapping(IO &IO,
void MappingTraits<WasmYAML::ElemSegment>::mapping(
IO &IO, WasmYAML::ElemSegment &Segment) {
+ if (!IO.outputting() || Segment.Flags)
+ IO.mapOptional("Flags", Segment.Flags);
+ if (!IO.outputting() ||
+ Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
+ IO.mapOptional("TableNumber", Segment.TableNumber);
+ if (!IO.outputting() ||
+ Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND)
+ IO.mapOptional("ElemKind", Segment.ElemKind);
IO.mapRequired("Offset", Segment.Offset);
IO.mapRequired("Functions", Segment.Functions);
}
diff --git a/llvm/test/ObjectYAML/wasm/multiple-tables.yaml b/llvm/test/ObjectYAML/wasm/multiple-tables.yaml
new file mode 100644
index 000000000000..50f03bc90641
--- /dev/null
+++ b/llvm/test/ObjectYAML/wasm/multiple-tables.yaml
@@ -0,0 +1,123 @@
+# RUN: yaml2obj %s | obj2yaml | FileCheck %s
+
+--- !WASM
+FileHeader:
+ Version: 0x1
+Sections:
+ - Type: TYPE
+ Signatures:
+ - Index: 0
+ ParamTypes: []
+ ReturnTypes: []
+ - Type: IMPORT
+ Imports:
+ - Module: env
+ Field: table_a
+ Kind: TABLE
+ Table:
+ Index: 0
+ ElemType: FUNCREF
+ Limits:
+ Initial: 0x0
+ - Type: FUNCTION
+ FunctionTypes: [ 0 ]
+ - Type: TABLE
+ Tables:
+ - Index: 1
+ ElemType: FUNCREF
+ Limits:
+ Initial: 0x0
+ - Index: 2
+ ElemType: EXTERNREF
+ Limits:
+ Initial: 0x0
+ - Index: 3
+ ElemType: FUNCREF
+ Limits:
+ Flags: [ HAS_MAX ]
+ Initial: 0x3
+ Maximum: 0x3
+ - Type: EXPORT
+ Exports:
+ - Name: table_b
+ Kind: TABLE
+ Index: 1
+ - Name: table_c
+ Kind: TABLE
+ Index: 2
+ - Type: ELEM
+ Segments:
+ - Flags: 2
+ TableNumber: 3
+ ElemKind: FUNCREF
+ Offset:
+ Opcode: I32_CONST
+ Value: 1
+ Functions: [ 0, 0 ]
+ - Type: CODE
+ Functions:
+ - Index: 0
+ Locals: []
+ Body: 0B
+...
+
+# CHECK: --- !WASM
+# CHECK-NEXT: FileHeader:
+# CHECK-NEXT: Version: 0x1
+# CHECK-NEXT: Sections:
+# CHECK-NEXT: - Type: TYPE
+# CHECK-NEXT: Signatures:
+# CHECK-NEXT: - Index: 0
+# CHECK-NEXT: ParamTypes: []
+# CHECK-NEXT: ReturnTypes: []
+# CHECK-NEXT: - Type: IMPORT
+# CHECK-NEXT: Imports:
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: table_a
+# CHECK-NEXT: Kind: TABLE
+# CHECK-NEXT: Table:
+# CHECK-NEXT: Index: 0
+# CHECK-NEXT: ElemType: FUNCREF
+# CHECK-NEXT: Limits:
+# CHECK-NEXT: Initial: 0x0
+# CHECK-NEXT: - Type: FUNCTION
+# CHECK-NEXT: FunctionTypes: [ 0 ]
+# CHECK-NEXT: - Type: TABLE
+# CHECK-NEXT: Tables:
+# CHECK-NEXT: - Index: 1
+# CHECK-NEXT: ElemType: FUNCREF
+# CHECK-NEXT: Limits:
+# CHECK-NEXT: Initial: 0x0
+# CHECK-NEXT: - Index: 2
+# CHECK-NEXT: ElemType: EXTERNREF
+# CHECK-NEXT: Limits:
+# CHECK-NEXT: Initial: 0x0
+# CHECK-NEXT: - Index: 3
+# CHECK-NEXT: ElemType: FUNCREF
+# CHECK-NEXT: Limits:
+# CHECK-NEXT: Flags: [ HAS_MAX ]
+# CHECK-NEXT: Initial: 0x3
+# CHECK-NEXT: Maximum: 0x3
+# CHECK-NEXT: - Type: EXPORT
+# CHECK-NEXT: Exports:
+# CHECK-NEXT: - Name: table_b
+# CHECK-NEXT: Kind: TABLE
+# CHECK-NEXT: Index: 1
+# CHECK-NEXT: - Name: table_c
+# CHECK-NEXT: Kind: TABLE
+# CHECK-NEXT: Index: 2
+# CHECK-NEXT: - Type: ELEM
+# CHECK-NEXT: Segments:
+# CHECK-NEXT: - Flags: 2
+# CHECK-NEXT: TableNumber: 3
+# CHECK-NEXT: ElemKind: FUNCREF
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Opcode: I32_CONST
+# CHECK-NEXT: Value: 1
+# CHECK-NEXT: Functions: [ 0, 0 ]
+# CHECK-NEXT: - Type: CODE
+# CHECK-NEXT: Functions:
+# CHECK-NEXT: - Index: 0
+# CHECK-NEXT: Locals: []
+# CHECK-NEXT: Body: 0B
+# CHECK-NEXT: ...
diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp
index 2d7ff3b2f9a5..c421b14331c1 100644
--- a/llvm/tools/obj2yaml/wasm2yaml.cpp
+++ b/llvm/tools/obj2yaml/wasm2yaml.cpp
@@ -327,7 +327,9 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
auto ElemSec = std::make_unique<WasmYAML::ElemSection>();
for (auto &Segment : Obj.elements()) {
WasmYAML::ElemSegment Seg;
- Seg.TableIndex = Segment.TableIndex;
+ Seg.Flags = Segment.Flags;
+ Seg.TableNumber = Segment.TableNumber;
+ Seg.ElemKind = Segment.ElemKind;
Seg.Offset = Segment.Offset;
append_range(Seg.Functions, Segment.Functions);
ElemSec->Segments.push_back(Seg);
More information about the llvm-commits
mailing list