Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -3092,7 +3092,7 @@ InlineAsm::AsmDialect(AsmDialect), CanThrow); break; } - case bitc::CST_CODE_BLOCKADDRESS:{ + case bitc::CST_CODE_BLOCKADDRESS: { if (Record.size() < 3) return error("Invalid blockaddress record"); unsigned FnTyID = Record[0]; Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -74,6 +74,7 @@ #include #include #include +#include #include #include #include @@ -3401,11 +3402,28 @@ } if (BlockAddress *BA = BlockAddress::lookup(&BB)) { - for (User *U : BA->users()) { - if (auto *I = dyn_cast(U)) { - Function *P = I->getParent()->getParent(); - if (P != &F) - BlockAddressUsers.insert(P); + std::deque BlockAddressUsersQueue; + SmallPtrSet BlockAddressUsersVisited; + + BlockAddressUsersQueue.push_back(BA); + BlockAddressUsersVisited.insert(BA); + + while (!BlockAddressUsersQueue.empty()) { + Value *V = BlockAddressUsersQueue.front(); + BlockAddressUsersQueue.pop_front(); + + for (User *U : V->users()) { + if ((isa(U) || isa(U)) && + !BlockAddressUsersVisited.contains(U)) { + BlockAddressUsersQueue.push_back(U); + BlockAddressUsersVisited.insert(U); + } + + if (auto *I = dyn_cast(U)) { + Function *P = I->getParent()->getParent(); + if (P != &F) + BlockAddressUsers.insert(P); + } } } } Index: llvm/test/Bitcode/blockaddress-aggregate-users.ll =================================================================== --- /dev/null +++ llvm/test/Bitcode/blockaddress-aggregate-users.ll @@ -0,0 +1,40 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-bcanalyzer -dump %t.bc | FileCheck %s +; RUN: llvm-dis %t.bc + +; There's a curious case where blockaddress constants may refer to functions +; outside of the function they're used in. There's a special bitcode function +; code, FUNC_CODE_BLOCKADDR_USERS, used to signify that this is the case. + +; The intent of this test is two-fold: +; 1. Ensure we produce BLOCKADDR_USERS bitcode function code on the first fn, +; @repro, since @fun and @fun2 both refer to @repro via blockaddress +; constants. +; 2. Ensure we can round-trip serializing+desearlizing such case. + +; CHECK: