Skip to content

Commit

Permalink
[WebAssembly] Elide data segments for .bss sections
Browse files Browse the repository at this point in the history
Summary:
WebAssembly memories are zero-initialized, so when module does not
import its memory initializing .bss sections is guaranteed to be a
no-op. To reduce binary size and initialization time, .bss sections
are simply not emitted into the final binary unless the memory is
imported.

Reviewers: sbc100

Subscribers: dschuff, jgravelle-google, aheejin, sunfish, llvm-commits

Tags: #llvm

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

llvm-svn: 374940
  • Loading branch information
tlively committed Oct 15, 2019
1 parent 0330fba commit 190dacc
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 49 deletions.
6 changes: 3 additions & 3 deletions lld/test/wasm/Inputs/locals-duplicate1.ll
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
target triple = "wasm32-unknown-unknown"

; Will collide: local (internal linkage) with global (external) linkage
@colliding_global1 = internal default global i32 0, align 4
@colliding_global1 = internal default global i32 1, align 4
; Will collide: global with local
@colliding_global2 = default global i32 0, align 4
@colliding_global2 = default global i32 1, align 4
; Will collide: local with local
@colliding_global3 = internal default global i32 0, align 4
@colliding_global3 = internal default global i32 1, align 4

; Will collide: local with global
define internal i32 @colliding_func1() {
Expand Down
6 changes: 3 additions & 3 deletions lld/test/wasm/Inputs/locals-duplicate2.ll
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
target triple = "wasm32-unknown-unknown"

; Will collide: local (internal linkage) with global (external) linkage
@colliding_global1 = default global i32 0, align 4
@colliding_global1 = default global i32 1, align 4
; Will collide: global with local
@colliding_global2 = internal default global i32 0, align 4
@colliding_global2 = internal default global i32 1, align 4
; Will collide: local with local
@colliding_global3 = internal default global i32 0, align 4
@colliding_global3 = internal default global i32 1, align 4

; Will collide: local with global
define i32 @colliding_func1() {
Expand Down
14 changes: 14 additions & 0 deletions lld/test/wasm/bss-only.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
; RUN: llc -filetype=obj %s -o %t.o
; RUN: wasm-ld -no-gc-sections --no-entry %t.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s

; Test that the data section is skipped entirely when there are only
; bss segments

target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"

@a = global [1000 x i8] zeroinitializer, align 1
@b = global i32 0

; CHECK-NOT: - Type: DATA
17 changes: 10 additions & 7 deletions lld/test/wasm/custom-section-name.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
; RUN: llc -filetype=obj %s -o %t.o
; RUN: wasm-ld -no-gc-sections --no-entry -o %t.wasm %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
; RUN: obj2yaml %t.wasm | FileCheck %s --check-prefixes=CHECK,NO-BSS
; RUN: wasm-ld -no-gc-sections --no-entry --import-memory -o %t.bss.wasm %t.o
; RUN: obj2yaml %t.bss.wasm | FileCheck %s --check-prefixes=CHECK,BSS
; RUN: wasm-ld -no-gc-sections --no-entry -o %t_reloc.o %t.o --relocatable
; RUN: obj2yaml %t_reloc.o | FileCheck -check-prefix RELOC %s

Expand Down Expand Up @@ -32,12 +34,13 @@ target triple = "wasm32-unknown-unknown"
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1032
; CHECK-NEXT: Content: '07000000'
; CHECK-NEXT: - SectionOffset: 37
; CHECK-NEXT: InitFlags: 0
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1036
; CHECK-NEXT: Content: '00000000'
; BSS-NEXT: - SectionOffset: 37
; BSS-NEXT: InitFlags: 0
; BSS-NEXT: Offset:
; BSS-NEXT: Opcode: I32_CONST
; BSS-NEXT: Value: 1036
; BSS-NEXT: Content: '00000000'
; NO-BSS-NOT: - SectionOffset:

; RELOC-LABEL: SegmentInfo:
; RELOC-NEXT: - Index: 0
Expand Down
6 changes: 0 additions & 6 deletions lld/test/wasm/data-layout.ll
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,6 @@ target triple = "wasm32-unknown-unknown"
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1040
; CHECK-NEXT: Content: '0100000000000000000000000000000003000000000000000004000034040000'
; CHECK-NEXT: - SectionOffset: 58
; CHECK-NEXT: InitFlags: 0
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1072
; CHECK-NEXT: Content: '0000000000000000'
; CHECK-NEXT: - Type: CUSTOM


Expand Down
11 changes: 0 additions & 11 deletions lld/test/wasm/data-segments.ll
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,6 @@ target triple = "wasm32-unknown-unknown"
; ACTIVE-NEXT: Opcode: I32_CONST
; ACTIVE-NEXT: Value: 1040
; ACTIVE-NEXT: Content: 68656C6C6F00676F6F646279650000002A000000
; ACTIVE-NEXT: - SectionOffset: 53
; ACTIVE-NEXT: InitFlags: 0
; ACTIVE-NEXT: Offset:
; ACTIVE-NEXT: Opcode: I32_CONST
; ACTIVE-NEXT: Value: 1060
; ACTIVE-NEXT: Content: '0000000000
; ACTIVE-SAME: 0000000000'
; ACTIVE-NEXT: - Type: CUSTOM
; ACTIVE-NEXT: Name: name
; ACTIVE-NEXT: FunctionNames:
Expand Down Expand Up @@ -78,10 +71,6 @@ target triple = "wasm32-unknown-unknown"
; PASSIVE-NEXT: - SectionOffset: 18
; PASSIVE-NEXT: InitFlags: 1
; PASSIVE-NEXT: Content: 68656C6C6F00676F6F646279650000002A000000
; PASSIVE-NEXT: - SectionOffset: 41
; PASSIVE-NEXT: InitFlags: 1
; PASSIVE-NEXT: Content: '0000000000
; PASSIVE-SAME: 0000000000'
; PASSIVE-NEXT: - Type: CUSTOM
; PASSIVE-NEXT: Name: name
; PASSIVE-NEXT: FunctionNames:
Expand Down
26 changes: 13 additions & 13 deletions lld/test/wasm/locals-duplicate.test
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1024
; CHECK-NEXT: Content: '000000000000000000000000000000000000000000000000'
; CHECK-NEXT: Content: '010000000100000001000000010000000100000001000000'
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
Expand Down Expand Up @@ -299,13 +299,13 @@
; RELOC-NEXT: Locals:
; RELOC-NEXT: Body: 4190808080000B
; RELOC-NEXT: - Index: 6
; RELOC-NEXT: Locals:
; RELOC-NEXT: Locals:
; RELOC-NEXT: Body: 4181808080000B
; RELOC-NEXT: - Index: 7
; RELOC-NEXT: Locals:
; RELOC-NEXT: Locals:
; RELOC-NEXT: Body: 4182808080000B
; RELOC-NEXT: - Index: 8
; RELOC-NEXT: Locals:
; RELOC-NEXT: Locals:
; RELOC-NEXT: Body: 4183808080000B
; RELOC-NEXT: - Index: 9
; RELOC-NEXT: Locals:
Expand All @@ -326,13 +326,13 @@
; RELOC-NEXT: Locals:
; RELOC-NEXT: Body: 4194808080000B
; RELOC-NEXT: - Index: 15
; RELOC-NEXT: Locals:
; RELOC-NEXT: Locals:
; RELOC-NEXT: Body: 4184808080000B
; RELOC-NEXT: - Index: 16
; RELOC-NEXT: Locals:
; RELOC-NEXT: Locals:
; RELOC-NEXT: Body: 4185808080000B
; RELOC-NEXT: - Index: 17
; RELOC-NEXT: Locals:
; RELOC-NEXT: Locals:
; RELOC-NEXT: Body: 4186808080000B
; RELOC-NEXT: - Type: DATA
; RELOC-NEXT: Segments:
Expand All @@ -341,19 +341,19 @@
; RELOC-NEXT: Offset:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 0
; RELOC-NEXT: Content: '0000000000000000'
; RELOC-NEXT: Content: '0100000001000000'
; RELOC-NEXT: - SectionOffset: 19
; RELOC-NEXT: InitFlags: 0
; RELOC-NEXT: Offset:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 8
; RELOC-NEXT: Content: '0000000000000000'
; RELOC-NEXT: Content: '0100000001000000'
; RELOC-NEXT: - SectionOffset: 32
; RELOC-NEXT: InitFlags: 0
; RELOC-NEXT: Offset:
; RELOC-NEXT: Opcode: I32_CONST
; RELOC-NEXT: Value: 16
; RELOC-NEXT: Content: '0000000000000000'
; RELOC-NEXT: Content: '0100000001000000'
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: linking
; RELOC-NEXT: Version: 2
Expand Down Expand Up @@ -489,15 +489,15 @@
; RELOC-NEXT: Size: 4
; RELOC-NEXT: SegmentInfo:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Name: .bss.colliding_global1
; RELOC-NEXT: Name: .data.colliding_global1
; RELOC-NEXT: Alignment: 2
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: - Index: 1
; RELOC-NEXT: Name: .bss.colliding_global2
; RELOC-NEXT: Name: .data.colliding_global2
; RELOC-NEXT: Alignment: 2
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: - Index: 2
; RELOC-NEXT: Name: .bss.colliding_global3
; RELOC-NEXT: Name: .data.colliding_global3
; RELOC-NEXT: Alignment: 2
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: - Type: CUSTOM
Expand Down
16 changes: 15 additions & 1 deletion lld/wasm/OutputSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,20 @@ void CodeSection::writeRelocations(raw_ostream &os) const {

void DataSection::finalizeContents() {
raw_string_ostream os(dataSectionHeader);
unsigned segmentCount =
std::count_if(segments.begin(), segments.end(),
[](OutputSegment *segment) { return !segment->isBss; });

writeUleb128(os, segments.size(), "data segment count");
writeUleb128(os, segmentCount, "data segment count");
os.flush();
bodySize = dataSectionHeader.size();

assert((!config->isPic || segments.size() <= 1) &&
"Currenly only a single data segment is supported in PIC mode");

for (OutputSegment *segment : segments) {
if (segment->isBss)
continue;
raw_string_ostream os(segment->header);
writeUleb128(os, segment->initFlags, "init flags");
if (segment->initFlags & WASM_SEGMENT_HAS_MEMINDEX)
Expand Down Expand Up @@ -181,6 +186,8 @@ void DataSection::writeTo(uint8_t *buf) {
memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size());

for (const OutputSegment *segment : segments) {
if (segment->isBss)
continue;
// Write data segment header
uint8_t *segStart = buf + segment->sectionOffset;
memcpy(segStart, segment->header.data(), segment->header.size());
Expand All @@ -205,6 +212,13 @@ void DataSection::writeRelocations(raw_ostream &os) const {
c->writeRelocations(os);
}

bool DataSection::isNeeded() const {
for (const OutputSegment *seg : segments)
if (!seg->isBss)
return true;
return false;
}

void CustomSection::finalizeContents() {
raw_string_ostream os(nameData);
encodeULEB128(name.size(), os);
Expand Down
2 changes: 1 addition & 1 deletion lld/wasm/OutputSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class DataSection : public OutputSection {
void writeTo(uint8_t *buf) override;
uint32_t getNumRelocations() const override;
void writeRelocations(raw_ostream &os) const override;
bool isNeeded() const override { return segments.size() > 0; }
bool isNeeded() const override;
void finalizeContents() override;

protected:
Expand Down
1 change: 1 addition & 0 deletions lld/wasm/OutputSegment.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class OutputSegment {
}

StringRef name;
bool isBss = false;
uint32_t index = 0;
uint32_t initFlags = 0;
uint32_t sectionOffset = 0;
Expand Down
6 changes: 6 additions & 0 deletions lld/wasm/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,12 @@ void ElemSection::writeBody() {
}
}

DataCountSection::DataCountSection(ArrayRef<OutputSegment *> segments)
: SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT),
numSegments(std::count_if(
segments.begin(), segments.end(),
[](OutputSegment *const segment) { return !segment->isBss; })) {}

void DataCountSection::writeBody() {
writeUleb128(bodyOutputStream, numSegments, "data count");
}
Expand Down
4 changes: 1 addition & 3 deletions lld/wasm/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,7 @@ class ElemSection : public SyntheticSection {

class DataCountSection : public SyntheticSection {
public:
DataCountSection(uint32_t numSegments)
: SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT),
numSegments(numSegments) {}
DataCountSection(ArrayRef<OutputSegment *> segments);
bool isNeeded() const override;
void writeBody() override;

Expand Down
9 changes: 8 additions & 1 deletion lld/wasm/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,13 @@ void Writer::createOutputSegments() {
s = make<OutputSegment>(name);
if (config->sharedMemory || name == ".tdata")
s->initFlags = WASM_SEGMENT_IS_PASSIVE;
// Exported memories are guaranteed to be zero-initialized, so no need
// to emit data segments for bss sections.
// TODO: consider initializing bss sections with memory.fill
// instructions when memory is imported and bulk-memory is available.
if (!config->importMemory && !config->relocatable &&
name.startswith(".bss"))
s->isBss = true;
segments.push_back(s);
}
s->addInputSegment(segment);
Expand Down Expand Up @@ -961,7 +968,7 @@ void Writer::createSyntheticSections() {
out.exportSec = make<ExportSection>();
out.startSec = make<StartSection>(segments.size());
out.elemSec = make<ElemSection>();
out.dataCountSec = make<DataCountSection>(segments.size());
out.dataCountSec = make<DataCountSection>(segments);
out.linkingSec = make<LinkingSection>(initFunctions, segments);
out.nameSec = make<NameSection>();
out.producersSec = make<ProducersSection>();
Expand Down

0 comments on commit 190dacc

Please sign in to comment.