[llvm] 0a6c4d8 - [WebAssmebly] Add support for defined wasm globals in MC and lld

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 30 12:44:23 PDT 2020


Author: Sam Clegg
Date: 2020-04-30T12:43:15-07:00
New Revision: 0a6c4d8d2ebc20b687341d3f66835a5071de055a

URL: https://github.com/llvm/llvm-project/commit/0a6c4d8d2ebc20b687341d3f66835a5071de055a
DIFF: https://github.com/llvm/llvm-project/commit/0a6c4d8d2ebc20b687341d3f66835a5071de055a.diff

LOG: [WebAssmebly] Add support for defined wasm globals in MC and lld

This change add support for defined wasm globals in the .s format,
the MC layer, and wasm-ld

Currently there is no support custom initialization and all wasm
globals are initialized to zero.

Fixes: PR45742

Differential Revision: https://reviews.llvm.org/D79137

Added: 
    lld/test/wasm/globals.s
    llvm/test/MC/WebAssembly/globals.s

Modified: 
    lld/wasm/WriterUtils.cpp
    llvm/include/llvm/BinaryFormat/Wasm.h
    llvm/lib/MC/WasmObjectWriter.cpp

Removed: 
    


################################################################################
diff  --git a/lld/test/wasm/globals.s b/lld/test/wasm/globals.s
new file mode 100644
index 000000000000..ec8d247779de
--- /dev/null
+++ b/lld/test/wasm/globals.s
@@ -0,0 +1,53 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
+# RUN: wasm-ld %t.o -o %t.wasm
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+.globl _start
+.globl read_global
+.globl write_global
+
+.globaltype foo_global, i32
+.globaltype bar_global, f32
+
+read_global:
+  .functype read_global () -> (i32)
+  global.get foo_global
+  end_function
+
+write_global:
+  .functype write_global (i32) -> ()
+  local.get 0
+  global.set foo_global
+  f32.const 1.0
+  global.set bar_global
+  end_function
+
+_start:
+  .functype _start () -> ()
+  i32.const 1
+  call write_global
+  end_function
+
+foo_global:
+bar_global:
+
+# CHECK:       - Type:            GLOBAL
+# CHECK-NEXT:    Globals:
+# CHECK-NEXT:      - Index:           0
+# CHECK-NEXT:        Type:            I32
+# CHECK-NEXT:        Mutable:         true
+# CHECK-NEXT:        InitExpr:
+# CHECK-NEXT:          Opcode:          I32_CONST
+# CHECK-NEXT:          Value:           66560
+# CHECK-NEXT:      - Index:           1
+# CHECK-NEXT:        Type:            I32
+# CHECK-NEXT:        Mutable:         true
+# CHECK-NEXT:        InitExpr:
+# CHECK-NEXT:          Opcode:          I32_CONST
+# CHECK-NEXT:          Value:           0
+# CHECK-NEXT:      - Index:           2
+# CHECK-NEXT:        Type:            F32
+# CHECK-NEXT:        Mutable:         true
+# CHECK-NEXT:        InitExpr:
+# CHECK-NEXT:          Opcode:          F32_CONST
+# CHECK-NEXT:          Value:           0

diff  --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp
index 4f1bce61d936..30e6bdf92ac9 100644
--- a/lld/wasm/WriterUtils.cpp
+++ b/lld/wasm/WriterUtils.cpp
@@ -100,6 +100,11 @@ void writeU32(raw_ostream &os, uint32_t number, const Twine &msg) {
   support::endian::write(os, number, support::little);
 }
 
+void writeU64(raw_ostream &os, uint64_t number, const Twine &msg) {
+  debugWrite(os.tell(), msg + "[0x" + utohexstr(number) + "]");
+  support::endian::write(os, number, support::little);
+}
+
 void writeValueType(raw_ostream &os, ValType type, const Twine &msg) {
   writeU8(os, static_cast<uint8_t>(type),
           msg + "[type: " + toString(type) + "]");
@@ -141,6 +146,12 @@ void writeInitExpr(raw_ostream &os, const WasmInitExpr &initExpr) {
   case WASM_OPCODE_I64_CONST:
     writeSleb128(os, initExpr.Value.Int64, "literal (i64)");
     break;
+  case WASM_OPCODE_F32_CONST:
+    writeU32(os, initExpr.Value.Float32, "literal (f32)");
+    break;
+  case WASM_OPCODE_F64_CONST:
+    writeU64(os, initExpr.Value.Float64, "literal (f64)");
+    break;
   case WASM_OPCODE_GLOBAL_GET:
     writeUleb128(os, initExpr.Value.Global, "literal (global index)");
     break;

diff  --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index dd743dbbbefa..7bc35317d618 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -75,10 +75,10 @@ struct WasmTable {
 struct WasmInitExpr {
   uint8_t Opcode;
   union {
-    int32_t Int32;
-    int64_t Int64;
-    int32_t Float32;
-    int64_t Float64;
+    uint32_t Int32;
+    uint64_t Int64;
+    uint32_t Float32;
+    uint64_t Float64;
     uint32_t Global;
   } Value;
 };

diff  --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index d51d3e1b5f71..0c09f99a7897 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -204,7 +204,7 @@ static void writePatchableSLEB(raw_pwrite_stream &Stream, int32_t X,
 }
 
 // Write X as a plain integer value at offset Offset in Stream.
-static void writeI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
+static void patchI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
   uint8_t Buffer[4];
   support::endian::write32le(Buffer, X);
   Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
@@ -308,6 +308,18 @@ class WasmObjectWriter : public MCObjectWriter {
     W.OS << Str;
   }
 
+  void writeI32(int32_t val) {
+    char Buffer[4];
+    support::endian::write32le(Buffer, val);
+    W.OS.write(Buffer, sizeof(Buffer));
+  }
+
+  void writeI64(int64_t val) {
+    char Buffer[8];
+    support::endian::write64le(Buffer, val);
+    W.OS.write(Buffer, sizeof(Buffer));
+  }
+
   void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); }
 
   void writeTypeSection(ArrayRef<WasmSignature> Signatures);
@@ -321,6 +333,7 @@ class WasmObjectWriter : public MCObjectWriter {
                         ArrayRef<WasmFunction> Functions);
   void writeDataSection();
   void writeEventSection(ArrayRef<wasm::WasmEventType> Events);
+  void writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals);
   void writeRelocSection(uint32_t SectionIndex, StringRef Name,
                          std::vector<WasmRelocationEntry> &Relocations);
   void writeLinkingMetaDataSection(
@@ -665,7 +678,7 @@ void WasmObjectWriter::applyRelocations(
     case wasm::R_WASM_FUNCTION_OFFSET_I32:
     case wasm::R_WASM_SECTION_OFFSET_I32:
     case wasm::R_WASM_GLOBAL_INDEX_I32:
-      writeI32(Stream, Value, Offset);
+      patchI32(Stream, Value, Offset);
       break;
     case wasm::R_WASM_TABLE_INDEX_SLEB:
     case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
@@ -777,6 +790,40 @@ void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) {
   endSection(Section);
 }
 
+void WasmObjectWriter::writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals) {
+  if (Globals.empty())
+    return;
+
+  SectionBookkeeping Section;
+  startSection(Section, wasm::WASM_SEC_GLOBAL);
+
+  encodeULEB128(Globals.size(), W.OS);
+  for (const wasm::WasmGlobal &Global : Globals) {
+    encodeULEB128(Global.Type.Type, W.OS);
+    W.OS << char(Global.Type.Mutable);
+    W.OS << char(Global.InitExpr.Opcode);
+    switch (Global.Type.Type) {
+    case wasm::WASM_TYPE_I32:
+      encodeSLEB128(0, W.OS);
+      break;
+    case wasm::WASM_TYPE_I64:
+      encodeSLEB128(0, W.OS);
+      break;
+    case wasm::WASM_TYPE_F32:
+      writeI32(0);
+      break;
+    case wasm::WASM_TYPE_F64:
+      writeI64(0);
+      break;
+    default:
+      llvm_unreachable("unexpected type");
+    }
+    W.OS << char(wasm::WASM_OPCODE_END);
+  }
+
+  endSection(Section);
+}
+
 void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
   if (Exports.empty())
     return;
@@ -1118,6 +1165,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
   SmallVector<wasm::WasmImport, 4> Imports;
   SmallVector<wasm::WasmExport, 4> Exports;
   SmallVector<wasm::WasmEventType, 1> Events;
+  SmallVector<wasm::WasmGlobal, 1> Globals;
   SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
   SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
   std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
@@ -1377,22 +1425,43 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
 
     } else if (WS.isGlobal()) {
       // A "true" Wasm global (currently just __stack_pointer)
-      if (WS.isDefined())
-        report_fatal_error("don't yet support defined globals");
-
-      // An import; the index was assigned above
-      LLVM_DEBUG(dbgs() << "  -> global index: "
-                        << WasmIndices.find(&WS)->second << "\n");
-
+      if (WS.isDefined()) {
+        assert(WasmIndices.count(&WS) == 0);
+        wasm::WasmGlobal Global;
+        Global.Type = WS.getGlobalType();
+        Global.Index = NumGlobalImports + Globals.size();
+        switch (Global.Type.Type) {
+        case wasm::WASM_TYPE_I32:
+          Global.InitExpr.Opcode = wasm::WASM_OPCODE_I32_CONST;
+          break;
+        case wasm::WASM_TYPE_I64:
+          Global.InitExpr.Opcode = wasm::WASM_OPCODE_I64_CONST;
+          break;
+        case wasm::WASM_TYPE_F32:
+          Global.InitExpr.Opcode = wasm::WASM_OPCODE_F32_CONST;
+          break;
+        case wasm::WASM_TYPE_F64:
+          Global.InitExpr.Opcode = wasm::WASM_OPCODE_F64_CONST;
+          break;
+        default:
+          llvm_unreachable("unexpected type");
+        }
+        WasmIndices[&WS] = Global.Index;
+        Globals.push_back(Global);
+      } else {
+        // An import; the index was assigned above
+        LLVM_DEBUG(dbgs() << "  -> global index: "
+                          << WasmIndices.find(&WS)->second << "\n");
+      }
     } else if (WS.isEvent()) {
       // C++ exception symbol (__cpp_exception)
       unsigned Index;
       if (WS.isDefined()) {
+        assert(WasmIndices.count(&WS) == 0);
         Index = NumEventImports + Events.size();
         wasm::WasmEventType Event;
         Event.SigIndex = getEventType(WS);
         Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
-        assert(WasmIndices.count(&WS) == 0);
         WasmIndices[&WS] = Index;
         Events.push_back(Event);
       } else {
@@ -1584,6 +1653,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
   // Skip the "table" section; we import the table instead.
   // Skip the "memory" section; we import the memory instead.
   writeEventSection(Events);
+  writeGlobalSection(Globals);
   writeExportSection(Exports);
   writeElemSection(TableElems);
   writeDataCountSection();

diff  --git a/llvm/test/MC/WebAssembly/globals.s b/llvm/test/MC/WebAssembly/globals.s
new file mode 100644
index 000000000000..10d696b7090a
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/globals.s
@@ -0,0 +1,79 @@
+# RUN: llvm-mc -triple=wasm32-unknown-unknown < %s | FileCheck %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck -check-prefix=BIN %s
+
+# Tests creating an accessing actual wasm globals
+
+.globl read_global
+.globl write_global
+.globaltype foo_global, i32
+.globaltype global2, i64
+.globaltype global3, f32
+.globaltype global4, f64
+
+read_global:
+  .functype read_global () -> (i32)
+  global.get foo_global
+  end_function
+
+write_global:
+  .functype write_global (i32) -> ()
+  local.get 0
+  global.set foo_global
+  global.set global2
+  global.set global3
+  global.set global4
+  end_function
+
+foo_global:
+global2:
+global3:
+global4:
+
+# CHECK: .globl  read_global
+# CNEXT: .globl  write_global
+# CHECK: .globaltype foo_global, i32
+# CHECK: foo_global:
+
+#      BIN: - Type:            GLOBAL
+# BIN-NEXT:   Globals:
+# BIN-NEXT:     - Index:           0
+# BIN-NEXT:       Type:            I32
+# BIN-NEXT:       Mutable:         true
+# BIN-NEXT:       InitExpr:
+# BIN-NEXT:         Opcode:          I32_CONST
+# BIN-NEXT:         Value:           0
+
+#      BIN:  - Type:            CUSTOM
+# BIN-NEXT:    Name:            linking
+# BIN-NEXT:    Version:         2
+# BIN-NEXT:    SymbolTable:
+# BIN-NEXT:      - Index:           0
+# BIN-NEXT:        Kind:            FUNCTION
+# BIN-NEXT:        Name:            read_global
+# BIN-NEXT:        Flags:           [  ]
+# BIN-NEXT:        Function:        0
+# BIN-NEXT:      - Index:           1
+# BIN-NEXT:        Kind:            FUNCTION
+# BIN-NEXT:        Name:            write_global
+# BIN-NEXT:        Flags:           [  ]
+# BIN-NEXT:        Function:        1
+# BIN-NEXT:      - Index:           2
+# BIN-NEXT:        Kind:            GLOBAL
+# BIN-NEXT:        Name:            foo_global
+# BIN-NEXT:        Flags:           [ BINDING_LOCAL ]
+# BIN-NEXT:        Global:          0
+# BIN-NEXT:      - Index:           3
+# BIN-NEXT:        Kind:            GLOBAL
+# BIN-NEXT:        Name:            global2
+# BIN-NEXT:        Flags:           [ BINDING_LOCAL ]
+# BIN-NEXT:        Global:          1
+# BIN-NEXT:      - Index:           4
+# BIN-NEXT:        Kind:            GLOBAL
+# BIN-NEXT:        Name:            global3
+# BIN-NEXT:        Flags:           [ BINDING_LOCAL ]
+# BIN-NEXT:        Global:          2
+# BIN-NEXT:      - Index:           5
+# BIN-NEXT:        Kind:            GLOBAL
+# BIN-NEXT:        Name:            global4
+# BIN-NEXT:        Flags:           [ BINDING_LOCAL ]
+# BIN-NEXT:        Global:          3


        


More information about the llvm-commits mailing list