Index: test/wasm/Inputs/globals.yaml =================================================================== --- /dev/null +++ test/wasm/Inputs/globals.yaml @@ -0,0 +1,53 @@ +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ReturnType: I64 + ParamTypes: + - Type: FUNCTION + FunctionTypes: [ 0 ] + - Type: GLOBAL + Globals: + - Index: 0 + Type: I64 + Mutable: true + InitExpr: + Opcode: I64_CONST + Value: 123 + - Index: 1 + Type: I64 + Mutable: true + InitExpr: + Opcode: I64_CONST + Value: 456 + - Type: CODE + Functions: + - Index: 0 + Locals: + Body: 2381808080000B + Relocations: + - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB + Index: 1 + Offset: 0x00000004 + - Type: CUSTOM + Name: linking + SymbolTable: + - Index: 0 + Kind: GLOBAL + Name: unused_global + Flags: [ VISIBILITY_HIDDEN ] + Global: 0 + - Index: 1 + Kind: GLOBAL + Name: used_global + Flags: [ VISIBILITY_HIDDEN ] + Global: 1 + - Index: 2 + Kind: FUNCTION + Name: use_global + Flags: [ VISIBILITY_HIDDEN ] + Function: 0 +... Index: test/wasm/gc-sections.ll =================================================================== --- test/wasm/gc-sections.ll +++ test/wasm/gc-sections.ll @@ -1,16 +1,20 @@ ; RUN: llc -filetype=obj %s -o %t.o -; RUN: wasm-ld -print-gc-sections -o %t1.wasm %t.o | FileCheck %s -check-prefix=PRINT-GC +; RUN: yaml2obj %S/Inputs/globals.yaml -o %t_globals.o +; RUN: wasm-ld -print-gc-sections -o %t1.wasm %t.o %t_globals.o | \ +; RUN: FileCheck %s -check-prefix=PRINT-GC ; PRINT-GC: removing unused section {{.*}}:(unused_function) ; PRINT-GC-NOT: removing unused section {{.*}}:(used_function) ; PRINT-GC: removing unused section {{.*}}:(.data.unused_data) ; PRINT-GC-NOT: removing unused section {{.*}}:(.data.used_data) +; PRINT-GC: removing unused section {{.*}}:(unused_global) +; PRINT-GC-NOT: removing unused section {{.*}}:(used_global) target triple = "wasm32-unknown-unknown-wasm" @unused_data = hidden global i64 1, align 4 @used_data = hidden global i32 2, align 4 -define hidden i64 @unused_function() { +define hidden i64 @unused_function(i64 %arg) { %1 = load i64, i64* @unused_data, align 4 ret i64 %1 } @@ -20,24 +24,45 @@ ret i32 %1 } +declare i64 @use_global() + define hidden void @_start() { entry: call i32 @used_function() + call i64 @use_global() ret void } ; RUN: obj2yaml %t1.wasm | FileCheck %s ; CHECK: - Type: TYPE -; CHECK-NEXT: Signatures: +; CHECK-NEXT: Signatures: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: ReturnType: NORESULT -; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: ReturnType: I32 -; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: ReturnType: I64 +; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION +; CHECK: - Type: GLOBAL +; CHECK-NEXT: Globals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I64 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I64_CONST +; CHECK-NEXT: Value: 456 + ; CHECK: - Type: DATA ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 7 @@ -55,24 +80,52 @@ ; CHECK-NEXT: Name: used_function ; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: use_global ; CHECK-NEXT: ... -; RUN: wasm-ld -print-gc-sections --no-gc-sections -o %t1.no-gc.wasm %t.o +; RUN: wasm-ld -print-gc-sections --no-gc-sections -o %t1.no-gc.wasm \ +; RUN: %t.o %t_globals.o ; RUN: obj2yaml %t1.no-gc.wasm | FileCheck %s -check-prefix=NO-GC ; NO-GC: - Type: TYPE -; NO-GC-NEXT: Signatures: +; NO-GC-NEXT: Signatures: ; NO-GC-NEXT: - Index: 0 ; NO-GC-NEXT: ReturnType: NORESULT ; NO-GC-NEXT: ParamTypes: ; NO-GC-NEXT: - Index: 1 ; NO-GC-NEXT: ReturnType: I64 -; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: - I64 ; NO-GC-NEXT: - Index: 2 ; NO-GC-NEXT: ReturnType: I32 -; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: - Index: 3 +; NO-GC-NEXT: ReturnType: I64 +; NO-GC-NEXT: ParamTypes: ; NO-GC-NEXT: - Type: FUNCTION +; NO-GC: - Type: GLOBAL +; NO-GC-NEXT: Globals: +; NO-GC-NEXT: - Index: 0 +; NO-GC-NEXT: Type: I32 +; NO-GC-NEXT: Mutable: true +; NO-GC-NEXT: InitExpr: +; NO-GC-NEXT: Opcode: I32_CONST +; NO-GC-NEXT: Value: 66576 +; NO-GC-NEXT: - Index: 1 +; NO-GC-NEXT: Type: I64 +; NO-GC-NEXT: Mutable: true +; NO-GC-NEXT: InitExpr: +; NO-GC-NEXT: Opcode: I64_CONST +; NO-GC-NEXT: Value: 123 +; NO-GC-NEXT: - Index: 2 +; NO-GC-NEXT: Type: I64 +; NO-GC-NEXT: Mutable: true +; NO-GC-NEXT: InitExpr: +; NO-GC-NEXT: Opcode: I64_CONST +; NO-GC-NEXT: Value: 456 + ; NO-GC: - Type: DATA ; NO-GC-NEXT: Segments: ; NO-GC-NEXT: - SectionOffset: 7 @@ -92,6 +145,8 @@ ; NO-GC-NEXT: Name: used_function ; NO-GC-NEXT: - Index: 3 ; NO-GC-NEXT: Name: _start +; NO-GC-NEXT: - Index: 4 +; NO-GC-NEXT: Name: use_global ; NO-GC-NEXT: ... ; RUN: not wasm-ld --gc-sections --relocatable -o %t1.no-gc.wasm %t.o 2>&1 | FileCheck %s -check-prefix=CHECK-ERROR Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -334,7 +334,8 @@ StackPointerGlobal.Type = {WASM_TYPE_I32, true}; StackPointerGlobal.InitExpr.Value.Int32 = 0; StackPointerGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; - InputGlobal *StackPointer = make(StackPointerGlobal); + StackPointerGlobal.Name = "__stack_pointer"; + InputGlobal *StackPointer = make(StackPointerGlobal, nullptr); StackPointer->Live = true; static WasmSignature NullSignature = {{}, WASM_TYPE_NORESULT}; Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -179,7 +179,7 @@ // Populate `Globals`. for (const WasmGlobal &G : WasmObj->globals()) - Globals.emplace_back(make(G)); + Globals.emplace_back(make(G, this)); // Populate `Symbols` based on the WasmSymbols in the object. Symbols.reserve(WasmObj->getNumberOfSymbols()); Index: wasm/InputGlobal.h =================================================================== --- wasm/InputGlobal.h +++ wasm/InputGlobal.h @@ -26,8 +26,10 @@ // combined to form the final GLOBALS section. class InputGlobal { public: - InputGlobal(const WasmGlobal &G) : Global(G) {} + InputGlobal(const WasmGlobal &G, ObjFile *F) + : File(F), Global(G), Live(!Config->GcSections) {} + StringRef getName() const { return Global.Name; } const WasmGlobalType &getType() const { return Global.Type; } uint32_t getGlobalIndex() const { return GlobalIndex.getValue(); } @@ -37,16 +39,21 @@ GlobalIndex = Index; } - bool Live = false; - + ObjFile *File; WasmGlobal Global; + bool Live = false; + protected: llvm::Optional GlobalIndex; }; } // namespace wasm +inline std::string toString(const wasm::InputGlobal *G) { + return (toString(G->File) + ":(" + G->getName() + ")").str(); +} + } // namespace lld #endif // LLD_WASM_INPUT_GLOBAL_H Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -786,13 +786,12 @@ // Mark target type as live File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]); File->TypeIsUsed[Reloc.Index] = true; - } else if (Reloc.Type == R_WEBASSEMBLY_GLOBAL_INDEX_LEB) { + } else if (Reloc.Type == R_WEBASSEMBLY_GLOBAL_INDEX_LEB && + Config->GcSections) { // Mark target global as live GlobalSymbol *Sym = File->getGlobalSymbol(Reloc.Index); - if (auto *G = dyn_cast(Sym)) { - DEBUG(dbgs() << "marking global live: " << Sym->getName() << "\n"); + if (auto *G = dyn_cast(Sym)) G->Global->Live = true; - } } } }; @@ -805,6 +804,17 @@ HandleRelocs(Chunk); } + if (Config->PrintGcSections) { + for (const ObjFile *Obj : Symtab->ObjectFiles) { + for (InputGlobal *G : Obj->Globals) + if (!G->Live) + message("removing unused section " + toString(G)); + } + for (InputGlobal *G : Symtab->SyntheticGlobals) + if (!G->Live) + message("removing unused section " + toString(G)); + } + uint32_t GlobalIndex = NumImportedGlobals + InputGlobals.size(); auto AddDefinedGlobal = [&](InputGlobal *Global) { if (Global->Live) {