diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp --- a/llvm/lib/Linker/IRMover.cpp +++ b/llvm/lib/Linker/IRMover.cpp @@ -1516,6 +1516,15 @@ computeTypeMapping(); std::reverse(Worklist.begin(), Worklist.end()); + + // Materialize all Functions in Worklist prior to remapping otherwise + // blockaddress Constants may fail to materialize during IR moving. + for (GlobalValue *GV : Worklist) + if (auto *F = dyn_cast(GV)) + if (!F->isDeclaration()) + if (Error E = F->materialize()) + return E; + while (!Worklist.empty()) { GlobalValue *GV = Worklist.back(); Worklist.pop_back(); diff --git a/llvm/test/Linker/blockaddress.ll b/llvm/test/Linker/blockaddress.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Linker/blockaddress.ll @@ -0,0 +1,55 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-link %t.bc 2>&1 | FileCheck %s + +; CHECK-NOT: Never resolved function from blockaddress + +declare void @f(i8*) + +; Test that a blockaddress in @y referring to %label in @x can be moved when @y +; appears after @x. +define void @x() { + br label %label + +label: + call void @y() + ret void +} + +define void @y() { + call void @f(i8* blockaddress(@x, %label)) + ret void +} + +; Test that a blockaddress in @a referring to %label in @b can be moved when @a +; appears before @b. +define void @a() { + call void @f(i8* blockaddress(@b, %label)) + ret void +} + +define void @b() { + br label %label + +label: + call void @a() + ret void +} + +; Test that @c and @d can both have blockaddress Constants that refer to one +; another. + +define void @c() { + br label %label + +label: + call void @f(i8* blockaddress(@d, %label)) + ret void +} + +define void @d() { + br label %label + +label: + call void @f(i8* blockaddress(@c, %label)) + ret void +}