[WebAssembly] MC: Create wasm data segments based on MCSections

This means that we can honor -fdata-sections rather than
always creating a segment for each symbol.

It also allows for a followup change to add .init_array and friends.

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

llvm-svn: 313395
This commit is contained in:
Sam Clegg 2017-09-15 20:54:59 +00:00
parent d75c714e9b
commit 91f177ea59
6 changed files with 151 additions and 69 deletions

View File

@ -43,11 +43,17 @@ private:
// itself and does not include the size of the section header.
uint64_t SectionOffset;
// For data sections, this is the offset of the corresponding wasm data
// segment
uint64_t MemoryOffset;
friend class MCContext;
MCSectionWasm(StringRef Section, unsigned type, SectionKind K,
const MCSymbolWasm *group, unsigned UniqueID, MCSymbol *Begin)
: MCSection(SV_Wasm, K, Begin), SectionName(Section), Type(type),
UniqueID(UniqueID), Group(group), SectionOffset(0) {}
UniqueID(UniqueID), Group(group), SectionOffset(0) {
assert(type == wasm::WASM_SEC_CODE || type == wasm::WASM_SEC_DATA);
}
void setSectionName(StringRef Name) { SectionName = Name; }
@ -74,6 +80,9 @@ public:
uint64_t getSectionOffset() const { return SectionOffset; }
void setSectionOffset(uint64_t Offset) { SectionOffset = Offset; }
uint32_t getMemoryOffset() const { return MemoryOffset; }
void setMemoryOffset(uint32_t Offset) { MemoryOffset = Offset; }
static bool classof(const MCSection *S) { return S->getVariant() == SV_Wasm; }
};

View File

@ -1248,8 +1248,8 @@ static const Comdat *getWasmComdat(const GlobalValue *GV) {
MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
llvm_unreachable("getExplicitSectionGlobal not yet implemented");
return nullptr;
StringRef Name = GO->getSection();
return getContext().getWasmSection(Name, wasm::WASM_SEC_DATA);
}
static MCSectionWasm *selectWasmSectionForGlobal(
@ -1262,10 +1262,12 @@ static MCSectionWasm *selectWasmSectionForGlobal(
bool UniqueSectionNames = TM.getUniqueSectionNames();
SmallString<128> Name = getSectionPrefixForGlobal(Kind);
uint32_t Type = wasm::WASM_SEC_DATA;
if (const auto *F = dyn_cast<Function>(GO)) {
const auto &OptionalPrefix = F->getSectionPrefix();
if (OptionalPrefix)
Name += *OptionalPrefix;
Type = wasm::WASM_SEC_CODE;
}
if (EmitUniqueSection && UniqueSectionNames) {
@ -1277,7 +1279,7 @@ static MCSectionWasm *selectWasmSectionForGlobal(
UniqueID = *NextUniqueID;
(*NextUniqueID)++;
}
return Ctx.getWasmSection(Name, /*Type=*/0, Group, UniqueID);
return Ctx.getWasmSection(Name, Type, Group, UniqueID);
}
MCSection *TargetLoweringObjectFileWasm::SelectSectionForGlobal(

View File

@ -820,24 +820,24 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) {
void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) {
// TODO: Set the section types and flags.
TextSection = Ctx->getWasmSection(".text", 0);
DataSection = Ctx->getWasmSection(".data", 0);
TextSection = Ctx->getWasmSection(".text", wasm::WASM_SEC_CODE);
DataSection = Ctx->getWasmSection(".data", wasm::WASM_SEC_DATA);
// TODO: Set the section types and flags.
DwarfLineSection = Ctx->getWasmSection(".debug_line", 0);
DwarfStrSection = Ctx->getWasmSection(".debug_str", 0);
DwarfLocSection = Ctx->getWasmSection(".debug_loc", 0);
DwarfAbbrevSection = Ctx->getWasmSection(".debug_abbrev", 0, "section_abbrev");
DwarfARangesSection = Ctx->getWasmSection(".debug_aranges", 0);
DwarfRangesSection = Ctx->getWasmSection(".debug_ranges", 0, "debug_range");
DwarfMacinfoSection = Ctx->getWasmSection(".debug_macinfo", 0, "debug_macinfo");
DwarfAddrSection = Ctx->getWasmSection(".debug_addr", 0);
DwarfCUIndexSection = Ctx->getWasmSection(".debug_cu_index", 0);
DwarfTUIndexSection = Ctx->getWasmSection(".debug_tu_index", 0);
DwarfInfoSection = Ctx->getWasmSection(".debug_info", 0, "section_info");
DwarfFrameSection = Ctx->getWasmSection(".debug_frame", 0);
DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", 0);
DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", 0);
DwarfLineSection = Ctx->getWasmSection(".debug_line", wasm::WASM_SEC_DATA);
DwarfStrSection = Ctx->getWasmSection(".debug_str", wasm::WASM_SEC_DATA);
DwarfLocSection = Ctx->getWasmSection(".debug_loc", wasm::WASM_SEC_DATA);
DwarfAbbrevSection = Ctx->getWasmSection(".debug_abbrev", wasm::WASM_SEC_DATA, "section_abbrev");
DwarfARangesSection = Ctx->getWasmSection(".debug_aranges", wasm::WASM_SEC_DATA);
DwarfRangesSection = Ctx->getWasmSection(".debug_ranges", wasm::WASM_SEC_DATA, "debug_range");
DwarfMacinfoSection = Ctx->getWasmSection(".debug_macinfo", wasm::WASM_SEC_DATA, "debug_macinfo");
DwarfAddrSection = Ctx->getWasmSection(".debug_addr", wasm::WASM_SEC_DATA);
DwarfCUIndexSection = Ctx->getWasmSection(".debug_cu_index", wasm::WASM_SEC_DATA);
DwarfTUIndexSection = Ctx->getWasmSection(".debug_tu_index", wasm::WASM_SEC_DATA);
DwarfInfoSection = Ctx->getWasmSection(".debug_info", wasm::WASM_SEC_DATA, "section_info");
DwarfFrameSection = Ctx->getWasmSection(".debug_frame", wasm::WASM_SEC_DATA);
DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", wasm::WASM_SEC_DATA);
DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", wasm::WASM_SEC_DATA);
// TODO: Define more sections.
}

View File

@ -156,7 +156,7 @@ void MCWasmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
void MCWasmStreamer::EmitIdent(StringRef IdentString) {
MCSection *Comment = getAssembler().getContext().getWasmSection(
".comment", 0, 0);
".comment", wasm::WASM_SEC_DATA);
PushSection();
SwitchSection(Comment);
if (!SeenIdent) {

View File

@ -163,7 +163,8 @@ struct WasmRelocationEntry {
void print(raw_ostream &Out) const {
Out << "Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend
<< ", Type=" << Type << ", FixupSection=" << FixupSection;
<< ", Type=" << Type
<< ", FixupSection=" << FixupSection->getSectionName();
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
@ -495,6 +496,39 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
return Value;
}
static void addData(SmallVectorImpl<char> &DataBytes,
MCSectionWasm &DataSection, uint32_t &DataAlignment) {
DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
DataAlignment = std::max(DataAlignment, DataSection.getAlignment());
DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n");
for (const MCFragment &Frag : DataSection) {
if (Frag.hasInstructions())
report_fatal_error("only data supported in data sections");
if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) {
if (Align->getValueSize() != 1)
report_fatal_error("only byte values supported for alignment");
// If nops are requested, use zeros, as this is the data section.
uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(),
Align->getAlignment()),
DataBytes.size() +
Align->getMaxBytesToEmit());
DataBytes.resize(Size, Value);
} else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) {
DataBytes.insert(DataBytes.end(), Fill->getSize(), Fill->getValue());
} else {
const auto &DataFrag = cast<MCDataFragment>(Frag);
const SmallVectorImpl<char> &Contents = DataFrag.getContents();
DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
}
}
DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n");
}
uint32_t WasmObjectWriter::getRelocationIndexValue(
const WasmRelocationEntry &RelEntry) {
switch (RelEntry.Type) {
@ -773,9 +807,7 @@ void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
report_fatal_error(".size expression must be evaluatable");
encodeULEB128(Size, getStream());
FuncSection.setSectionOffset(getStream().tell() - Section.ContentsOffset);
Asm.writeSectionData(&FuncSection, Layout);
}
@ -1016,7 +1048,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
// In the special .global_variables section, we've encoded global
// variables used by the function. Translate them into the Globals
// list.
MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", 0, 0);
MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", wasm::WASM_SEC_DATA);
if (!GlobalVars->getFragmentList().empty()) {
if (GlobalVars->getFragmentList().size() != 1)
report_fatal_error("only one .global_variables fragment supported");
@ -1072,7 +1104,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
// In the special .stack_pointer section, we've encoded the stack pointer
// index.
MCSectionWasm *StackPtr = Ctx.getWasmSection(".stack_pointer", 0, 0);
MCSectionWasm *StackPtr = Ctx.getWasmSection(".stack_pointer", wasm::WASM_SEC_DATA);
if (!StackPtr->getFragmentList().empty()) {
if (StackPtr->getFragmentList().size() != 1)
report_fatal_error("only one .stack_pointer fragment supported");
@ -1089,6 +1121,21 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data();
}
for (MCSection &Sec : Asm) {
auto &Section = static_cast<MCSectionWasm &>(Sec);
if (Section.getType() != wasm::WASM_SEC_DATA)
continue;
DataSize = alignTo(DataSize, Section.getAlignment());
DataSegments.emplace_back();
WasmDataSegment &Segment = DataSegments.back();
Segment.Offset = DataSize;
Segment.Section = &Section;
addData(Segment.Data, Section, DataAlignment);
DataSize += Segment.Data.size();
Section.setMemoryOffset(Segment.Offset);
}
// Handle regular defined and undefined symbols.
for (const MCSymbol &S : Asm.symbols()) {
// Ignore unnamed temporary symbols, which aren't ever exported, imported,
@ -1151,9 +1198,6 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
if (!WS.isDefined(/*SetUsed=*/false))
continue;
if (WS.getOffset() != 0)
report_fatal_error("data sections must contain one variable each: " +
WS.getName());
if (!WS.getSize())
report_fatal_error("data symbols must have a size set with .size: " +
WS.getName());
@ -1162,58 +1206,20 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
report_fatal_error(".size expression must be evaluatable");
auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection))
report_fatal_error("data sections must contain at most one variable");
DataAlignment = std::max(DataAlignment, DataSection.getAlignment());
DataSegments.emplace_back();
WasmDataSegment &Segment = DataSegments.back();
DataSize = alignTo(DataSize, DataSection.getAlignment());
Segment.Offset = DataSize;
Segment.Section = &DataSection;
// For each global, prepare a corresponding wasm global holding its
// address. For externals these will also be named exports.
Index = NumGlobalImports + Globals.size();
auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
WasmGlobal Global;
Global.Type = PtrType;
Global.IsMutable = false;
Global.HasImport = false;
Global.InitialValue = DataSize;
Global.InitialValue = DataSection.getMemoryOffset() + Layout.getSymbolOffset(WS);
Global.ImportIndex = 0;
SymbolIndices[&WS] = Index;
DEBUG(dbgs() << " -> global index: " << Index << "\n");
Globals.push_back(Global);
for (const MCFragment &Frag : DataSection) {
if (Frag.hasInstructions())
report_fatal_error("only data supported in data sections");
if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) {
if (Align->getValueSize() != 1)
report_fatal_error("only byte values supported for alignment");
// If nops are requested, use zeros, as this is the data section.
uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
uint64_t Size = std::min<uint64_t>(
alignTo(Segment.Data.size(), Align->getAlignment()),
Segment.Data.size() + Align->getMaxBytesToEmit());
Segment.Data.resize(Size, Value);
} else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) {
Segment.Data.insert(Segment.Data.end(), Fill->getSize(), Fill->getValue());
} else {
const auto &DataFrag = cast<MCDataFragment>(Frag);
const SmallVectorImpl<char> &Contents = DataFrag.getContents();
Segment.Data.insert(Segment.Data.end(), Contents.begin(),
Contents.end());
}
}
DataSize += Segment.Data.size();
}
// If the symbol is visible outside this translation unit, export it.

View File

@ -0,0 +1,65 @@
; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj %s -o - | obj2yaml | FileCheck %s
%struct.bd = type { i32, i8 }
@global0 = global i32 8, align 8
@global1 = global %struct.bd { i32 1, i8 3 }, align 8, section ".sec1"
@global2 = global i64 7, align 8, section ".sec1"
@global3 = global i32 8, align 8, section ".sec2"
; CHECK: - Type: GLOBAL
; CHECK-NEXT: Globals:
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 0
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 8
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 16
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 24
; CHECK-NEXT: - Type: EXPORT
; CHECK-NEXT: Exports:
; CHECK-NEXT: - Name: global0
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 0
; CHECK-NEXT: - Name: global1
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: global2
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: global3
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 6
; CHECK-NEXT: MemoryIndex: 0
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 0
; CHECK-NEXT: Content: '08000000'
; CHECK-NEXT: - SectionOffset: 15
; CHECK-NEXT: MemoryIndex: 0
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 8
; CHECK-NEXT: Content: '01000000030000000700000000000000'
; CHECK-NEXT: - SectionOffset: 36
; CHECK-NEXT: MemoryIndex: 0
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 24
; CHECK-NEXT: Content: '08000000'