Index: lib/Transforms/IPO/GlobalOpt.cpp =================================================================== --- lib/Transforms/IPO/GlobalOpt.cpp +++ lib/Transforms/IPO/GlobalOpt.cpp @@ -66,6 +66,7 @@ #include "llvm/Transforms/Utils/CtorUtils.h" #include "llvm/Transforms/Utils/Evaluator.h" #include "llvm/Transforms/Utils/GlobalStatus.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" #include #include #include @@ -2925,10 +2926,16 @@ if (const Comdat *C = GV.getComdat()) if (!GV.isDiscardableIfUnused() || !GV.use_empty()) NotDiscardableComdats.insert(C); - for (Function &F : M) + for (Function &F : M) { + if (F.getName() == "__stack_chk_fail" || + F.getName() == "memcpy" || + F.getName() == "memmove") { + appendToUsed(M, &F); + } if (const Comdat *C = F.getComdat()) if (!F.isDefTriviallyDead()) NotDiscardableComdats.insert(C); + } for (GlobalAlias &GA : M.aliases()) if (const Comdat *C = GA.getComdat()) if (!GA.isDiscardableIfUnused() || !GA.use_empty()) Index: test/ThinLTO/X86/Inputs/builtin-nostrip.ll =================================================================== --- test/ThinLTO/X86/Inputs/builtin-nostrip.ll +++ test/ThinLTO/X86/Inputs/builtin-nostrip.ll @@ -0,0 +1,9 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + + +; Called via llvm.global_ctors, should be detected as live via the +; marking of llvm.global_ctors as a live root in the index. +define void @boo() { + ret void +} Index: test/ThinLTO/X86/builtin-nostrip.ll =================================================================== --- test/ThinLTO/X86/builtin-nostrip.ll +++ test/ThinLTO/X86/builtin-nostrip.ll @@ -0,0 +1,93 @@ +; RUN: opt -module-summary %s -o %t1.bc +; RUN: opt -module-summary %p/Inputs/builtin-nostrip.ll -o %t2.bc + +; RUN: llvm-lto -exported-symbol=main -thinlto-action=run %t1.bc %t2.bc +; RUN: llvm-nm %t1.bc.thinlto.o | FileCheck %s --check-prefix=CHECK-NM + +; RUN: llvm-lto2 run %t1.bc %t2.bc -o %t.out -save-temps \ +; RUN: -r %t1.bc,main,plx \ +; RUN: -r %t1.bc,bar,pl \ +; RUN: -r %t1.bc,boo,l \ +; RUN: -r %t1.bc,live_available_externally_func,l \ +; RUN: -r %t1.bc,__stack_chk_fail,pl \ +; RUN: -r %t1.bc,memmove,pl \ +; RUN: -r %t1.bc,memcpy,pl \ +; RUN: -r %t2.bc,boo,pl + +; The final binary should not contain any of the dead functions; +; make sure _stack_chk_fail is there. +; CHECK-NM-NOT: bar +; CHECK-NM: t __stack_chk_fail + +; RUN: llvm-lto2 run %t1.bc %t2.bc -o %t.out -save-temps \ +; RUN: -r %t1.bc,main,plx \ +; RUN: -r %t1.bc,bar,pl \ +; RUN: -r %t1.bc,boo,l \ +; RUN: -r %t1.bc,live_available_externally_func,l \ +; RUN: -r %t1.bc,__stack_chk_fail,pl \ +; RUN: -r %t1.bc,memmove,pl \ +; RUN: -r %t1.bc,memcpy,pl \ +; RUN: -r %t2.bc,boo,pl + +; The final binary should not contain any of the dead functions; +; make sure memmove and memcpy are there. +; CHECK-NM-NOT: bar +; CHECK-NM: t memcpy +; CHECK-NM: t memmove + +; Next test the case where Inputs/builtin-nostrip.ll does not get a module index, +; which will cause it to be handled by regular LTO in the new LTO API. +; In that case there are uses of @dead_func in the regular LTO partition +; and it shouldn't be internalized. +; RUN: opt %p/Inputs/builtin-nostrip.ll -o %t3.bc +; RUN: llvm-lto2 run %t1.bc %t3.bc -o %t4.out -save-temps \ +; RUN: -r %t1.bc,main,plx \ +; RUN: -r %t1.bc,bar,pl \ +; RUN: -r %t1.bc,boo,l \ +; RUN: -r %t1.bc,live_available_externally_func,l \ +; RUN: -r %t1.bc,__stack_chk_fail,pl \ +; RUN: -r %t1.bc,memmove,pl \ +; RUN: -r %t1.bc,memcpy,pl \ +; RUN: -r %t3.bc,boo,pl + + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + + +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] + +declare void @boo() + +define internal void @_GLOBAL__I_a() #1 section "__TEXT,__StaticInit,regular,pure_instructions" { +entry: + call void @boo() + ret void +} + +define void @bar() { + ret void +} + + +define void @__stack_chk_fail() { + ret void +} + +define void @memmove() { + ret void +} + +define void @memcpy() { + ret void +} + +define available_externally void @live_available_externally_func() { + ret void +} + +define void @main() { + call void @bar() + call void @live_available_externally_func() + ret void +}