diff --git a/lld/test/wasm/data-segment-merging.ll b/lld/test/wasm/data-segment-merging.ll --- a/lld/test/wasm/data-segment-merging.ll +++ b/lld/test/wasm/data-segment-merging.ll @@ -8,40 +8,92 @@ @e = private constant [9 x i8] c"constant\00", align 1 @f = private constant i8 43, align 4 -; RUN: llc -filetype=obj %s -o %t.data-segment-merging.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: llc -filetype=obj %s -o %t.atomics.o -mattr=+atomics +; RUN: llc -filetype=obj %s -o %t.bulk-mem.o -mattr=+bulk-memory +; RUN: llc -filetype=obj %s -o %t.atomics.bulk-mem.o -mattr=+atomics,+bulk-memory -; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.data-segment-merging.o +; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.o ; RUN: obj2yaml %t.merged.wasm | FileCheck %s --check-prefix=MERGE ; MERGE-NOT: DATACOUNT +; MERGE: - Type: CODE +; MERGE: Body: 0B ; MERGE: - Type: DATA ; MERGE: Segments: +; MERGE: InitFlags: 0 ; MERGE: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 +; MERGE: InitFlags: 0 ; MERGE: Content: 636F6E7374616E74000000002B ; MERGE-NOT: Content: -; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.data-segment-merging.o +; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.o ; RUN: obj2yaml %t.separate.wasm | FileCheck %s --check-prefix=SEPARATE ; SEPARATE-NOT: DATACOUNT +; SEPARATE: - Type: CODE +; SEPARATE: Body: 0B ; SEPARATE: - Type: DATA ; SEPARATE: Segments: +; SEPARATE: InitFlags: 0 ; SEPARATE: Content: 68656C6C6F00 +; SEPARATE: InitFlags: 0 ; SEPARATE: Content: 676F6F6462796500 +; SEPARATE: InitFlags: 0 ; SEPARATE: Content: '776861746576657200' +; SEPARATE: InitFlags: 0 ; SEPARATE: Content: 2A000000 +; SEPARATE: InitFlags: 0 ; SEPARATE: Content: 636F6E7374616E7400 ; SEPARATE: Content: 2B ; SEPARATE-NOT: Content: -; RUN: llc -filetype=obj %s -mattr=+bulk-memory -o %t.data-segment-merging.bulk-memory.o -; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.bulk-memory.wasm %t.data-segment-merging.bulk-memory.o -; RUN: obj2yaml %t.merged.bulk-memory.wasm | FileCheck %s --check-prefix=BULK-MEMORY - -; BULK-MEMORY: - Type: DATACOUNT -; BULK-MEMORY: Count: 2 -; BULK-MEMORY: - Type: DATA -; BULK-MEMORY: Segments: -; BULK-MEMORY: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 -; BULK-MEMORY: Content: 636F6E7374616E74000000002B -; BULK-MEMORY-NOT: Content: +; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 -o %t.merged.atomics.wasm %t.atomics.o +; RUN: obj2yaml %t.merged.atomics.wasm | FileCheck %s --check-prefix=MERGE-SHARED + +; MERGE-SHARED-NOT: DATACOUNT +; MERGE-SHARED: - Type: CODE +; MERGE-SHARED-NEXT: Functions: +; MERGE-SHARED-NEXT: - Index: 0 +; MERGE-SHARED-NEXT: Locals: [] +; MERGE-SHARED-NEXT: Body: 4180084100411CFC080000FC0900419C084100410DFC080100FC09010B +; MERGE-SHARED: - Type: DATA +; MERGE-SHARED: Segments: +; MERGE-SHARED: InitFlags: 1 +; MERGE-SHARED: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 +; MERGE-SHARED: InitFlags: 1 +; MERGE-SHARED: Content: 636F6E7374616E74000000002B +; MERGE-SHARED-NOT: Content: + +; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.bulk-mem.wasm %t.bulk-mem.o +; RUN: obj2yaml %t.merged.bulk-mem.wasm | FileCheck %s --check-prefix=MERGE-BULK-MEM + +; MERGE-BULK-MEM: - Type: DATACOUNT +; MERGE-BULK-MEM: Count: 2 +; MERGE-BULK-MEM: - Type: CODE +; MERGE-BULK-MEM: Body: 0B +; MERGE-BULK-MEM: - Type: DATA +; MERGE-BULK-MEM: Segments: +; MERGE-BULK-MEM: InitFlags: 0 +; MERGE-BULK-MEM: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 +; MERGE-BULK-MEM: InitFlags: 0 +; MERGE-BULK-MEM: Content: 636F6E7374616E74000000002B +; MERGE-BULK-MEM-NOT: Content: + +; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 -o %t.merged.atomics.bulk-mem.wasm %t.atomics.bulk-mem.o +; RUN: obj2yaml %t.merged.atomics.bulk-mem.wasm | FileCheck %s --check-prefix=MERGE-SHARED-BULK-MEM + +; MERGE-SHARED-BULK-MEM: - Type: DATACOUNT +; MERGE-SHARED-BULK-MEM-NEXT: Count: 2 +; MERGE-SHARED-BULK-MEM: - Type: CODE +; MERGE-SHARED-BULK-MEM-NEXT: Functions: +; MERGE-SHARED-BULK-MEM-NEXT: - Index: 0 +; MERGE-SHARED-BULK-MEM-NEXT: Locals: [] +; MERGE-SHARED-BULK-MEM-NEXT: Body: 4180084100411CFC080000FC0900419C084100410DFC080100FC09010B +; MERGE-SHARED-BULK-MEM: - Type: DATA +; MERGE-SHARED-BULK-MEM: Segments: +; MERGE-SHARED-BULK-MEM: InitFlags: 1 +; MERGE-SHARED-BULK-MEM: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 +; MERGE-SHARED-BULK-MEM: InitFlags: 1 +; MERGE-SHARED-BULK-MEM: Content: 636F6E7374616E74000000002B +; MERGE-SHARED-BULK-MEM-NOT: Content: diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -159,20 +159,26 @@ OS.flush(); BodySize = DataSectionHeader.size(); + assert(!Config->Pic || + Segments.size() <= 1 && + "Currenly only a single data segment is supported in PIC mode"); + for (OutputSegment *Segment : Segments) { raw_string_ostream OS(Segment->Header); - writeUleb128(OS, 0, "memory index"); - WasmInitExpr InitExpr; - if (Config->Pic) { - assert(Segments.size() <= 1 && - "Currenly only a single data segment is supported in PIC mode"); - InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET; - InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex(); - } else { - InitExpr.Opcode = WASM_OPCODE_I32_CONST; - InitExpr.Value.Int32 = Segment->StartVA; + writeUleb128(OS, Segment->InitFlags, "init flags"); + if (Segment->InitFlags & WASM_SEGMENT_HAS_MEMINDEX) + writeUleb128(OS, 0, "memory index"); + if ((Segment->InitFlags & WASM_SEGMENT_IS_PASSIVE) == 0) { + WasmInitExpr InitExpr; + if (Config->Pic) { + InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET; + InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex(); + } else { + InitExpr.Opcode = WASM_OPCODE_I32_CONST; + InitExpr.Value.Int32 = Segment->StartVA; + } + writeInitExpr(OS, InitExpr); } - writeInitExpr(OS, InitExpr); writeUleb128(OS, Segment->Size, "segment size"); OS.flush(); diff --git a/lld/wasm/OutputSegment.h b/lld/wasm/OutputSegment.h --- a/lld/wasm/OutputSegment.h +++ b/lld/wasm/OutputSegment.h @@ -33,6 +33,7 @@ StringRef Name; const uint32_t Index; + uint32_t InitFlags = 0; uint32_t SectionOffset = 0; uint32_t Alignment = 0; uint32_t StartVA = 0; diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1295,6 +1295,8 @@ if (S == nullptr) { LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n"); S = make(Name, Segments.size()); + if (Config->SharedMemory) + S->InitFlags = WASM_SEGMENT_IS_PASSIVE; Segments.push_back(S); } S->addInputSegment(Segment); @@ -1343,11 +1345,38 @@ { raw_string_ostream OS(BodyContent); writeUleb128(OS, 0, "num locals"); + + // initialize passive data segments + for (const OutputSegment *S : Segments) { + if (S->InitFlags & WASM_SEGMENT_IS_PASSIVE) { + // destination address + writeU8(OS, WASM_OPCODE_I32_CONST, "i32.const"); + writeUleb128(OS, S->StartVA, "destination address"); + // source segment offset + writeU8(OS, WASM_OPCODE_I32_CONST, "i32.const"); + writeUleb128(OS, 0, "segment offset"); + // memory region size + writeU8(OS, WASM_OPCODE_I32_CONST, "i32.const"); + writeUleb128(OS, S->Size, "memory region size"); + // memory.init instruction + writeU8(OS, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); + writeUleb128(OS, WASM_OPCODE_MEMORY_INIT, "MEMORY.INIT"); + writeUleb128(OS, S->Index, "segment index immediate"); + writeU8(OS, 0, "memory index immediate"); + // data.drop instruction + writeU8(OS, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); + writeUleb128(OS, WASM_OPCODE_DATA_DROP, "DATA.DROP"); + writeUleb128(OS, S->Index, "segment index immediate"); + } + } + if (Config->Pic) { writeU8(OS, WASM_OPCODE_CALL, "CALL"); writeUleb128(OS, WasmSym::ApplyRelocs->getFunctionIndex(), "function index"); } + + // call constructors for (const WasmInitEntry &F : InitFunctions) { writeU8(OS, WASM_OPCODE_CALL, "CALL"); writeUleb128(OS, F.Sym->getFunctionIndex(), "function index"); @@ -1408,12 +1437,12 @@ calculateImports(); log("-- assignIndexes"); assignIndexes(); - log("-- calculateInitFunctions"); - calculateInitFunctions(); log("-- calculateTypes"); calculateTypes(); log("-- layoutMemory"); layoutMemory(); + log("-- calculateInitFunctions"); + calculateInitFunctions(); if (!Config->Relocatable) { if (Config->Pic) createApplyRelocationsFunction(); diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -249,6 +249,9 @@ WASM_OPCODE_F32_CONST = 0x43, WASM_OPCODE_F64_CONST = 0x44, WASM_OPCODE_I32_ADD = 0x6a, + WASM_OPCODE_MISC_PREFIX = 0xfc, + WASM_OPCODE_MEMORY_INIT = 0x08, + WASM_OPCODE_DATA_DROP = 0x09, }; enum : unsigned {