llvm.org GIT mirror llvm / e92250a
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@322135 91177308-0d34-0410-b5e6-96231b3b80d8 Sam Clegg 1 year, 9 months ago
13 changed file(s) with 327 addition(s) and 33 deletion(s). Raw diff Collapse all Expand all
882882 The linker may choose any COMDAT key but the sections must contain the
883883 same amount of data.
884884
885 Note that the Mach-O platform doesn't support COMDATs and ELF only supports
886 ``any`` as a selection kind.
885 Note that the Mach-O platform doesn't support COMDATs, and ELF and WebAssembly
886 only support ``any`` as a selection kind.
887887
888888 Here is an example of a COMDAT group where a function will only be selected if
889889 the COMDAT key's section is the largest:
659659 return getArch() == Triple::aarch64 || getArch() == Triple::aarch64_be;
660660 }
661661
662 /// Tests wether the target supports comdat
662 /// Tests whether the target supports comdat
663663 bool supportsCOMDAT() const {
664 return !isOSBinFormatMachO() && !isOSBinFormatWasm();
664 return !isOSBinFormatMachO();
665665 }
666666
667667 /// @}
9494 ArrayRef Body;
9595 uint32_t CodeSectionOffset;
9696 uint32_t Size;
97 StringRef Comdat;
9798 };
9899
99100 struct WasmDataSegment {
103104 StringRef Name;
104105 uint32_t Alignment;
105106 uint32_t Flags;
107 StringRef Comdat;
106108 };
107109
108110 struct WasmElemSegment {
173175 };
174176
175177 enum : unsigned {
176 WASM_NAMES_FUNCTION = 0x1,
177 WASM_NAMES_LOCAL = 0x2,
178 };
179
180 enum : unsigned {
181178 WASM_LIMITS_FLAG_HAS_MAX = 0x1,
182179 };
183180
189186 F64 = WASM_TYPE_F64,
190187 };
191188
192 // Linking metadata kinds.
189 // Kind codes used in the custom "name" section
190 enum : unsigned {
191 WASM_NAMES_FUNCTION = 0x1,
192 WASM_NAMES_LOCAL = 0x2,
193 };
194
195 // Kind codes used in the custom "linking" section
193196 enum : unsigned {
194197 WASM_SYMBOL_INFO = 0x2,
195198 WASM_DATA_SIZE = 0x3,
196199 WASM_SEGMENT_INFO = 0x5,
197200 WASM_INIT_FUNCS = 0x6,
201 WASM_COMDAT_INFO = 0x7,
202 };
203
204 // Kind codes used in the custom "linking" section in the WASM_COMDAT_INFO
205 enum : unsigned {
206 WASM_COMDAT_DATA = 0x0,
207 WASM_COMDAT_FUNCTION = 0x1,
198208 };
199209
200210 const unsigned WASM_SYMBOL_BINDING_MASK = 0x3;
148148 ArrayRef elements() const { return ElemSegments; }
149149 ArrayRef dataSegments() const { return DataSegments; }
150150 ArrayRef functions() const { return Functions; }
151 ArrayRef comdats() const { return Comdats; }
151152 uint32_t startFunction() const { return StartFunction; }
152153
153154 void moveSymbolNext(DataRefImpl &Symb) const override;
231232 // Custom section types
232233 Error parseNameSection(const uint8_t *Ptr, const uint8_t *End);
233234 Error parseLinkingSection(const uint8_t *Ptr, const uint8_t *End);
235 Error parseLinkingSectionComdat(const uint8_t *&Ptr, const uint8_t *End);
234236 Error parseRelocSection(StringRef Name, const uint8_t *Ptr,
235237 const uint8_t *End);
236238
249251 std::vector DataSegments;
250252 std::vector Functions;
251253 std::vector Symbols;
254 std::vector Comdats;
252255 uint32_t StartFunction = -1;
253256 bool HasLinkingSection = false;
254257 wasm::WasmLinkingData LinkingData;
3636 LLVM_YAML_STRONG_TYPEDEF(uint32_t, SymbolFlags)
3737 LLVM_YAML_STRONG_TYPEDEF(uint32_t, SegmentFlags)
3838 LLVM_YAML_STRONG_TYPEDEF(uint32_t, LimitFlags)
39 LLVM_YAML_STRONG_TYPEDEF(uint32_t, ComdatKind)
3940
4041 struct FileHeader {
4142 yaml::Hex32 Version;
137138 uint32_t FunctionIndex;
138139 };
139140
141 struct ComdatEntry {
142 ComdatKind Kind;
143 uint32_t Index;
144 };
145
146 struct Comdat {
147 StringRef Name;
148 std::vector Entries;
149 };
150
140151 struct Section {
141152 explicit Section(SectionType SecType) : Type(SecType) {}
142153 virtual ~Section();
180191 std::vector SymbolInfos;
181192 std::vector SegmentInfos;
182193 std::vector InitFunctions;
194 std::vector Comdats;
183195 };
184196
185197 struct TypeSection : Section {
317329 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SegmentInfo)
318330 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SymbolInfo)
319331 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::InitFunction)
332 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ComdatEntry)
333 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Comdat)
320334
321335 namespace llvm {
322336 namespace yaml {
413427 static void mapping(IO &IO, WasmYAML::InitFunction &Init);
414428 };
415429
430 template <> struct ScalarEnumerationTraits {
431 static void enumeration(IO &IO, WasmYAML::ComdatKind &Kind);
432 };
433
434 template <> struct MappingTraits {
435 static void mapping(IO &IO, WasmYAML::ComdatEntry &ComdatEntry);
436 };
437
438 template <> struct MappingTraits {
439 static void mapping(IO &IO, WasmYAML::Comdat &Comdat);
440 };
441
416442 template <> struct ScalarEnumerationTraits {
417443 static void enumeration(IO &IO, WasmYAML::ValueType &Type);
418444 };
12531253 // Wasm
12541254 //===----------------------------------------------------------------------===//
12551255
1256 static void checkWasmComdat(const GlobalValue *GV) {
1256 static const Comdat *getWasmComdat(const GlobalValue *GV) {
12571257 const Comdat *C = GV->getComdat();
12581258 if (!C)
1259 return;
1260
1261 // TODO(sbc): At some point we may need COMDAT support but currently
1262 // they are not supported.
1263 report_fatal_error("WebAssembly doesn't support COMDATs, '" + C->getName() +
1264 "' cannot be lowered.");
1259 return nullptr;
1260
1261 if (C->getSelectionKind() != Comdat::Any)
1262 report_fatal_error("WebAssembly COMDATs only support "
1263 "SelectionKind::Any, '" + C->getName() + "' cannot be "
1264 "lowered.");
1265
1266 return C;
12651267 }
12661268
12671269 static SectionKind getWasmKindForNamedSection(StringRef Name, SectionKind K) {
12771279 MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal(
12781280 const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
12791281 StringRef Name = GO->getSection();
1280 checkWasmComdat(GO);
1282
12811283 Kind = getWasmKindForNamedSection(Name, Kind);
1282 return getContext().getWasmSection(Name, Kind);
1284
1285 StringRef Group = "";
1286 if (const Comdat *C = getWasmComdat(GO)) {
1287 Group = C->getName();
1288 }
1289
1290 return getContext().getWasmSection(Name, Kind, Group,
1291 MCContext::GenericSectionID);
12831292 }
12841293
12851294 static MCSectionWasm *selectWasmSectionForGlobal(
12861295 MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang,
12871296 const TargetMachine &TM, bool EmitUniqueSection, unsigned *NextUniqueID) {
12881297 StringRef Group = "";
1289 checkWasmComdat(GO);
1298 if (const Comdat *C = getWasmComdat(GO)) {
1299 Group = C->getName();
1300 }
12901301
12911302 bool UniqueSectionNames = TM.getUniqueSectionNames();
12921303 SmallString<128> Name = getSectionPrefixForGlobal(Kind);
137137 uint32_t ImportIndex;
138138 };
139139
140 // Information about a single item which is part of a COMDAT. For each data
141 // segment or function which is in the COMDAT, there is a corresponding
142 // WasmComdatEntry.
143 struct WasmComdatEntry {
144 unsigned Kind;
145 uint32_t Index;
146 };
147
140148 // Information about a single relocation.
141149 struct WasmRelocationEntry {
142150 uint64_t Offset; // Where is the relocation.
283291 void writeDataRelocSection();
284292 void writeLinkingMetaDataSection(
285293 ArrayRef Segments, uint32_t DataSize,
286 const SmallVector, 4> &SymbolFlags,
287 const SmallVector, 2> &InitFuncs);
294 ArrayRef> SymbolFlags,
295 ArrayRef> InitFuncs,
296 const std::map>& Comdats);
288297
289298 uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
290299 void applyRelocations(ArrayRef Relocations,
912921
913922 void WasmObjectWriter::writeLinkingMetaDataSection(
914923 ArrayRef Segments, uint32_t DataSize,
915 const SmallVector, 4> &SymbolFlags,
916 const SmallVector, 2> &InitFuncs) {
924 ArrayRef> SymbolFlags,
925 ArrayRef> InitFuncs,
926 const std::map>& Comdats) {
917927 SectionBookkeeping Section;
918928 startSection(Section, wasm::WASM_SEC_CUSTOM, "linking");
919929 SectionBookkeeping SubSection;
955965 endSection(SubSection);
956966 }
957967
968 if (Comdats.size()) {
969 startSection(SubSection, wasm::WASM_COMDAT_INFO);
970 encodeULEB128(Comdats.size(), getStream());
971 for (const auto &C : Comdats) {
972 writeString(C.first);
973 encodeULEB128(0, getStream()); // flags for future use
974 encodeULEB128(C.second.size(), getStream());
975 for (const WasmComdatEntry &Entry : C.second) {
976 encodeULEB128(Entry.Kind, getStream());
977 encodeULEB128(Entry.Index, getStream());
978 }
979 }
980 endSection(SubSection);
981 }
982
958983 endSection(Section);
959984 }
960985
9961021 SmallVector Exports;
9971022 SmallVector, 4> SymbolFlags;
9981023 SmallVector, 2> InitFuncs;
1024 std::map> Comdats;
9991025 unsigned NumFuncImports = 0;
10001026 SmallVector DataSegments;
10011027 uint32_t DataSize = 0;
11421168 Segment.Flags = 0;
11431169 DataSize += Segment.Data.size();
11441170 Section.setMemoryOffset(Segment.Offset);
1171
1172 if (const MCSymbolWasm *C = Section.getGroup()) {
1173 Comdats[C->getName()].emplace_back(
1174 WasmComdatEntry{wasm::WASM_COMDAT_DATA,
1175 static_cast(DataSegments.size()) - 1});
1176 }
11451177 }
11461178
11471179 // Handle regular defined and undefined symbols.
12151247 // address. For externals these will also be named exports.
12161248 Index = NumGlobalImports + Globals.size();
12171249 auto &DataSection = static_cast(WS.getSection());
1250 assert(DataSection.isWasmData());
12181251
12191252 WasmGlobal Global;
12201253 Global.Type = PtrType;
12381271 Export.Kind = wasm::WASM_EXTERNAL_GLOBAL;
12391272 DEBUG(dbgs() << " -> export " << Exports.size() << "\n");
12401273 Exports.push_back(Export);
1274
12411275 if (!WS.isExternal())
12421276 SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL);
1277
1278 if (WS.isFunction()) {
1279 auto &Section = static_cast(WS.getSection(false));
1280 if (const MCSymbolWasm *C = Section.getGroup())
1281 Comdats[C->getName()].emplace_back(
1282 WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index});
1283 }
12431284 }
12441285 }
12451286
13711412 writeCodeRelocSection();
13721413 writeDataRelocSection();
13731414 writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags,
1374 InitFuncs);
1415 InitFuncs, Comdats);
13751416
13761417 // TODO: Translate the .comment section to the output.
13771418 // TODO: Translate debug sections to the output.
99 #include "llvm/ADT/ArrayRef.h"
1010 #include "llvm/ADT/STLExtras.h"
1111 #include "llvm/ADT/StringRef.h"
12 #include "llvm/ADT/StringSet.h"
1213 #include "llvm/ADT/Triple.h"
1314 #include "llvm/BinaryFormat/Wasm.h"
1415 #include "llvm/MC/SubtargetFeature.h"
421422 }
422423 break;
423424 }
425 case wasm::WASM_COMDAT_INFO:
426 if (Error Err = parseLinkingSectionComdat(Ptr, SubSectionEnd))
427 return Err;
428 break;
424429 default:
425430 Ptr += Size;
426431 break;
432437 if (Ptr != End)
433438 return make_error("Linking section ended prematurely",
434439 object_error::parse_failed);
440 return Error::success();
441 }
442
443 Error WasmObjectFile::parseLinkingSectionComdat(const uint8_t *&Ptr,
444 const uint8_t *End)
445 {
446 uint32_t ComdatCount = readVaruint32(Ptr);
447 StringSet<> ComdatSet;
448 while (ComdatCount--) {
449 StringRef Name = readString(Ptr);
450 if (Name.empty() || !ComdatSet.insert(Name).second)
451 return make_error("Bad/duplicate COMDAT name " + Twine(Name),
452 object_error::parse_failed);
453 Comdats.emplace_back(Name);
454 uint32_t Flags = readVaruint32(Ptr);
455 if (Flags != 0)
456 return make_error("Unsupported COMDAT flags",
457 object_error::parse_failed);
458
459 uint32_t EntryCount = readVaruint32(Ptr);
460 while (EntryCount--) {
461 unsigned Kind = readVaruint32(Ptr);
462 unsigned Index = readVaruint32(Ptr);
463 switch (Kind) {
464 default:
465 return make_error("Invalid COMDAT entry type",
466 object_error::parse_failed);
467 case wasm::WASM_COMDAT_DATA:
468 if (Index >= DataSegments.size())
469 return make_error("COMDAT data index out of range",
470 object_error::parse_failed);
471 if (!DataSegments[Index].Data.Comdat.empty())
472 return make_error("Data segment in two COMDATs",
473 object_error::parse_failed);
474 DataSegments[Index].Data.Comdat = Name;
475 break;
476 case wasm::WASM_COMDAT_FUNCTION:
477 if (Index < NumImportedFunctions || !isValidFunctionIndex(Index))
478 return make_error("COMDAT function index out of range",
479 object_error::parse_failed);
480 Index -= NumImportedFunctions;
481 if (!Functions[Index].Comdat.empty())
482 return make_error("Function in two COMDATs",
483 object_error::parse_failed);
484 Functions[Index].Comdat = Name;
485 break;
486 }
487 }
488 }
435489 return Error::success();
436490 }
437491
6060 IO.mapOptional("SymbolInfo", Section.SymbolInfos);
6161 IO.mapOptional("SegmentInfo", Section.SegmentInfos);
6262 IO.mapOptional("InitFunctions", Section.InitFunctions);
63 IO.mapOptional("Comdats", Section.Comdats);
6364 }
6465
6566 static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) {
367368 IO.mapRequired("FunctionIndex", Init.FunctionIndex);
368369 }
369370
371 void ScalarEnumerationTraits::enumeration(
372 IO &IO, WasmYAML::ComdatKind &Kind) {
373 #define ECase(X) IO.enumCase(Kind, #X, wasm::WASM_COMDAT_##X);
374 ECase(FUNCTION);
375 ECase(DATA);
376 #undef ECase
377 }
378
379 void MappingTraits::mapping(
380 IO &IO, WasmYAML::ComdatEntry &ComdatEntry) {
381 IO.mapRequired("Kind", ComdatEntry.Kind);
382 IO.mapRequired("Index", ComdatEntry.Index);
383 }
384
385 void MappingTraits::mapping(
386 IO &IO, WasmYAML::Comdat &Comdat) {
387 IO.mapRequired("Name", Comdat.Name);
388 IO.mapRequired("Entries", Comdat.Entries);
389 }
390
370391 void MappingTraits::mapping(IO &IO,
371392 WasmYAML::SymbolInfo &Info) {
372393 IO.mapRequired("Name", Info.Name);
+0
-5
test/CodeGen/WebAssembly/comdat.ll less more
None ; RUN: not llc < %s -mtriple wasm32-unknown-unknown-wasm 2>&1 | FileCheck %s
1
2 $f = comdat any
3 @f = global i32 0, comdat
4 ; CHECK: LLVM ERROR: WebAssembly doesn't support COMDATs, 'f' cannot be lowered.
0 ; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj %s -o - | obj2yaml | FileCheck %s
1
2 ; Import a function just so we can check the index arithmetic for
3 ; WASM_COMDAT_FUNCTION entries is performed correctly
4 declare i32 @funcImport()
5 define i32 @callImport() {
6 entry:
7 %call = call i32 @funcImport()
8 ret i32 %call
9 }
10
11 ; Function in its own COMDAT
12 $basicInlineFn = comdat any
13 define linkonce_odr i32 @basicInlineFn() #1 comdat {
14 ret i32 0
15 }
16
17 ; Global, data, and function in same COMDAT
18 $sharedComdat = comdat any
19 @constantData = weak_odr constant [3 x i8] c"abc", comdat($sharedComdat)
20 define linkonce_odr i32 @sharedFn() #1 comdat($sharedComdat) {
21 ret i32 0
22 }
23
24 ; CHECK: - Type: EXPORT
25 ; CHECK-NEXT: Exports:
26 ; CHECK-NEXT: - Name: callImport
27 ; CHECK-NEXT: Kind: FUNCTION
28 ; CHECK-NEXT: Index: 1
29 ; CHECK-NEXT: - Name: basicInlineFn
30 ; CHECK-NEXT: Kind: FUNCTION
31 ; CHECK-NEXT: Index: 2
32 ; CHECK-NEXT: - Name: sharedFn
33 ; CHECK-NEXT: Kind: FUNCTION
34 ; CHECK-NEXT: Index: 3
35 ; CHECK-NEXT: - Name: constantData
36 ; CHECK-NEXT: Kind: GLOBAL
37 ; CHECK-NEXT: Index: 1
38 ; CHECK-NEXT: - Type: CODE
39 ; CHECK-NEXT: Relocations:
40 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB
41 ; CHECK-NEXT: Index: 0
42 ; CHECK-NEXT: Offset: 0x00000004
43 ; CHECK-NEXT: Functions:
44 ; CHECK-NEXT: - Index: 1
45 ; CHECK-NEXT: Locals:
46 ; CHECK-NEXT: Body: 1080808080000B
47 ; CHECK-NEXT: - Index: 2
48 ; CHECK-NEXT: Locals:
49 ; CHECK-NEXT: Body: 41000B
50 ; CHECK-NEXT: - Index: 3
51 ; CHECK-NEXT: Locals:
52 ; CHECK-NEXT: Body: 41000B
53 ; CHECK-NEXT: - Type: DATA
54 ; CHECK-NEXT: Segments:
55 ; CHECK-NEXT: - SectionOffset: 6
56 ; CHECK-NEXT: MemoryIndex: 0
57 ; CHECK-NEXT: Offset:
58 ; CHECK-NEXT: Opcode: I32_CONST
59 ; CHECK-NEXT: Value: 0
60 ; CHECK-NEXT: Content: '616263'
61 ; CHECK-NEXT: - Type: CUSTOM
62 ; CHECK-NEXT: Name: name
63 ; CHECK-NEXT: FunctionNames:
64 ; CHECK-NEXT: - Index: 0
65 ; CHECK-NEXT: Name: funcImport
66 ; CHECK-NEXT: - Index: 1
67 ; CHECK-NEXT: Name: callImport
68 ; CHECK-NEXT: - Index: 2
69 ; CHECK-NEXT: Name: basicInlineFn
70 ; CHECK-NEXT: - Index: 3
71 ; CHECK-NEXT: Name: sharedFn
72 ; CHECK-NEXT: - Type: CUSTOM
73 ; CHECK-NEXT: Name: linking
74 ; CHECK-NEXT: DataSize: 3
75 ; CHECK-NEXT: SymbolInfo:
76 ; CHECK-NEXT: - Name: basicInlineFn
77 ; CHECK-NEXT: Flags: [ BINDING_WEAK ]
78 ; CHECK-NEXT: - Name: sharedFn
79 ; CHECK-NEXT: Flags: [ BINDING_WEAK ]
80 ; CHECK-NEXT: - Name: constantData
81 ; CHECK-NEXT: Flags: [ BINDING_WEAK ]
82 ; CHECK-NEXT: SegmentInfo:
83 ; CHECK-NEXT: - Index: 0
84 ; CHECK-NEXT: Name: .rodata.constantData
85 ; CHECK-NEXT: Alignment: 1
86 ; CHECK-NEXT: Flags: [ ]
87 ; CHECK-NEXT: Comdats:
88 ; CHECK-NEXT: - Name: basicInlineFn
89 ; CHECK-NEXT: Entries:
90 ; CHECK-NEXT: - Kind: FUNCTION
91 ; CHECK-NEXT: Index: 2
92 ; CHECK-NEXT: - Name: sharedComdat
93 ; CHECK-NEXT: Entries:
94 ; CHECK-NEXT: - Kind: FUNCTION
95 ; CHECK-NEXT: Index: 3
96 ; CHECK-NEXT: - Kind: DATA
97 ; CHECK-NEXT: Index: 0
98 ; CHECK-NEXT: ...
6464 CustomSec = std::move(NameSec);
6565 } else if (WasmSec.Name == "linking") {
6666 std::unique_ptr LinkingSec = make_unique();
67 size_t Index = 0;
67 std::map ComdatIndexes;
68 for (StringRef ComdatName : Obj.comdats()) {
69 ComdatIndexes[ComdatName] = LinkingSec->Comdats.size();
70 LinkingSec->Comdats.emplace_back(WasmYAML::Comdat{ComdatName, {}});
71 }
72 for (auto &Func : Obj.functions()) {
73 if (!Func.Comdat.empty()) {
74 auto &Comdat = LinkingSec->Comdats[ComdatIndexes[Func.Comdat]];
75 Comdat.Entries.emplace_back(
76 WasmYAML::ComdatEntry{wasm::WASM_COMDAT_FUNCTION, Func.Index});
77 }
78 }
79 uint32_t SegmentIndex = 0;
6880 for (const object::WasmSegment &Segment : Obj.dataSegments()) {
6981 if (!Segment.Data.Name.empty()) {
7082 WasmYAML::SegmentInfo SegmentInfo;
7183 SegmentInfo.Name = Segment.Data.Name;
72 SegmentInfo.Index = Index;
84 SegmentInfo.Index = SegmentIndex;
7385 SegmentInfo.Alignment = Segment.Data.Alignment;
7486 SegmentInfo.Flags = Segment.Data.Flags;
7587 LinkingSec->SegmentInfos.push_back(SegmentInfo);
7688 }
77 Index++;
89 if (!Segment.Data.Comdat.empty()) {
90 auto &Comdat = LinkingSec->Comdats[ComdatIndexes[Segment.Data.Comdat]];
91 Comdat.Entries.emplace_back(
92 WasmYAML::ComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
93 }
94 SegmentIndex++;
7895 }
7996 for (const object::SymbolRef& Sym: Obj.symbols()) {
8097 const object::WasmSymbol Symbol = Obj.getWasmSymbol(Sym);
174174 }
175175 SubSection.Done();
176176 }
177
178 // COMDAT_INFO subsection
179 if (Section.Comdats.size()) {
180 encodeULEB128(wasm::WASM_COMDAT_INFO, OS);
181 encodeULEB128(Section.Comdats.size(), SubSection.GetStream());
182 for (const auto &C : Section.Comdats) {
183 writeStringRef(C.Name, SubSection.GetStream());
184 encodeULEB128(0, SubSection.GetStream()); // flags for future use
185 encodeULEB128(C.Entries.size(), SubSection.GetStream());
186 for (const WasmYAML::ComdatEntry &Entry : C.Entries) {
187 encodeULEB128(Entry.Kind, SubSection.GetStream());
188 encodeULEB128(Entry.Index, SubSection.GetStream());
189 }
190 }
191 SubSection.Done();
192 }
193
177194 return 0;
178195 }
179196