[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