Index: test/wasm/call-indirect.ll =================================================================== --- test/wasm/call-indirect.ll +++ test/wasm/call-indirect.ll @@ -43,21 +43,21 @@ ; CHECK-NEXT: ReturnType: I64 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ReturnType: I64 ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I64 ; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: -; CHECK-NEXT: - I32 ; CHECK-NEXT: - Index: 4 -; CHECK-NEXT: ReturnType: I64 +; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: -; CHECK-NEXT: - I64 +; CHECK-NEXT: - I32 ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1, 2, 2, 3, 1 ] +; CHECK-NEXT: FunctionTypes: [ 0, 3, 1, 1, 4, 3 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -120,16 +120,16 @@ ; CHECK-NEXT: Locals: ; CHECK-NEXT: - Type: I32 ; CHECK-NEXT: Count: 1 -; CHECK-NEXT: Body: 4100280284888080002100410028028088808000118080808000001A2000118280808000001A0B +; CHECK-NEXT: Body: 4100280284888080002100410028028088808000118080808000001A2000118180808000001A0B ; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41020B ; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 410028028888808000118280808000001A41000B +; CHECK-NEXT: Body: 410028028888808000118180808000001A41000B ; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 42012000118480808000001A0B +; CHECK-NEXT: Body: 42012000118280808000001A0B ; CHECK-NEXT: - Index: 5 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 0B Index: test/wasm/gc-sections.ll =================================================================== --- test/wasm/gc-sections.ll +++ test/wasm/gc-sections.ll @@ -7,12 +7,12 @@ target triple = "wasm32-unknown-unknown-wasm" -@unused_data = hidden global i32 1, align 4 +@unused_data = hidden global i64 1, align 4 @used_data = hidden global i32 2, align 4 -define hidden i32 @unused_function() { - %1 = load i32, i32* @unused_data, align 4 - ret i32 %1 +define hidden i64 @unused_function() { + %1 = load i64, i64* @unused_data, align 4 + ret i64 %1 } define hidden i32 @used_function() { @@ -27,6 +27,17 @@ } ; RUN: obj2yaml %t1.wasm | FileCheck %s + +; CHECK: - Type: TYPE +; CHECK-NEXT: Signatures: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Type: FUNCTION + ; CHECK: - Type: DATA ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 7 @@ -51,6 +62,20 @@ ; RUN: lld -flavor wasm -print-gc-sections --no-gc-sections -o %t1.no-gc.wasm %t.o ; RUN: obj2yaml %t1.no-gc.wasm | FileCheck %s -check-prefix=NO-GC + +; NO-GC: - Type: TYPE +; NO-GC-NEXT: Signatures: +; NO-GC-NEXT: - Index: 0 +; NO-GC-NEXT: ReturnType: I64 +; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: - Index: 1 +; NO-GC-NEXT: ReturnType: I32 +; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: - Index: 2 +; NO-GC-NEXT: ReturnType: NORESULT +; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: - Type: FUNCTION + ; NO-GC: - Type: DATA ; NO-GC-NEXT: Segments: ; NO-GC-NEXT: - SectionOffset: 7 @@ -58,10 +83,10 @@ ; NO-GC-NEXT: Offset: ; NO-GC-NEXT: Opcode: I32_CONST ; NO-GC-NEXT: Value: 1024 -; NO-GC-NEXT: Content: '0100000002000000' +; NO-GC-NEXT: Content: '010000000000000002000000' ; NO-GC-NEXT: - Type: CUSTOM ; NO-GC-NEXT: Name: linking -; NO-GC-NEXT: DataSize: 8 +; NO-GC-NEXT: DataSize: 12 ; NO-GC-NEXT: - Type: CUSTOM ; NO-GC-NEXT: Name: name ; NO-GC-NEXT: FunctionNames: Index: test/wasm/relocatable.ll =================================================================== --- test/wasm/relocatable.ll +++ test/wasm/relocatable.ll @@ -38,34 +38,34 @@ ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I32 ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: -; CHECK-NEXT: - I32 ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: IMPORT ; CHECK-NEXT: Imports: ; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: puts ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: SigIndex: 1 +; CHECK-NEXT: SigIndex: 0 ; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: foo_import ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: SigIndex: 2 +; CHECK-NEXT: SigIndex: 1 ; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: bar_import ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: SigIndex: 2 +; CHECK-NEXT: SigIndex: 1 ; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: data_import ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: GlobalType: I32 ; CHECK-NEXT: GlobalMutable: false ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 2, 2 ] +; CHECK-NEXT: FunctionTypes: [ 2, 1, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC Index: wasm/InputChunks.h =================================================================== --- wasm/InputChunks.h +++ wasm/InputChunks.h @@ -59,14 +59,14 @@ bool Discarded = false; std::vector OutRelocations; - const ObjFile *File; + ObjFile *File; // The garbage collector sets sections' Live bits. // If GC is disabled, all sections are considered live by default. unsigned Live : 1; protected: - InputChunk(const ObjFile *F, Kind K) + InputChunk(ObjFile *F, Kind K) : File(F), Live(!Config->GcSections), SectionKind(K) {} virtual ~InputChunk() = default; void calcRelocations(); @@ -88,7 +88,7 @@ // each global variable. class InputSegment : public InputChunk { public: - InputSegment(const WasmSegment &Seg, const ObjFile *F) + InputSegment(const WasmSegment &Seg, ObjFile *F) : InputChunk(F, InputChunk::DataSegment), Segment(Seg) {} static bool classof(const InputChunk *C) { return C->kind() == DataSegment; } @@ -127,7 +127,7 @@ class InputFunction : public InputChunk { public: InputFunction(const WasmSignature &S, const WasmFunction *Func, - const ObjFile *F) + ObjFile *F) : InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {} static bool classof(const InputChunk *C) { Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -101,6 +101,7 @@ const WasmSection *DataSection = nullptr; std::vector TypeMap; + std::vector TypeIsUsed; std::vector Segments; std::vector Functions; Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -63,6 +63,7 @@ } uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const { + assert(TypeIsUsed[Original]); return TypeMap[Original]; } @@ -149,6 +150,9 @@ DataSection = &Section; } + TypeMap.resize(getWasmObj()->types().size()); + TypeIsUsed.resize(getWasmObj()->types().size(), false); + initializeSymbols(); } Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -689,15 +689,23 @@ } void Writer::calculateTypes() { + // The output type section is the union of the following sets: + // 1. Any signature used in the TYPE relocation + // 2. The signatures of all imported functions + // 3. The signatures of all defined functions + for (ObjFile *File : Symtab->ObjectFiles) { - File->TypeMap.reserve(File->getWasmObj()->types().size()); - for (const WasmSignature &Sig : File->getWasmObj()->types()) - File->TypeMap.push_back(registerType(Sig)); + ArrayRef Types = File->getWasmObj()->types(); + for (uint32_t I = 0; I < Types.size(); I++) + if (File->TypeIsUsed[I]) + File->TypeMap[I] = registerType(Types[I]); } - for (Symbol *Sym : Symtab->getSymbols()) - if (Sym->isFunction()) - registerType(Sym->getFunctionType()); + for (const Symbol *Sym : ImportedFunctions) + registerType(Sym->getFunctionType()); + + for (const InputFunction *F : DefinedFunctions) + registerType(F->Signature); } void Writer::assignIndexes() { @@ -746,25 +754,30 @@ } for (ObjFile *File : Symtab->ObjectFiles) { - DEBUG(dbgs() << "Table Indexes: " << File->getName() << "\n"); - auto HandleTableRelocs = [&](InputChunk *Chunk) { + DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n"); + auto HandleRelocs = [&](InputChunk *Chunk) { if (Chunk->Discarded) return; + ArrayRef Types = File->getWasmObj()->types(); for (const WasmRelocation& Reloc : Chunk->getRelocations()) { - if (Reloc.Type != R_WEBASSEMBLY_TABLE_INDEX_I32 && - Reloc.Type != R_WEBASSEMBLY_TABLE_INDEX_SLEB) - continue; - Symbol *Sym = File->getFunctionSymbol(Reloc.Index); - if (Sym->hasTableIndex() || !Sym->hasOutputIndex()) - continue; - Sym->setTableIndex(TableIndex++); - IndirectFunctions.emplace_back(Sym); + if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 || + Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB) { + Symbol *Sym = File->getFunctionSymbol(Reloc.Index); + if (Sym->hasTableIndex() || !Sym->hasOutputIndex()) + continue; + Sym->setTableIndex(TableIndex++); + IndirectFunctions.emplace_back(Sym); + } else if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) { + Chunk->File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]); + Chunk->File->TypeIsUsed[Reloc.Index] = true; + } } }; + for (InputFunction* Function : File->Functions) - HandleTableRelocs(Function); + HandleRelocs(Function); for (InputSegment* Segment : File->Segments) - HandleTableRelocs(Segment); + HandleRelocs(Segment); } } @@ -858,8 +871,6 @@ } void Writer::run() { - log("-- calculateTypes"); - calculateTypes(); log("-- calculateImports"); calculateImports(); log("-- assignIndexes"); @@ -870,6 +881,8 @@ calculateInitFunctions(); if (!Config->Relocatable) createCtorFunction(); + log("-- calculateTypes"); + calculateTypes(); if (errorHandler().Verbose) { log("Defined Functions: " + Twine(DefinedFunctions.size()));