Index: include/llvm/CodeGen/RuntimeLibcalls.h =================================================================== --- include/llvm/CodeGen/RuntimeLibcalls.h +++ include/llvm/CodeGen/RuntimeLibcalls.h @@ -29,7 +29,7 @@ /// enum Libcall { #define HANDLE_LIBCALL(code, name) code, - #include "RuntimeLibcalls.def" + #include "llvm/IR/RuntimeLibcalls.def" #undef HANDLE_LIBCALL }; Index: include/llvm/module.modulemap =================================================================== --- include/llvm/module.modulemap +++ include/llvm/module.modulemap @@ -26,7 +26,6 @@ // These are intended for (repeated) textual inclusion. textual header "CodeGen/CommandFlags.inc" textual header "CodeGen/DIEValue.def" - textual header "CodeGen/RuntimeLibcalls.def" } module Target { @@ -222,6 +221,7 @@ textual header "IR/Instruction.def" textual header "IR/Metadata.def" textual header "IR/Value.def" + textual header "IR/RuntimeLibcalls.def" } module LLVM_IRReader { requires cplusplus umbrella "IRReader" module * { export * } } Index: lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- lib/CodeGen/TargetLoweringBase.cpp +++ lib/CodeGen/TargetLoweringBase.cpp @@ -118,7 +118,7 @@ void TargetLoweringBase::InitLibcalls(const Triple &TT) { #define HANDLE_LIBCALL(code, name) \ setLibcallName(RTLIB::code, name); -#include "llvm/CodeGen/RuntimeLibcalls.def" +#include "llvm/IR/RuntimeLibcalls.def" #undef HANDLE_LIBCALL // Initialize calling conventions to their default. for (int LC = 0; LC < RTLIB::UNKNOWN_LIBCALL; ++LC) Index: lib/Object/IRSymtab.cpp =================================================================== --- lib/Object/IRSymtab.cpp +++ lib/Object/IRSymtab.cpp @@ -42,6 +42,12 @@ using namespace llvm; using namespace irsymtab; +static const char *LibcallRoutineNames[] = { +#define HANDLE_LIBCALL(code, name) name, +#include "llvm/IR/RuntimeLibcalls.def" +#undef HANDLE_LIBCALL +}; + namespace { const char *getExpectedProducerName() { @@ -226,7 +232,17 @@ setStr(Sym.IRName, GV->getName()); - if (Used.count(GV)) + bool isBuiltinFunc = false; + + // FIXME: This fixes the issue with builtin functions being + // internalized (and later dead-code-eliminated) in the new LTO + // implementation. However this does not fix the old LTO implementaion, + // which still internalizes the function definitions. + for (const char *libcall_name : LibcallRoutineNames) + if (GV->getName() == libcall_name) + isBuiltinFunc = true; + + if (Used.count(GV) || isBuiltinFunc) Sym.Flags |= 1 << storage::Symbol::FB_used; if (GV->isThreadLocal()) Sym.Flags |= 1 << storage::Symbol::FB_tls; 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,101 @@ +; REQUIRES: x86-registered-target +; Compile with thinlto indices, to enable thinlto. +; RUN: opt -module-summary %s -o %t1.bc +; RUN: opt -module-summary %p/Inputs/builtin-nostrip.ll -o %t2.bc + +; Test old lto interface with thinlto (currently known to be broken, so +; the FileCheck line is commented out). +; 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 + +; Test new lto interface with thinlto. +; 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 +; RUN: llvm-nm %t.out.1 | FileCheck %s --check-prefix=CHECK-NM +; + +; Re-compile, this time without the thinlto indices. +; RUN: opt %s -o %t4.bc +; RUN: opt %p/Inputs/builtin-nostrip.ll -o %t3.bc + +; Test the new lto interface without thinlto. +; RUN: llvm-lto2 run %t4.bc %t3.bc -o %t5.out -save-temps \ +; RUN: -r %t4.bc,main,plx \ +; RUN: -r %t4.bc,bar,pl \ +; RUN: -r %t4.bc,boo,l \ +; RUN: -r %t4.bc,live_available_externally_func,l \ +; RUN: -r %t4.bc,__stack_chk_fail,pl \ +; RUN: -r %t4.bc,memmove,pl \ +; RUN: -r %t4.bc,memcpy,pl \ +; RUN: -r %t3.bc,boo,pl +; RUN: llvm-nm %t5.out.0 | FileCheck %s --check-prefix=CHECK-NM + +; Test the old lto interface without thinlto. For now we need to +; use a different nm check, because currently the old lto interface +; internalizes these symbols. Once the old lto interface gets +; fixed, we should be able to use the same CHECK-NM tests as the +; other FileChecks. +; RUN: llvm-lto -exported-symbol=main %t3.bc %t4.bc -o %t6 +; RUN: llvm-nm %t6 | FileCheck %s --check-prefix=CHECK-NM2 + +; The final binary should not contain any of the dead functions; +; make sure memmove and memcpy are there. +; CHECK-NM-NOT: bar +; CHECK-NM-DAG: T __stack_chk_fail +; CHECK-NM-DAG: T memcpy +; CHECK-NM-DAG: T memmove +; CHECK-NM-NOT: bar + +; Test case for old lto without thinlto. Hopefully these can be +; eliminated once the old lto interface is fixed. +; CHECK-NM2-DAG: t memcpy +; CHECK-NM2-DAG: t memmove +; CHECK-NM2-DAG: t __stack_chk_fail + +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 +}