[WebAssembly] Elide data segments for .bss sections
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
This commit is contained in:
parent
0330fba6e1
commit
190dacc3cc
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -128,8 +128,11 @@ 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();
|
||||
|
||||
|
@ -137,6 +140,8 @@ void DataSection::finalizeContents() {
|
|||
"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)
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
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:
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
}
|
||||
|
||||
StringRef name;
|
||||
bool isBss = false;
|
||||
uint32_t index = 0;
|
||||
uint32_t initFlags = 0;
|
||||
uint32_t sectionOffset = 0;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -250,9 +250,7 @@ protected:
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
@ -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>();
|
||||
|
|
Loading…
Reference in New Issue