mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[WebAssembly] Add COMDAT support
This adds COMDAT support to the Wasm object-file format. Spec: https://github.com/WebAssembly/tool-conventions/pull/31 Corresponding LLD change: https://bugs.llvm.org/show_bug.cgi?id=35533, and D40845 Patch by Nicholas Wilson Differential Revision: https://reviews.llvm.org/D40844 llvm-svn: 322135
This commit is contained in:
parent
bfc554dace
commit
9c22504bad
@ -883,8 +883,8 @@ The selection kind must be one of the following:
|
||||
The linker may choose any COMDAT key but the sections must contain the
|
||||
same amount of data.
|
||||
|
||||
Note that the Mach-O platform doesn't support COMDATs and ELF only supports
|
||||
``any`` as a selection kind.
|
||||
Note that the Mach-O platform doesn't support COMDATs, and ELF and WebAssembly
|
||||
only support ``any`` as a selection kind.
|
||||
|
||||
Here is an example of a COMDAT group where a function will only be selected if
|
||||
the COMDAT key's section is the largest:
|
||||
|
@ -660,9 +660,9 @@ public:
|
||||
return getArch() == Triple::aarch64 || getArch() == Triple::aarch64_be;
|
||||
}
|
||||
|
||||
/// Tests wether the target supports comdat
|
||||
/// Tests whether the target supports comdat
|
||||
bool supportsCOMDAT() const {
|
||||
return !isOSBinFormatMachO() && !isOSBinFormatWasm();
|
||||
return !isOSBinFormatMachO();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
@ -95,6 +95,7 @@ struct WasmFunction {
|
||||
ArrayRef<uint8_t> Body;
|
||||
uint32_t CodeSectionOffset;
|
||||
uint32_t Size;
|
||||
StringRef Comdat;
|
||||
};
|
||||
|
||||
struct WasmDataSegment {
|
||||
@ -104,6 +105,7 @@ struct WasmDataSegment {
|
||||
StringRef Name;
|
||||
uint32_t Alignment;
|
||||
uint32_t Flags;
|
||||
StringRef Comdat;
|
||||
};
|
||||
|
||||
struct WasmElemSegment {
|
||||
@ -173,11 +175,6 @@ enum : unsigned {
|
||||
WASM_OPCODE_F64_CONST = 0x44,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
WASM_NAMES_FUNCTION = 0x1,
|
||||
WASM_NAMES_LOCAL = 0x2,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
WASM_LIMITS_FLAG_HAS_MAX = 0x1,
|
||||
};
|
||||
@ -190,12 +187,25 @@ enum class ValType {
|
||||
F64 = WASM_TYPE_F64,
|
||||
};
|
||||
|
||||
// Linking metadata kinds.
|
||||
// Kind codes used in the custom "name" section
|
||||
enum : unsigned {
|
||||
WASM_NAMES_FUNCTION = 0x1,
|
||||
WASM_NAMES_LOCAL = 0x2,
|
||||
};
|
||||
|
||||
// Kind codes used in the custom "linking" section
|
||||
enum : unsigned {
|
||||
WASM_SYMBOL_INFO = 0x2,
|
||||
WASM_DATA_SIZE = 0x3,
|
||||
WASM_SEGMENT_INFO = 0x5,
|
||||
WASM_INIT_FUNCS = 0x6,
|
||||
WASM_COMDAT_INFO = 0x7,
|
||||
};
|
||||
|
||||
// Kind codes used in the custom "linking" section in the WASM_COMDAT_INFO
|
||||
enum : unsigned {
|
||||
WASM_COMDAT_DATA = 0x0,
|
||||
WASM_COMDAT_FUNCTION = 0x1,
|
||||
};
|
||||
|
||||
const unsigned WASM_SYMBOL_BINDING_MASK = 0x3;
|
||||
|
@ -149,6 +149,7 @@ public:
|
||||
ArrayRef<wasm::WasmElemSegment> elements() const { return ElemSegments; }
|
||||
ArrayRef<WasmSegment> dataSegments() const { return DataSegments; }
|
||||
ArrayRef<wasm::WasmFunction> functions() const { return Functions; }
|
||||
ArrayRef<StringRef> comdats() const { return Comdats; }
|
||||
uint32_t startFunction() const { return StartFunction; }
|
||||
|
||||
void moveSymbolNext(DataRefImpl &Symb) const override;
|
||||
@ -232,6 +233,7 @@ private:
|
||||
// Custom section types
|
||||
Error parseNameSection(const uint8_t *Ptr, const uint8_t *End);
|
||||
Error parseLinkingSection(const uint8_t *Ptr, const uint8_t *End);
|
||||
Error parseLinkingSectionComdat(const uint8_t *&Ptr, const uint8_t *End);
|
||||
Error parseRelocSection(StringRef Name, const uint8_t *Ptr,
|
||||
const uint8_t *End);
|
||||
|
||||
@ -250,6 +252,7 @@ private:
|
||||
std::vector<WasmSegment> DataSegments;
|
||||
std::vector<wasm::WasmFunction> Functions;
|
||||
std::vector<WasmSymbol> Symbols;
|
||||
std::vector<StringRef> Comdats;
|
||||
uint32_t StartFunction = -1;
|
||||
bool HasLinkingSection = false;
|
||||
wasm::WasmLinkingData LinkingData;
|
||||
|
@ -37,6 +37,7 @@ LLVM_YAML_STRONG_TYPEDEF(uint32_t, RelocType)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, SymbolFlags)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, SegmentFlags)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, LimitFlags)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ComdatKind)
|
||||
|
||||
struct FileHeader {
|
||||
yaml::Hex32 Version;
|
||||
@ -138,6 +139,16 @@ struct InitFunction {
|
||||
uint32_t FunctionIndex;
|
||||
};
|
||||
|
||||
struct ComdatEntry {
|
||||
ComdatKind Kind;
|
||||
uint32_t Index;
|
||||
};
|
||||
|
||||
struct Comdat {
|
||||
StringRef Name;
|
||||
std::vector<ComdatEntry> Entries;
|
||||
};
|
||||
|
||||
struct Section {
|
||||
explicit Section(SectionType SecType) : Type(SecType) {}
|
||||
virtual ~Section();
|
||||
@ -181,6 +192,7 @@ struct LinkingSection : CustomSection {
|
||||
std::vector<SymbolInfo> SymbolInfos;
|
||||
std::vector<SegmentInfo> SegmentInfos;
|
||||
std::vector<InitFunction> InitFunctions;
|
||||
std::vector<Comdat> Comdats;
|
||||
};
|
||||
|
||||
struct TypeSection : Section {
|
||||
@ -318,6 +330,8 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::NameEntry)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SegmentInfo)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SymbolInfo)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::InitFunction)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ComdatEntry)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Comdat)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
@ -414,6 +428,18 @@ template <> struct MappingTraits<WasmYAML::InitFunction> {
|
||||
static void mapping(IO &IO, WasmYAML::InitFunction &Init);
|
||||
};
|
||||
|
||||
template <> struct ScalarEnumerationTraits<WasmYAML::ComdatKind> {
|
||||
static void enumeration(IO &IO, WasmYAML::ComdatKind &Kind);
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<WasmYAML::ComdatEntry> {
|
||||
static void mapping(IO &IO, WasmYAML::ComdatEntry &ComdatEntry);
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<WasmYAML::Comdat> {
|
||||
static void mapping(IO &IO, WasmYAML::Comdat &Comdat);
|
||||
};
|
||||
|
||||
template <> struct ScalarEnumerationTraits<WasmYAML::ValueType> {
|
||||
static void enumeration(IO &IO, WasmYAML::ValueType &Type);
|
||||
};
|
||||
|
@ -1254,15 +1254,17 @@ void TargetLoweringObjectFileCOFF::emitLinkerFlagsForGlobal(
|
||||
// Wasm
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void checkWasmComdat(const GlobalValue *GV) {
|
||||
static const Comdat *getWasmComdat(const GlobalValue *GV) {
|
||||
const Comdat *C = GV->getComdat();
|
||||
if (!C)
|
||||
return;
|
||||
return nullptr;
|
||||
|
||||
// TODO(sbc): At some point we may need COMDAT support but currently
|
||||
// they are not supported.
|
||||
report_fatal_error("WebAssembly doesn't support COMDATs, '" + C->getName() +
|
||||
"' cannot be lowered.");
|
||||
if (C->getSelectionKind() != Comdat::Any)
|
||||
report_fatal_error("WebAssembly COMDATs only support "
|
||||
"SelectionKind::Any, '" + C->getName() + "' cannot be "
|
||||
"lowered.");
|
||||
|
||||
return C;
|
||||
}
|
||||
|
||||
static SectionKind getWasmKindForNamedSection(StringRef Name, SectionKind K) {
|
||||
@ -1278,16 +1280,25 @@ static SectionKind getWasmKindForNamedSection(StringRef Name, SectionKind K) {
|
||||
MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal(
|
||||
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
|
||||
StringRef Name = GO->getSection();
|
||||
checkWasmComdat(GO);
|
||||
|
||||
Kind = getWasmKindForNamedSection(Name, Kind);
|
||||
return getContext().getWasmSection(Name, Kind);
|
||||
|
||||
StringRef Group = "";
|
||||
if (const Comdat *C = getWasmComdat(GO)) {
|
||||
Group = C->getName();
|
||||
}
|
||||
|
||||
return getContext().getWasmSection(Name, Kind, Group,
|
||||
MCContext::GenericSectionID);
|
||||
}
|
||||
|
||||
static MCSectionWasm *selectWasmSectionForGlobal(
|
||||
MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang,
|
||||
const TargetMachine &TM, bool EmitUniqueSection, unsigned *NextUniqueID) {
|
||||
StringRef Group = "";
|
||||
checkWasmComdat(GO);
|
||||
if (const Comdat *C = getWasmComdat(GO)) {
|
||||
Group = C->getName();
|
||||
}
|
||||
|
||||
bool UniqueSectionNames = TM.getUniqueSectionNames();
|
||||
SmallString<128> Name = getSectionPrefixForGlobal(Kind);
|
||||
|
@ -138,6 +138,14 @@ struct WasmGlobal {
|
||||
uint32_t ImportIndex;
|
||||
};
|
||||
|
||||
// Information about a single item which is part of a COMDAT. For each data
|
||||
// segment or function which is in the COMDAT, there is a corresponding
|
||||
// WasmComdatEntry.
|
||||
struct WasmComdatEntry {
|
||||
unsigned Kind;
|
||||
uint32_t Index;
|
||||
};
|
||||
|
||||
// Information about a single relocation.
|
||||
struct WasmRelocationEntry {
|
||||
uint64_t Offset; // Where is the relocation.
|
||||
@ -284,8 +292,9 @@ private:
|
||||
void writeDataRelocSection();
|
||||
void writeLinkingMetaDataSection(
|
||||
ArrayRef<WasmDataSegment> Segments, uint32_t DataSize,
|
||||
const SmallVector<std::pair<StringRef, uint32_t>, 4> &SymbolFlags,
|
||||
const SmallVector<std::pair<uint16_t, uint32_t>, 2> &InitFuncs);
|
||||
ArrayRef<std::pair<StringRef, uint32_t>> SymbolFlags,
|
||||
ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
|
||||
const std::map<StringRef, std::vector<WasmComdatEntry>>& Comdats);
|
||||
|
||||
uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
|
||||
void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
|
||||
@ -913,8 +922,9 @@ void WasmObjectWriter::writeDataRelocSection() {
|
||||
|
||||
void WasmObjectWriter::writeLinkingMetaDataSection(
|
||||
ArrayRef<WasmDataSegment> Segments, uint32_t DataSize,
|
||||
const SmallVector<std::pair<StringRef, uint32_t>, 4> &SymbolFlags,
|
||||
const SmallVector<std::pair<uint16_t, uint32_t>, 2> &InitFuncs) {
|
||||
ArrayRef<std::pair<StringRef, uint32_t>> SymbolFlags,
|
||||
ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
|
||||
const std::map<StringRef, std::vector<WasmComdatEntry>>& Comdats) {
|
||||
SectionBookkeeping Section;
|
||||
startSection(Section, wasm::WASM_SEC_CUSTOM, "linking");
|
||||
SectionBookkeeping SubSection;
|
||||
@ -956,6 +966,21 @@ void WasmObjectWriter::writeLinkingMetaDataSection(
|
||||
endSection(SubSection);
|
||||
}
|
||||
|
||||
if (Comdats.size()) {
|
||||
startSection(SubSection, wasm::WASM_COMDAT_INFO);
|
||||
encodeULEB128(Comdats.size(), getStream());
|
||||
for (const auto &C : Comdats) {
|
||||
writeString(C.first);
|
||||
encodeULEB128(0, getStream()); // flags for future use
|
||||
encodeULEB128(C.second.size(), getStream());
|
||||
for (const WasmComdatEntry &Entry : C.second) {
|
||||
encodeULEB128(Entry.Kind, getStream());
|
||||
encodeULEB128(Entry.Index, getStream());
|
||||
}
|
||||
}
|
||||
endSection(SubSection);
|
||||
}
|
||||
|
||||
endSection(Section);
|
||||
}
|
||||
|
||||
@ -997,6 +1022,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
SmallVector<WasmExport, 4> Exports;
|
||||
SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags;
|
||||
SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
|
||||
std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
|
||||
unsigned NumFuncImports = 0;
|
||||
SmallVector<WasmDataSegment, 4> DataSegments;
|
||||
uint32_t DataSize = 0;
|
||||
@ -1143,6 +1169,12 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
Segment.Flags = 0;
|
||||
DataSize += Segment.Data.size();
|
||||
Section.setMemoryOffset(Segment.Offset);
|
||||
|
||||
if (const MCSymbolWasm *C = Section.getGroup()) {
|
||||
Comdats[C->getName()].emplace_back(
|
||||
WasmComdatEntry{wasm::WASM_COMDAT_DATA,
|
||||
static_cast<uint32_t>(DataSegments.size()) - 1});
|
||||
}
|
||||
}
|
||||
|
||||
// Handle regular defined and undefined symbols.
|
||||
@ -1216,6 +1248,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
// address. For externals these will also be named exports.
|
||||
Index = NumGlobalImports + Globals.size();
|
||||
auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
|
||||
assert(DataSection.isWasmData());
|
||||
|
||||
WasmGlobal Global;
|
||||
Global.Type = PtrType;
|
||||
@ -1239,8 +1272,16 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
Export.Kind = wasm::WASM_EXTERNAL_GLOBAL;
|
||||
DEBUG(dbgs() << " -> export " << Exports.size() << "\n");
|
||||
Exports.push_back(Export);
|
||||
|
||||
if (!WS.isExternal())
|
||||
SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL);
|
||||
|
||||
if (WS.isFunction()) {
|
||||
auto &Section = static_cast<MCSectionWasm &>(WS.getSection(false));
|
||||
if (const MCSymbolWasm *C = Section.getGroup())
|
||||
Comdats[C->getName()].emplace_back(
|
||||
WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1372,7 +1413,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
writeCodeRelocSection();
|
||||
writeDataRelocSection();
|
||||
writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags,
|
||||
InitFuncs);
|
||||
InitFuncs, Comdats);
|
||||
|
||||
// TODO: Translate the .comment section to the output.
|
||||
// TODO: Translate debug sections to the output.
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/BinaryFormat/Wasm.h"
|
||||
#include "llvm/MC/SubtargetFeature.h"
|
||||
@ -422,6 +423,10 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wasm::WASM_COMDAT_INFO:
|
||||
if (Error Err = parseLinkingSectionComdat(Ptr, SubSectionEnd))
|
||||
return Err;
|
||||
break;
|
||||
default:
|
||||
Ptr += Size;
|
||||
break;
|
||||
@ -436,6 +441,55 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error WasmObjectFile::parseLinkingSectionComdat(const uint8_t *&Ptr,
|
||||
const uint8_t *End)
|
||||
{
|
||||
uint32_t ComdatCount = readVaruint32(Ptr);
|
||||
StringSet<> ComdatSet;
|
||||
while (ComdatCount--) {
|
||||
StringRef Name = readString(Ptr);
|
||||
if (Name.empty() || !ComdatSet.insert(Name).second)
|
||||
return make_error<GenericBinaryError>("Bad/duplicate COMDAT name " + Twine(Name),
|
||||
object_error::parse_failed);
|
||||
Comdats.emplace_back(Name);
|
||||
uint32_t Flags = readVaruint32(Ptr);
|
||||
if (Flags != 0)
|
||||
return make_error<GenericBinaryError>("Unsupported COMDAT flags",
|
||||
object_error::parse_failed);
|
||||
|
||||
uint32_t EntryCount = readVaruint32(Ptr);
|
||||
while (EntryCount--) {
|
||||
unsigned Kind = readVaruint32(Ptr);
|
||||
unsigned Index = readVaruint32(Ptr);
|
||||
switch (Kind) {
|
||||
default:
|
||||
return make_error<GenericBinaryError>("Invalid COMDAT entry type",
|
||||
object_error::parse_failed);
|
||||
case wasm::WASM_COMDAT_DATA:
|
||||
if (Index >= DataSegments.size())
|
||||
return make_error<GenericBinaryError>("COMDAT data index out of range",
|
||||
object_error::parse_failed);
|
||||
if (!DataSegments[Index].Data.Comdat.empty())
|
||||
return make_error<GenericBinaryError>("Data segment in two COMDATs",
|
||||
object_error::parse_failed);
|
||||
DataSegments[Index].Data.Comdat = Name;
|
||||
break;
|
||||
case wasm::WASM_COMDAT_FUNCTION:
|
||||
if (Index < NumImportedFunctions || !isValidFunctionIndex(Index))
|
||||
return make_error<GenericBinaryError>("COMDAT function index out of range",
|
||||
object_error::parse_failed);
|
||||
Index -= NumImportedFunctions;
|
||||
if (!Functions[Index].Comdat.empty())
|
||||
return make_error<GenericBinaryError>("Function in two COMDATs",
|
||||
object_error::parse_failed);
|
||||
Functions[Index].Comdat = Name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
WasmSection* WasmObjectFile::findCustomSectionByName(StringRef Name) {
|
||||
for (WasmSection& Section : Sections) {
|
||||
if (Section.Type == wasm::WASM_SEC_CUSTOM && Section.Name == Name)
|
||||
|
@ -61,6 +61,7 @@ static void sectionMapping(IO &IO, WasmYAML::LinkingSection &Section) {
|
||||
IO.mapOptional("SymbolInfo", Section.SymbolInfos);
|
||||
IO.mapOptional("SegmentInfo", Section.SegmentInfos);
|
||||
IO.mapOptional("InitFunctions", Section.InitFunctions);
|
||||
IO.mapOptional("Comdats", Section.Comdats);
|
||||
}
|
||||
|
||||
static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) {
|
||||
@ -368,6 +369,26 @@ void MappingTraits<WasmYAML::InitFunction>::mapping(
|
||||
IO.mapRequired("FunctionIndex", Init.FunctionIndex);
|
||||
}
|
||||
|
||||
void ScalarEnumerationTraits<WasmYAML::ComdatKind>::enumeration(
|
||||
IO &IO, WasmYAML::ComdatKind &Kind) {
|
||||
#define ECase(X) IO.enumCase(Kind, #X, wasm::WASM_COMDAT_##X);
|
||||
ECase(FUNCTION);
|
||||
ECase(DATA);
|
||||
#undef ECase
|
||||
}
|
||||
|
||||
void MappingTraits<WasmYAML::ComdatEntry>::mapping(
|
||||
IO &IO, WasmYAML::ComdatEntry &ComdatEntry) {
|
||||
IO.mapRequired("Kind", ComdatEntry.Kind);
|
||||
IO.mapRequired("Index", ComdatEntry.Index);
|
||||
}
|
||||
|
||||
void MappingTraits<WasmYAML::Comdat>::mapping(
|
||||
IO &IO, WasmYAML::Comdat &Comdat) {
|
||||
IO.mapRequired("Name", Comdat.Name);
|
||||
IO.mapRequired("Entries", Comdat.Entries);
|
||||
}
|
||||
|
||||
void MappingTraits<WasmYAML::SymbolInfo>::mapping(IO &IO,
|
||||
WasmYAML::SymbolInfo &Info) {
|
||||
IO.mapRequired("Name", Info.Name);
|
||||
|
@ -1,5 +0,0 @@
|
||||
; RUN: not llc < %s -mtriple wasm32-unknown-unknown-wasm 2>&1 | FileCheck %s
|
||||
|
||||
$f = comdat any
|
||||
@f = global i32 0, comdat
|
||||
; CHECK: LLVM ERROR: WebAssembly doesn't support COMDATs, 'f' cannot be lowered.
|
99
test/MC/WebAssembly/comdat.ll
Normal file
99
test/MC/WebAssembly/comdat.ll
Normal file
@ -0,0 +1,99 @@
|
||||
; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj %s -o - | obj2yaml | FileCheck %s
|
||||
|
||||
; Import a function just so we can check the index arithmetic for
|
||||
; WASM_COMDAT_FUNCTION entries is performed correctly
|
||||
declare i32 @funcImport()
|
||||
define i32 @callImport() {
|
||||
entry:
|
||||
%call = call i32 @funcImport()
|
||||
ret i32 %call
|
||||
}
|
||||
|
||||
; Function in its own COMDAT
|
||||
$basicInlineFn = comdat any
|
||||
define linkonce_odr i32 @basicInlineFn() #1 comdat {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Global, data, and function in same COMDAT
|
||||
$sharedComdat = comdat any
|
||||
@constantData = weak_odr constant [3 x i8] c"abc", comdat($sharedComdat)
|
||||
define linkonce_odr i32 @sharedFn() #1 comdat($sharedComdat) {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; CHECK: - Type: EXPORT
|
||||
; CHECK-NEXT: Exports:
|
||||
; CHECK-NEXT: - Name: callImport
|
||||
; CHECK-NEXT: Kind: FUNCTION
|
||||
; CHECK-NEXT: Index: 1
|
||||
; CHECK-NEXT: - Name: basicInlineFn
|
||||
; CHECK-NEXT: Kind: FUNCTION
|
||||
; CHECK-NEXT: Index: 2
|
||||
; CHECK-NEXT: - Name: sharedFn
|
||||
; CHECK-NEXT: Kind: FUNCTION
|
||||
; CHECK-NEXT: Index: 3
|
||||
; CHECK-NEXT: - Name: constantData
|
||||
; CHECK-NEXT: Kind: GLOBAL
|
||||
; CHECK-NEXT: Index: 1
|
||||
; CHECK-NEXT: - Type: CODE
|
||||
; CHECK-NEXT: Relocations:
|
||||
; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
|
||||
; CHECK-NEXT: Index: 0
|
||||
; CHECK-NEXT: Offset: 0x00000004
|
||||
; CHECK-NEXT: Functions:
|
||||
; CHECK-NEXT: - Index: 1
|
||||
; CHECK-NEXT: Locals:
|
||||
; CHECK-NEXT: Body: 1080808080000B
|
||||
; CHECK-NEXT: - Index: 2
|
||||
; CHECK-NEXT: Locals:
|
||||
; CHECK-NEXT: Body: 41000B
|
||||
; CHECK-NEXT: - Index: 3
|
||||
; CHECK-NEXT: Locals:
|
||||
; CHECK-NEXT: Body: 41000B
|
||||
; 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: '616263'
|
||||
; CHECK-NEXT: - Type: CUSTOM
|
||||
; CHECK-NEXT: Name: name
|
||||
; CHECK-NEXT: FunctionNames:
|
||||
; CHECK-NEXT: - Index: 0
|
||||
; CHECK-NEXT: Name: funcImport
|
||||
; CHECK-NEXT: - Index: 1
|
||||
; CHECK-NEXT: Name: callImport
|
||||
; CHECK-NEXT: - Index: 2
|
||||
; CHECK-NEXT: Name: basicInlineFn
|
||||
; CHECK-NEXT: - Index: 3
|
||||
; CHECK-NEXT: Name: sharedFn
|
||||
; CHECK-NEXT: - Type: CUSTOM
|
||||
; CHECK-NEXT: Name: linking
|
||||
; CHECK-NEXT: DataSize: 3
|
||||
; CHECK-NEXT: SymbolInfo:
|
||||
; CHECK-NEXT: - Name: basicInlineFn
|
||||
; CHECK-NEXT: Flags: [ BINDING_WEAK ]
|
||||
; CHECK-NEXT: - Name: sharedFn
|
||||
; CHECK-NEXT: Flags: [ BINDING_WEAK ]
|
||||
; CHECK-NEXT: - Name: constantData
|
||||
; CHECK-NEXT: Flags: [ BINDING_WEAK ]
|
||||
; CHECK-NEXT: SegmentInfo:
|
||||
; CHECK-NEXT: - Index: 0
|
||||
; CHECK-NEXT: Name: .rodata.constantData
|
||||
; CHECK-NEXT: Alignment: 1
|
||||
; CHECK-NEXT: Flags: [ ]
|
||||
; CHECK-NEXT: Comdats:
|
||||
; CHECK-NEXT: - Name: basicInlineFn
|
||||
; CHECK-NEXT: Entries:
|
||||
; CHECK-NEXT: - Kind: FUNCTION
|
||||
; CHECK-NEXT: Index: 2
|
||||
; CHECK-NEXT: - Name: sharedComdat
|
||||
; CHECK-NEXT: Entries:
|
||||
; CHECK-NEXT: - Kind: FUNCTION
|
||||
; CHECK-NEXT: Index: 3
|
||||
; CHECK-NEXT: - Kind: DATA
|
||||
; CHECK-NEXT: Index: 0
|
||||
; CHECK-NEXT: ...
|
@ -65,17 +65,34 @@ std::unique_ptr<WasmYAML::CustomSection> WasmDumper::dumpCustomSection(const Was
|
||||
CustomSec = std::move(NameSec);
|
||||
} else if (WasmSec.Name == "linking") {
|
||||
std::unique_ptr<WasmYAML::LinkingSection> LinkingSec = make_unique<WasmYAML::LinkingSection>();
|
||||
size_t Index = 0;
|
||||
std::map<StringRef,size_t> ComdatIndexes;
|
||||
for (StringRef ComdatName : Obj.comdats()) {
|
||||
ComdatIndexes[ComdatName] = LinkingSec->Comdats.size();
|
||||
LinkingSec->Comdats.emplace_back(WasmYAML::Comdat{ComdatName, {}});
|
||||
}
|
||||
for (auto &Func : Obj.functions()) {
|
||||
if (!Func.Comdat.empty()) {
|
||||
auto &Comdat = LinkingSec->Comdats[ComdatIndexes[Func.Comdat]];
|
||||
Comdat.Entries.emplace_back(
|
||||
WasmYAML::ComdatEntry{wasm::WASM_COMDAT_FUNCTION, Func.Index});
|
||||
}
|
||||
}
|
||||
uint32_t SegmentIndex = 0;
|
||||
for (const object::WasmSegment &Segment : Obj.dataSegments()) {
|
||||
if (!Segment.Data.Name.empty()) {
|
||||
WasmYAML::SegmentInfo SegmentInfo;
|
||||
SegmentInfo.Name = Segment.Data.Name;
|
||||
SegmentInfo.Index = Index;
|
||||
SegmentInfo.Index = SegmentIndex;
|
||||
SegmentInfo.Alignment = Segment.Data.Alignment;
|
||||
SegmentInfo.Flags = Segment.Data.Flags;
|
||||
LinkingSec->SegmentInfos.push_back(SegmentInfo);
|
||||
}
|
||||
Index++;
|
||||
if (!Segment.Data.Comdat.empty()) {
|
||||
auto &Comdat = LinkingSec->Comdats[ComdatIndexes[Segment.Data.Comdat]];
|
||||
Comdat.Entries.emplace_back(
|
||||
WasmYAML::ComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
|
||||
}
|
||||
SegmentIndex++;
|
||||
}
|
||||
for (const object::SymbolRef& Sym: Obj.symbols()) {
|
||||
const object::WasmSymbol Symbol = Obj.getWasmSymbol(Sym);
|
||||
|
@ -175,6 +175,23 @@ int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &S
|
||||
}
|
||||
SubSection.Done();
|
||||
}
|
||||
|
||||
// COMDAT_INFO subsection
|
||||
if (Section.Comdats.size()) {
|
||||
encodeULEB128(wasm::WASM_COMDAT_INFO, OS);
|
||||
encodeULEB128(Section.Comdats.size(), SubSection.GetStream());
|
||||
for (const auto &C : Section.Comdats) {
|
||||
writeStringRef(C.Name, SubSection.GetStream());
|
||||
encodeULEB128(0, SubSection.GetStream()); // flags for future use
|
||||
encodeULEB128(C.Entries.size(), SubSection.GetStream());
|
||||
for (const WasmYAML::ComdatEntry &Entry : C.Entries) {
|
||||
encodeULEB128(Entry.Kind, SubSection.GetStream());
|
||||
encodeULEB128(Entry.Index, SubSection.GetStream());
|
||||
}
|
||||
}
|
||||
SubSection.Done();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user