Index: include/llvm/LTO/LTO.h =================================================================== --- include/llvm/LTO/LTO.h +++ include/llvm/LTO/LTO.h @@ -424,6 +424,9 @@ /// This global is either used by more than one partition or has an /// external reference, and therefore cannot be internalized. External = -2u, + + /// This global is undefined. + Undefined = -3u, }; }; @@ -451,8 +454,8 @@ /// each global symbol based on its internal resolution of that symbol. struct SymbolResolution { SymbolResolution() - : Prevailing(0), FinalDefinitionInLinkageUnit(0), VisibleToRegularObj(0) { - } + : Prevailing(0), FinalDefinitionInLinkageUnit(0), VisibleToRegularObj(0), + Undefined(0) {} /// The linker has chosen this definition of the symbol. unsigned Prevailing : 1; @@ -462,6 +465,9 @@ /// The definition of this symbol is visible outside of the LTO unit. unsigned VisibleToRegularObj : 1; + + /// This symbol has no definition. + unsigned Undefined : 1; }; } // namespace lto Index: lib/LTO/LTO.cpp =================================================================== --- lib/LTO/LTO.cpp +++ lib/LTO/LTO.cpp @@ -246,10 +246,12 @@ auto &GlobalRes = GlobalResolutions[Sym.getName()]; if (GV) { GlobalRes.UnnamedAddr &= GV->hasGlobalUnnamedAddr(); - if (Res.Prevailing) + if (Res.Prevailing || Res.Undefined) GlobalRes.IRName = GV->getName(); } - if (Res.VisibleToRegularObj || (GV && Used.count(GV)) || + if (Res.Undefined && GV && GV->isDeclarationForLinker()) + GlobalRes.Partition = GlobalResolution::Undefined; + else if (Res.VisibleToRegularObj || (GV && Used.count(GV)) || (GlobalRes.Partition != GlobalResolution::Unknown && GlobalRes.Partition != Partition)) GlobalRes.Partition = GlobalResolution::External; @@ -273,6 +275,8 @@ OS << 'l'; if (Res.VisibleToRegularObj) OS << 'x'; + if (Res.Undefined) + OS << 'u'; OS << '\n'; } assert(ResI == Res.end()); @@ -461,11 +465,20 @@ if (R.second.IRName.empty()) continue; if (R.second.Partition != 0 && - R.second.Partition != GlobalResolution::External) + R.second.Partition != GlobalResolution::External && + R.second.Partition != GlobalResolution::Undefined) continue; GlobalValue *GV = RegularLTO.CombinedModule->getNamedValue(R.second.IRName); + + if (GV && GV->hasExternalWeakLinkage() && + R.second.Partition == GlobalResolution::Undefined) { + GV->replaceAllUsesWith(Constant::getNullValue(GV->getType())); + GV->eraseFromParent(); + continue; + } + // Ignore symbols defined in other partitions. if (!GV || GV->hasLocalLinkage()) continue; Index: test/LTO/Resolution/X86/weak.ll =================================================================== --- /dev/null +++ test/LTO/Resolution/X86/weak.ll @@ -0,0 +1,22 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-lto2 %t.bc -r %t.bc,main,plx -r %t.bc,_Z1fv,u -o %t.o -save-temps +; RUN: llvm-dis %t.o.0.2.internalize.bc -o - | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i32 @main() { +entry: +; weak symbol _Z1fv resolved as undefined, replaced with nullptr. +; CHECK-NOT: _Z1fv + br i1 icmp ne (void ()* @_Z1fv, void ()* null), label %if.then, label %if.end + +if.then: ; preds = %entry + ret i32 1 + unreachable + +if.end: ; preds = %entry + ret i32 0 +} + +declare extern_weak void @_Z1fv() Index: test/tools/gold/X86/comdat.ll =================================================================== --- test/tools/gold/X86/comdat.ll +++ test/tools/gold/X86/comdat.ll @@ -39,7 +39,7 @@ ; RES: 1.o,a15,px{{$}} ; RES: 2.o,f1,l{{$}} -; RES: 2.o,will_be_undefined,{{$}} +; RES: 2.o,will_be_undefined,u{{$}} ; RES: 2.o,v1,{{$}} ; RES: 2.o,r21,px{{$}} ; RES: 2.o,r22,px{{$}} Index: test/tools/gold/X86/emit-llvm.ll =================================================================== --- test/tools/gold/X86/emit-llvm.ll +++ test/tools/gold/X86/emit-llvm.ll @@ -43,7 +43,7 @@ @g6 = linkonce_odr unnamed_addr global i32 32 @g7 = extern_weak global i32 -; CHECK-DAG: @g7 = extern_weak global i32 +; CHECK-NOT: @g7 @g8 = external global i32 @@ -110,7 +110,7 @@ ; RES: .o,g4,px{{$}} ; RES: .o,g5,px{{$}} ; RES: .o,g6,p{{$}} -; RES: .o,g7,{{$}} -; RES: .o,g8,{{$}} +; RES: .o,g7,u{{$}} +; RES: .o,g8,u{{$}} ; RES: .o,g9,px{{$}} ; RES: .o,g10,px{{$}} Index: test/tools/gold/X86/weak_undefined.ll =================================================================== --- /dev/null +++ test/tools/gold/X86/weak_undefined.ll @@ -0,0 +1,24 @@ +; RUN: llvm-as %s -o %t.o +; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \ +; RUN: --plugin-opt=emit-llvm \ +; RUN: -shared %t.o -o %t2.o +; RUN: llvm-dis %t2.o -o - | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i32 @main() { +entry: +; weak symbol _Z1fv resolved as undefined, replaced with nullptr. +; CHECK-NOT: _Z1fv + br i1 icmp ne (void ()* @_Z1fv, void ()* null), label %if.then, label %if.end + +if.then: ; preds = %entry + ret i32 1 + unreachable + +if.end: ; preds = %entry + ret i32 0 +} + +declare extern_weak void @_Z1fv() Index: tools/gold/gold-plugin.cpp =================================================================== --- tools/gold/gold-plugin.cpp +++ tools/gold/gold-plugin.cpp @@ -588,12 +588,15 @@ case LDPR_UNKNOWN: llvm_unreachable("Unexpected resolution"); + case LDPR_UNDEF: + R.Undefined = true; + break; + case LDPR_RESOLVED_IR: case LDPR_RESOLVED_EXEC: case LDPR_RESOLVED_DYN: case LDPR_PREEMPTED_IR: case LDPR_PREEMPTED_REG: - case LDPR_UNDEF: break; case LDPR_PREVAILING_DEF_IRONLY: Index: tools/llvm-lto2/llvm-lto2.cpp =================================================================== --- tools/llvm-lto2/llvm-lto2.cpp +++ tools/llvm-lto2/llvm-lto2.cpp @@ -122,6 +122,8 @@ Res.FinalDefinitionInLinkageUnit = true; else if (C == 'x') Res.VisibleToRegularObj = true; + else if (C == 'u') + Res.Undefined = true; else llvm::errs() << "invalid character " << C << " in resolution: " << R << '\n';