[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