[lld] r365088 - [WebAssembly] Add option to emit passive segments

Thomas Lively via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 3 15:04:54 PDT 2019


Author: tlively
Date: Wed Jul  3 15:04:54 2019
New Revision: 365088

URL: http://llvm.org/viewvc/llvm-project?rev=365088&view=rev
Log:
[WebAssembly] Add option to emit passive segments

Summary:
Adds `--passive-segments` and `--active-segments` flags to control
what kind of segments are emitted. For now the default is always
to emit active segments so this is not a breaking change, but in
the future the default will be changed to passive segments when
shared memory is requested and active segments otherwise. When
passive segments are emitted, corresponding memory.init and
data.drop instructions are emitted in a `__wasm_init_memory`
function that is automatically called at the beginning of
`__wasm_call_ctors`.

Reviewers: sbc100, aheejin, dschuff

Subscribers: azakai, dschuff, jgravelle-google, sunfish, jfb, llvm-commits

Tags: #llvm

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

Added:
    lld/trunk/test/wasm/data-segments.ll
Modified:
    lld/trunk/test/wasm/data-segment-merging.ll
    lld/trunk/wasm/Config.h
    lld/trunk/wasm/Driver.cpp
    lld/trunk/wasm/MarkLive.cpp
    lld/trunk/wasm/Options.td
    lld/trunk/wasm/OutputSections.cpp
    lld/trunk/wasm/OutputSegment.h
    lld/trunk/wasm/Symbols.cpp
    lld/trunk/wasm/Symbols.h
    lld/trunk/wasm/SyntheticSections.cpp
    lld/trunk/wasm/Writer.cpp

Modified: lld/trunk/test/wasm/data-segment-merging.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/data-segment-merging.ll?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/test/wasm/data-segment-merging.ll (original)
+++ lld/trunk/test/wasm/data-segment-merging.ll Wed Jul  3 15:04:54 2019
@@ -8,40 +8,117 @@ target triple = "wasm32-unknown-unknown"
 @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 -mattr=+bulk-memory -filetype=obj %s -o %t.o
 
-; 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:            DATA
-; MERGE:     Segments:
-; MERGE:        Content:         68656C6C6F00676F6F6462796500776861746576657200002A000000
-; MERGE:        Content:         636F6E7374616E74000000002B
-; MERGE-NOT:    Content:
+; MERGE-LABEL: - Type:            DATA
+; MERGE-NEXT:    Segments:
+; MERGE-NEXT:      - SectionOffset:   7
+; MERGE-NEXT:        InitFlags:       0
+; MERGE-NEXT:        Offset:
+; MERGE:             Content:         68656C6C6F00676F6F6462796500776861746576657200002A000000
+; MERGE-NEXT:      - SectionOffset:   41
+; MERGE-NEXT:        InitFlags:       0
+; MERGE-NEXT:        Offset:
+; MERGE:             Content:         636F6E7374616E74000000002B
+; MERGE-NEXT:  - Type:            CUSTOM
+; MERGE-NEXT:    Name:            name
+; MERGE-NEXT:    FunctionNames:
+; MERGE-NEXT:      - Index:           0
+; MERGE-NEXT:        Name:            __wasm_call_ctors
+; MERGE-NOT:       - Index:
 
-; 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:            DATA
-; SEPARATE:     Segments:
-; SEPARATE:        Content:         68656C6C6F00
-; SEPARATE:        Content:         676F6F6462796500
-; SEPARATE:        Content:         '776861746576657200'
-; SEPARATE:        Content:         2A000000
-; 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:
+; SEPARATE-LABEL: - Type:            DATA
+; SEPARATE-NEXT:    Segments:
+; SEPARATE-NEXT:      - SectionOffset:   7
+; SEPARATE-NEXT:        InitFlags:       0
+; SEPARATE-NEXT:        Offset:
+; SEPARATE:             Content:         68656C6C6F00
+; SEPARATE-NEXT:      - SectionOffset:   19
+; SEPARATE-NEXT:        InitFlags:       0
+; SEPARATE-NEXT:        Offset:
+; SEPARATE:             Content:         676F6F6462796500
+; SEPARATE-NEXT:      - SectionOffset:   33
+; SEPARATE-NEXT:        InitFlags:       0
+; SEPARATE-NEXT:        Offset:
+; SEPARATE:             Content:         '776861746576657200'
+; SEPARATE-NEXT:      - SectionOffset:   48
+; SEPARATE-NEXT:        InitFlags:       0
+; SEPARATE-NEXT:        Offset:
+; SEPARATE:             Content:         2A000000
+; SEPARATE-NEXT:      - SectionOffset:   58
+; SEPARATE-NEXT:        InitFlags:       0
+; SEPARATE-NEXT:        Offset:
+; SEPARATE:             Content:         636F6E7374616E7400
+; SEPARATE-NEXT:      - SectionOffset:   73
+; SEPARATE-NEXT:        InitFlags:       0
+; SEPARATE-NEXT:        Offset:
+; SEPARATE:             Content:         2B
+; SEPARATE-NEXT:  - Type:            CUSTOM
+; SEPARATE-NEXT:    Name:            name
+; SEPARATE-NEXT:    FunctionNames:
+; SEPARATE-NEXT:      - Index:           0
+; SEPARATE-NEXT:        Name:            __wasm_call_ctors
+; SEPARATE-NOT:       - Index:
+
+; RUN: wasm-ld -no-gc-sections --no-entry --passive-segments -o %t.merged.passive.wasm %t.o
+; RUN: obj2yaml %t.merged.passive.wasm | FileCheck %s --check-prefix=PASSIVE-MERGE
+
+; PASSIVE-MERGE-LABEL: - Type:            DATACOUNT
+; PASSIVE-MERGE-NEXT:    Count:           2
+; PASSIVE-MERGE-LABEL: - Type:            DATA
+; PASSIVE-MERGE-NEXT:    Segments:
+; PASSIVE-MERGE-NEXT:      - SectionOffset:   3
+; PASSIVE-MERGE-NEXT:        InitFlags:       1
+; PASSIVE-MERGE-NEXT:        Content:         68656C6C6F00676F6F6462796500776861746576657200002A000000
+; PASSIVE-MERGE-NEXT:      - SectionOffset:   33
+; PASSIVE-MERGE-NEXT:        InitFlags:       1
+; PASSIVE-MERGE-NEXT:        Content:         636F6E7374616E74000000002B
+; PASSIVE-MERGE-NEXT:  - Type:            CUSTOM
+; PASSIVE-MERGE-NEXT:    Name:            name
+; PASSIVE-MERGE-NEXT:    FunctionNames:
+; PASSIVE-MERGE-NEXT:      - Index:           0
+; PASSIVE-MERGE-NEXT:        Name:            __wasm_call_ctors
+; PASSIVE-MERGE-NEXT:      - Index:           1
+; PASSIVE-MERGE-NEXT:        Name:            __wasm_init_memory
+; PASSIVE-MERGE-NOT:       - Index:
+
+; RUN: wasm-ld -no-gc-sections --no-entry --passive-segments -no-merge-data-segments -o %t.separate.passive.wasm %t.o
+; RUN: obj2yaml %t.separate.passive.wasm | FileCheck %s --check-prefix=PASSIVE-SEPARATE
+
+; PASSIVE-SEPARATE-LABEL: - Type:            DATACOUNT
+; PASSIVE-SEPARATE-NEXT:    Count:           6
+; PASSIVE-SEPARATE-LABEL: - Type:            DATA
+; PASSIVE-SEPARATE-NEXT:    Segments:
+; PASSIVE-SEPARATE-NEXT:      - SectionOffset:   3
+; PASSIVE-SEPARATE-NEXT:        InitFlags:       1
+; PASSIVE-SEPARATE-NEXT:        Content:         68656C6C6F00
+; PASSIVE-SEPARATE-NEXT:      - SectionOffset:   11
+; PASSIVE-SEPARATE-NEXT:        InitFlags:       1
+; PASSIVE-SEPARATE-NEXT:        Content:         676F6F6462796500
+; PASSIVE-SEPARATE-NEXT:      - SectionOffset:   21
+; PASSIVE-SEPARATE-NEXT:        InitFlags:       1
+; PASSIVE-SEPARATE-NEXT:        Content:         '776861746576657200'
+; PASSIVE-SEPARATE-NEXT:      - SectionOffset:   32
+; PASSIVE-SEPARATE-NEXT:        InitFlags:       1
+; PASSIVE-SEPARATE-NEXT:        Content:         2A000000
+; PASSIVE-SEPARATE-NEXT:      - SectionOffset:   38
+; PASSIVE-SEPARATE-NEXT:        InitFlags:       1
+; PASSIVE-SEPARATE-NEXT:        Content:         636F6E7374616E7400
+; PASSIVE-SEPARATE-NEXT:      - SectionOffset:   49
+; PASSIVE-SEPARATE-NEXT:        InitFlags:       1
+; PASSIVE-SEPARATE-NEXT:        Content:         2B
+; PASSIVE-SEPARATE-NEXT:    - Type:            CUSTOM
+; PASSIVE-SEPARATE-NEXT:      Name:            name
+; PASSIVE-SEPARATE-NEXT:      FunctionNames:
+; PASSIVE-SEPARATE-NEXT:        - Index:           0
+; PASSIVE-SEPARATE-NEXT:          Name:            __wasm_call_ctors
+; PASSIVE-SEPARATE-NEXT:        - Index:           1
+; PASSIVE-SEPARATE-NEXT:          Name:            __wasm_init_memory
+; PASSIVE-SEPARATE-NOT:         - Index

Added: lld/trunk/test/wasm/data-segments.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/data-segments.ll?rev=365088&view=auto
==============================================================================
--- lld/trunk/test/wasm/data-segments.ll (added)
+++ lld/trunk/test/wasm/data-segments.ll Wed Jul  3 15:04:54 2019
@@ -0,0 +1,99 @@
+; 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
+
+; atomics => active segments (TODO: error)
+; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.o -o %t.atomics.wasm
+; RUN: obj2yaml %t.atomics.wasm | FileCheck %s --check-prefix ACTIVE
+
+; atomics, active segments => active segments
+; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --active-segments %t.atomics.o -o %t.atomics.active.wasm
+; RUN: obj2yaml %t.atomics.active.wasm | FileCheck %s --check-prefix ACTIVE
+
+; atomics, passive segments => error
+; RUN: not wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --passive-segments %t.atomics.o -o %t.atomics.passive.wasm 2>&1 | FileCheck %s --check-prefix ERROR
+
+; bulk memory => active segments
+; RUN: wasm-ld -no-gc-sections --no-entry %t.bulk-mem.o -o %t.bulk-mem.wasm
+; RUN: obj2yaml %t.bulk-mem.wasm | FileCheck %s --check-prefix ACTIVE
+
+; bulk-memory, active segments => active segments
+; RUN: wasm-ld -no-gc-sections --no-entry --active-segments %t.bulk-mem.o -o %t.bulk-mem.active.wasm
+; RUN: obj2yaml %t.bulk-mem.active.wasm | FileCheck %s --check-prefix ACTIVE
+
+; bulk memory, passive segments => passive segments
+; RUN: wasm-ld -no-gc-sections --no-entry --passive-segments %t.bulk-mem.o -o %t.bulk-mem.passive.wasm
+; RUN: obj2yaml %t.bulk-mem.passive.wasm | FileCheck %s --check-prefix PASSIVE
+
+; atomics, bulk memory => active segments (TODO: passive)
+; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.wasm
+; RUN: obj2yaml %t.atomics.bulk-mem.wasm | FileCheck %s --check-prefix ACTIVE
+
+; atomics, bulk memory, active segments   => active segments
+; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --active-segments %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.active.wasm
+; RUN: obj2yaml %t.atomics.bulk-mem.active.wasm | FileCheck %s --check-prefix ACTIVE
+
+; atomics, bulk memory, passive segments  => passive segments
+; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --passive-segments %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.passive.wasm
+; RUN: obj2yaml %t.atomics.bulk-mem.passive.wasm | FileCheck %s --check-prefix PASSIVE
+
+target triple = "wasm32-unknown-unknown"
+
+ at a = hidden global [6 x i8] c"hello\00", align 1
+ at b = hidden global [8 x i8] c"goodbye\00", align 1
+ at c = hidden global [9 x i8] c"whatever\00", align 1
+ at d = hidden global i32 42, align 4
+
+ at e = private constant [9 x i8] c"constant\00", align 1
+ at f = private constant i8 43, align 4
+
+; ERROR: 'bulk-memory' feature must be used in order to emit passive segments
+
+; ACTIVE-LABEL: - Type:            CODE
+; ACTIVE-NEXT:    Functions:
+; ACTIVE-NEXT:      - Index:           0
+; ACTIVE-NEXT:        Locals:          []
+; ACTIVE-NEXT:        Body:            0B
+; ACTIVE-NEXT:  - Type:            DATA
+; ACTIVE-NEXT:    Segments:
+; ACTIVE-NEXT:      - SectionOffset:   7
+; ACTIVE-NEXT:        InitFlags:       0
+; ACTIVE-NEXT:        Offset:
+; ACTIVE-NEXT:        Opcode:          I32_CONST
+; ACTIVE-NEXT:        Value:           1024
+; ACTIVE-NEXT:        Content:         68656C6C6F00676F6F6462796500776861746576657200002A000000
+; ACTIVE-NEXT:      - SectionOffset:   41
+; ACTIVE-NEXT:        InitFlags:       0
+; ACTIVE-NEXT:        Offset:
+; ACTIVE-NEXT:        Opcode:          I32_CONST
+; ACTIVE-NEXT:        Value:           1052
+; ACTIVE-NEXT:        Content:         636F6E7374616E74000000002B
+; ACTIVE-NEXT:  - Type:            CUSTOM
+; ACTIVE-NEXT:    Name:            name
+; ACTIVE-NEXT:    FunctionNames:
+; ACTIVE-NEXT:      - Index:           0
+; ACTIVE-NEXT:        Name:            __wasm_call_ctors
+
+; PASSIVE-LABEL: - Type:            CODE
+; PASSIVE-NEXT:    Functions:
+; PASSIVE-NEXT:      - Index:           0
+; PASSIVE-NEXT:        Locals:          []
+; PASSIVE-NEXT:        Body:            10010B
+; PASSIVE-NEXT:      - Index:           1
+; PASSIVE-NEXT:        Locals:          []
+; PASSIVE-NEXT:        Body:            4180084100411CFC080000FC0900419C084100410DFC080100FC09010B
+; PASSIVE-NEXT:  - Type:            DATA
+; PASSIVE-NEXT:    Segments:
+; PASSIVE-NEXT:      - SectionOffset:   3
+; PASSIVE-NEXT:        InitFlags:       1
+; PASSIVE-NEXT:        Content:         68656C6C6F00676F6F6462796500776861746576657200002A000000
+; PASSIVE-NEXT:      - SectionOffset:   33
+; PASSIVE-NEXT:        InitFlags:       1
+; PASSIVE-NEXT:        Content:         636F6E7374616E74000000002B
+; PASSIVE-NEXT:  - Type:            CUSTOM
+; PASSIVE-NEXT:    Name:            name
+; PASSIVE-NEXT:    FunctionNames:
+; PASSIVE-NEXT:      - Index:           0
+; PASSIVE-NEXT:        Name:            __wasm_call_ctors
+; PASSIVE-NEXT:      - Index:           1
+; PASSIVE-NEXT:        Name:            __wasm_init_memory

Modified: lld/trunk/wasm/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Config.h?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/wasm/Config.h (original)
+++ lld/trunk/wasm/Config.h Wed Jul  3 15:04:54 2019
@@ -34,6 +34,7 @@ struct Configuration {
   bool GcSections;
   bool ImportMemory;
   bool SharedMemory;
+  bool PassiveSegments;
   bool ImportTable;
   bool MergeDataSegments;
   bool Pie;

Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Wed Jul  3 15:04:54 2019
@@ -320,6 +320,9 @@ static void readConfigs(opt::InputArgLis
       Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
   Config->ImportMemory = Args.hasArg(OPT_import_memory);
   Config->SharedMemory = Args.hasArg(OPT_shared_memory);
+  // TODO: Make passive segments the default with shared memory
+  Config->PassiveSegments =
+      Args.hasFlag(OPT_passive_segments, OPT_active_segments, false);
   Config->ImportTable = Args.hasArg(OPT_import_table);
   Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);
   Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
@@ -460,10 +463,19 @@ static void createSyntheticSymbols() {
         "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
         make<SyntheticFunction>(NullSignature, "__wasm_call_ctors"));
 
+    if (Config->PassiveSegments) {
+      // Passive segments are used to avoid memory being reinitialized on each
+      // thread's instantiation. These passive segments are initialized and
+      // dropped in __wasm_init_memory, which is the first function called from
+      // __wasm_call_ctors.
+      WasmSym::InitMemory = Symtab->addSyntheticFunction(
+          "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN,
+          make<SyntheticFunction>(NullSignature, "__wasm_init_memory"));
+    }
+
     if (Config->Pic) {
-      // For PIC code we create a synthetic function call __wasm_apply_relocs
-      // and add this as the first call in __wasm_call_ctors.
-      // We also unconditionally export 
+      // For PIC code we create a synthetic function __wasm_apply_relocs which
+      // is called from __wasm_call_ctors before the user-level constructors.
       WasmSym::ApplyRelocs = Symtab->addSyntheticFunction(
           "__wasm_apply_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
           make<SyntheticFunction>(NullSignature, "__wasm_apply_relocs"));

Modified: lld/trunk/wasm/MarkLive.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/MarkLive.cpp?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/wasm/MarkLive.cpp (original)
+++ lld/trunk/wasm/MarkLive.cpp Wed Jul  3 15:04:54 2019
@@ -50,6 +50,10 @@ void lld::wasm::markLive() {
     // function.  However, this function does not contain relocations so we
     // have to manually mark the ctors as live if CallCtors itself is live.
     if (Sym == WasmSym::CallCtors) {
+      if (Config->PassiveSegments)
+        Enqueue(WasmSym::InitMemory);
+      if (Config->Pic)
+        Enqueue(WasmSym::ApplyRelocs);
       for (const ObjFile *Obj : Symtab->ObjectFiles) {
         const WasmLinkingData &L = Obj->getWasmObj()->linkingData();
         for (const WasmInitFunc &F : L.InitFunctions) {
@@ -79,10 +83,8 @@ void lld::wasm::markLive() {
     }
   }
 
-  if (Config->Pic) {
+  if (Config->Pic)
     Enqueue(WasmSym::CallCtors);
-    Enqueue(WasmSym::ApplyRelocs);
-  }
 
   // Follow relocations to mark all reachable chunks.
   while (!Q.empty()) {

Modified: lld/trunk/wasm/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Options.td?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/wasm/Options.td (original)
+++ lld/trunk/wasm/Options.td Wed Jul  3 15:04:54 2019
@@ -143,6 +143,12 @@ def import_memory: F<"import-memory">,
 def shared_memory: F<"shared-memory">,
   HelpText<"Use shared linear memory">;
 
+def active_segments: F<"active-segments">,
+  HelpText<"Force segments to be active">;
+
+def passive_segments: F<"passive-segments">,
+  HelpText<"Force segments to be passive">;
+
 def import_table: F<"import-table">,
   HelpText<"Import function table from the environment">;
 

Modified: lld/trunk/wasm/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/OutputSections.cpp?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/wasm/OutputSections.cpp (original)
+++ lld/trunk/wasm/OutputSections.cpp Wed Jul  3 15:04:54 2019
@@ -132,20 +132,26 @@ void DataSection::finalizeContents() {
   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();
 

Modified: lld/trunk/wasm/OutputSegment.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/OutputSegment.h?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/wasm/OutputSegment.h (original)
+++ lld/trunk/wasm/OutputSegment.h Wed Jul  3 15:04:54 2019
@@ -33,6 +33,7 @@ public:
 
   StringRef Name;
   const uint32_t Index;
+  uint32_t InitFlags = 0;
   uint32_t SectionOffset = 0;
   uint32_t Alignment = 0;
   uint32_t StartVA = 0;

Modified: lld/trunk/wasm/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.cpp?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.cpp (original)
+++ lld/trunk/wasm/Symbols.cpp Wed Jul  3 15:04:54 2019
@@ -25,6 +25,7 @@ using namespace lld;
 using namespace lld::wasm;
 
 DefinedFunction *WasmSym::CallCtors;
+DefinedFunction *WasmSym::InitMemory;
 DefinedFunction *WasmSym::ApplyRelocs;
 DefinedData *WasmSym::DsoHandle;
 DefinedData *WasmSym::DataEnd;

Modified: lld/trunk/wasm/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.h?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.h (original)
+++ lld/trunk/wasm/Symbols.h Wed Jul  3 15:04:54 2019
@@ -438,6 +438,10 @@ struct WasmSym {
   // Function that directly calls all ctors in priority order.
   static DefinedFunction *CallCtors;
 
+  // __wasm_init_memory
+  // Function that initializes passive data segments post-instantiation.
+  static DefinedFunction *InitMemory;
+
   // __wasm_apply_relocs
   // Function that applies relocations to data segment post-instantiation.
   static DefinedFunction *ApplyRelocs;

Modified: lld/trunk/wasm/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SyntheticSections.cpp?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/wasm/SyntheticSections.cpp (original)
+++ lld/trunk/wasm/SyntheticSections.cpp Wed Jul  3 15:04:54 2019
@@ -323,7 +323,7 @@ void DataCountSection::writeBody() {
 }
 
 bool DataCountSection::isNeeded() const {
-  return NumSegments && Out.TargetFeaturesSec->Features.count("bulk-memory");
+  return NumSegments && Config->PassiveSegments;
 }
 
 static uint32_t getWasmFlags(const Symbol *Sym) {

Modified: lld/trunk/wasm/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.cpp?rev=365088&r1=365087&r2=365088&view=diff
==============================================================================
--- lld/trunk/wasm/Writer.cpp (original)
+++ lld/trunk/wasm/Writer.cpp Wed Jul  3 15:04:54 2019
@@ -54,6 +54,7 @@ public:
 private:
   void openFile();
 
+  void createInitMemoryFunction();
   void createApplyRelocationsFunction();
   void createCallCtorsFunction();
 
@@ -407,6 +408,10 @@ void Writer::populateTargetFeatures() {
     error("'atomics' feature is disallowed by " + Disallowed["atomics"] +
           ", so --shared-memory must not be used");
 
+  if (!Used.count("bulk-memory") && Config->PassiveSegments)
+    error("'bulk-memory' feature must be used in order to emit passive "
+          "segments");
+
   // Validate that used features are allowed in output
   if (!InferFeatures) {
     for (auto &Feature : Used.keys()) {
@@ -621,6 +626,8 @@ void Writer::createOutputSegments() {
       if (S == nullptr) {
         LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n");
         S = make<OutputSegment>(Name, Segments.size());
+        if (Config->PassiveSegments)
+          S->InitFlags = WASM_SEGMENT_IS_PASSIVE;
         Segments.push_back(S);
       }
       S->addInputSegment(Segment);
@@ -629,10 +636,57 @@ void Writer::createOutputSegments() {
   }
 }
 
+static void CreateFunction(DefinedFunction *Func, StringRef BodyContent) {
+  std::string FunctionBody;
+  {
+    raw_string_ostream OS(FunctionBody);
+    writeUleb128(OS, BodyContent.size(), "function size");
+    OS << BodyContent;
+  }
+  ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
+  cast<SyntheticFunction>(Func->Function)->setBody(Body);
+}
+
+void Writer::createInitMemoryFunction() {
+  LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n");
+  std::string BodyContent;
+  {
+    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");
+      }
+    }
+    writeU8(OS, WASM_OPCODE_END, "END");
+  }
+
+  CreateFunction(WasmSym::InitMemory, BodyContent);
+}
+
 // For -shared (PIC) output, we create create a synthetic function which will
 // apply any relocations to the data segments on startup.  This function is
-// called __wasm_apply_relocs and is added at the very beginning of
-// __wasm_call_ctors before any of the constructors run.
+// called __wasm_apply_relocs and is added at the beginning of __wasm_call_ctors
+// before any of the constructors run.
 void Writer::createApplyRelocationsFunction() {
   LLVM_DEBUG(dbgs() << "createApplyRelocationsFunction\n");
   // First write the body's contents to a string.
@@ -646,16 +700,7 @@ void Writer::createApplyRelocationsFunct
     writeU8(OS, WASM_OPCODE_END, "END");
   }
 
-  // Once we know the size of the body we can create the final function body
-  std::string FunctionBody;
-  {
-    raw_string_ostream OS(FunctionBody);
-    writeUleb128(OS, BodyContent.size(), "function size");
-    OS << BodyContent;
-  }
-
-  ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
-  cast<SyntheticFunction>(WasmSym::ApplyRelocs->Function)->setBody(Body);
+  CreateFunction(WasmSym::ApplyRelocs, BodyContent);
 }
 
 // Create synthetic "__wasm_call_ctors" function based on ctor functions
@@ -669,11 +714,20 @@ void Writer::createCallCtorsFunction() {
   {
     raw_string_ostream OS(BodyContent);
     writeUleb128(OS, 0, "num locals");
+
+    if (Config->PassiveSegments) {
+      writeU8(OS, WASM_OPCODE_CALL, "CALL");
+      writeUleb128(OS, WasmSym::InitMemory->getFunctionIndex(),
+                   "function index");
+    }
+
     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");
@@ -681,16 +735,7 @@ void Writer::createCallCtorsFunction() {
     writeU8(OS, WASM_OPCODE_END, "END");
   }
 
-  // Once we know the size of the body we can create the final function body
-  std::string FunctionBody;
-  {
-    raw_string_ostream OS(FunctionBody);
-    writeUleb128(OS, BodyContent.size(), "function size");
-    OS << BodyContent;
-  }
-
-  ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
-  cast<SyntheticFunction>(WasmSym::CallCtors->Function)->setBody(Body);
+  CreateFunction(WasmSym::CallCtors, BodyContent);
 }
 
 // Populate InitFunctions vector with init functions from all input objects.
@@ -779,6 +824,8 @@ void Writer::run() {
 
   if (!Config->Relocatable) {
     // Create linker synthesized functions
+    if (Config->PassiveSegments)
+      createInitMemoryFunction();
     if (Config->Pic)
       createApplyRelocationsFunction();
     createCallCtorsFunction();




More information about the llvm-commits mailing list