Index: test/tools/gold/X86/Inputs/thinlto_linkonceresolution.ll =================================================================== --- /dev/null +++ test/tools/gold/X86/Inputs/thinlto_linkonceresolution.ll @@ -0,0 +1,4 @@ +target triple = "x86_64-unknown-linux-gnu" +define linkonce_odr hidden void @f() { + ret void +} Index: test/tools/gold/X86/thinlto_linkonceresolution.ll =================================================================== --- /dev/null +++ test/tools/gold/X86/thinlto_linkonceresolution.ll @@ -0,0 +1,25 @@ +; RUN: llvm-as -function-summary %s -o %t.o +; RUN: llvm-as -function-summary %p/Inputs/thinlto_linkonceresolution.ll -o %t2.o + +; Ensure the plugin ensures that for ThinLTO the prevailing copy of a +; linkonce symbol is changed to weak to ensure it is not eliminated. +; Note that gold picks the first copy of f() as the prevailing one, +; so listing %t2.o first is sufficient to ensure that this copy is +; preempted. Also, set the import-instr-limit to 0 to prevent f() from +; being imported from %t2.o which hides the problem. +; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \ +; RUN: --plugin-opt=thinlto \ +; RUN: --plugin-opt=-import-instr-limit=0 \ +; RUN: -o %t3.o %t2.o %t.o +; RUN: llvm-nm %t3.o | FileCheck %s + +; CHECK-NOT: U f + +target triple = "x86_64-unknown-linux-gnu" +define i32 @g() { + call void @f() + ret i32 0 +} +define linkonce_odr hidden void @f() { + ret void +} Index: tools/gold/gold-plugin.cpp =================================================================== --- tools/gold/gold-plugin.cpp +++ tools/gold/gold-plugin.cpp @@ -661,6 +661,22 @@ return Obj.takeIndex(); } +/// Force the prevailing copy of a linkonce to be kept by converting it to weak. +/// This is necessary when there are either non-IR uses or we are doing +/// ThinLTO compilation. +static void convertLinkOnceToWeak(GlobalValue *GV) { + switch (GV->getLinkage()) { + default: + break; + case GlobalValue::LinkOnceAnyLinkage: + GV->setLinkage(GlobalValue::WeakAnyLinkage); + break; + case GlobalValue::LinkOnceODRLinkage: + GV->setLinkage(GlobalValue::WeakODRLinkage); + break; + } +} + static std::unique_ptr getModuleForFile(LLVMContext &Context, claimed_file &F, const void *View, ld_plugin_input_file &Info, raw_fd_ostream *ApiFile, @@ -754,6 +770,15 @@ case LDPR_PREVAILING_DEF_IRONLY: { Keep.push_back(GV); + if (options::thinlto) { + // For ThinLTO the IR files are compiled through the backend, + // independently, so we need to ensure that the prevailing copy will be + // emitted into the object file by making it weak. + convertLinkOnceToWeak(GV); + // Skip the below handling for internalization, which isn't + // performed in ThinLTO mode currently anyway. + break; + } // The IR linker has to be able to map this value to a declaration, // so we can only internalize after linking. if (!Used.count(GV)) @@ -764,25 +789,25 @@ case LDPR_PREVAILING_DEF: Keep.push_back(GV); // There is a non IR use, so we have to force optimizations to keep this. - switch (GV->getLinkage()) { - default: - break; - case GlobalValue::LinkOnceAnyLinkage: - GV->setLinkage(GlobalValue::WeakAnyLinkage); - break; - case GlobalValue::LinkOnceODRLinkage: - GV->setLinkage(GlobalValue::WeakODRLinkage); - break; - } + convertLinkOnceToWeak(GV); break; case LDPR_PREVAILING_DEF_IRONLY_EXP: { + Keep.push_back(GV); + if (options::thinlto) { + // For ThinLTO the IR files are compiled through the backend, + // independently, so we need to ensure that the prevailing copy will be + // emitted into the object file by making it weak. + convertLinkOnceToWeak(GV); + // Skip the below handling for internalization, which isn't + // performed in ThinLTO mode currently anyway. + break; + } // We can only check for address uses after we merge the modules. The // reason is that this GV might have a copy in another module // and in that module the address might be significant, but that // copy will be LDPR_PREEMPTED_IR. Maybe.insert(GV->getName()); - Keep.push_back(GV); break; } }