Index: lib/Transforms/IPO/GlobalDCE.cpp =================================================================== --- lib/Transforms/IPO/GlobalDCE.cpp +++ lib/Transforms/IPO/GlobalDCE.cpp @@ -46,6 +46,7 @@ private: SmallPtrSet AliveGlobals; SmallPtrSet SeenConstants; + SmallPtrSet SeenBlockAddressFnUsers; /// GlobalIsNeeded - mark the specific global value as needed, and /// recursively mark anything that it uses as also needed. @@ -192,6 +193,11 @@ Changed = true; } + // Some global initializers elements may leave dead references to functions, + // (e.g. BlockAddresses), clean them up. + for (auto F : SeenBlockAddressFnUsers) + F->removeDeadConstantUsers(); + // Make sure that all memory is released AliveGlobals.clear(); SeenConstants.clear(); @@ -231,6 +237,12 @@ GlobalIsNeeded(GV); else if (Constant *C = dyn_cast(*U)) MarkUsedGlobalsAsNeeded(C); + + // Keep track of functions used by BlockAddresses; global initializers + // may leave dangling BlockAddresses referring to those. + for (auto UB = G->user_begin(), UE = G->user_end(); UB != UE; ++UB) + if (isa(*UB)) + SeenBlockAddressFnUsers.insert(G); } } Index: test/Transforms/GlobalDCE/deadblockaddr.ll =================================================================== --- /dev/null +++ test/Transforms/GlobalDCE/deadblockaddr.ll @@ -0,0 +1,16 @@ +; RUN: opt -globaldce -simplifycfg -S < %s | FileCheck %s + +; Tests whether globaldce does the right cleanup while removing @bar +; so that a dead BlockAddress reference to foo won't prevent other passes +; to work properly, e.g. simplifycfg +@bar = internal unnamed_addr constant i8* blockaddress(@foo, %L1) + +; CHECK-LABEL: foo +; CHECK-NOT: br label %L1 +; CHECK: ret void +define void @foo() { +entry: + br label %L1 +L1: + ret void +}