diff --git a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp index 623a8b711ed895..ac53ff33e83624 100644 --- a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp +++ b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp @@ -104,6 +104,21 @@ static bool mergeEmptyReturnBlocks(Function &F) { continue; } + // Skip merging if this would result in a CallBr instruction with a + // duplicate destination. FIXME: See note in CodeGenPrepare.cpp. + bool SkipCallBr = false; + for (pred_iterator PI = pred_begin(&BB), E = pred_end(&BB); + PI != E && !SkipCallBr; ++PI) { + if (auto *CBI = dyn_cast((*PI)->getTerminator())) + for (unsigned i = 0, e = CBI->getNumSuccessors(); i != e; ++i) + if (RetBlock == CBI->getSuccessor(i)) { + SkipCallBr = true; + break; + } + } + if (SkipCallBr) + continue; + // Otherwise, we found a duplicate return block. Merge the two. Changed = true; diff --git a/llvm/test/Transforms/SimplifyCFG/callbr-destinations.ll b/llvm/test/Transforms/SimplifyCFG/callbr-destinations.ll new file mode 100644 index 00000000000000..18210e5e0b0603 --- /dev/null +++ b/llvm/test/Transforms/SimplifyCFG/callbr-destinations.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -simplifycfg -disable-output +; +; Test that SimplifyCFG does not cause CallBr instructions to have duplicate +; destinations, which will cause the verifier to assert. + +define void @fun0() { +entry: + callbr void asm sideeffect "", "X"(i8* blockaddress(@fun0, %bb1)) + to label %bb2 [label %bb1] + +bb1: ; preds = %bb + ret void + +bb2: ; preds = %bb + ret void +} + +define void @fun1() { +entry: + callbr void asm sideeffect "", "X"(i8* blockaddress(@fun1, %bb1)) + to label %bb2 [label %bb1] + +bb2: ; preds = %bb + ret void + +bb1: ; preds = %bb + ret void +}