Index: llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp =================================================================== --- llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp +++ llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp @@ -54,6 +54,7 @@ // std::vector ReturningBlocks; std::vector UnreachableBlocks; + bool Changed = false; for (BasicBlock &I : F) if (isa(I.getTerminator())) ReturningBlocks.push_back(&I); @@ -74,15 +75,16 @@ BB->getInstList().pop_back(); // Remove the unreachable inst. BranchInst::Create(UnreachableBlock, BB); } + Changed = true; } // Now handle return blocks. if (ReturningBlocks.empty()) { ReturnBlock = nullptr; - return false; // No blocks return + return Changed; // No blocks return } else if (ReturningBlocks.size() == 1) { ReturnBlock = ReturningBlocks.front(); // Already has a single return block - return false; + return Changed; } // Otherwise, we need to insert a new basic block into the function, add a PHI Index: llvm/test/Transforms/UnifyFunctionExitNodes/unreachable-blocks-status.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/UnifyFunctionExitNodes/unreachable-blocks-status.ll @@ -0,0 +1,67 @@ +; RUN: opt -mergereturn -S < %s | FileCheck %s + +; The pass did previously not report the correct Modified status in the case +; where a function had at most one return block, and an unified unreachable +; block was created. This was caught by the pass return status check that is +; hidden under EXPENSIVE_CHECKS. + +; CHECK: for.foo.body2: +; CHECK-NEXT: br label %UnifiedUnreachableBlock + +; CHECK: for.foo.end: +; CHECK-NEXT: br label %UnifiedUnreachableBlock + +; CHECK: UnifiedUnreachableBlock: +; CHECK-NEXT: unreachable + +define i32 @foo() { +entry: + br label %for.foo.cond + +for.foo.cond: ; preds = %entry + br i1 false, label %for.foo.body, label %for.foo.end3 + +for.foo.body: ; preds = %for.foo.cond + br label %for.foo.cond1 + +for.foo.cond1: ; preds = %for.foo.body + br i1 false, label %for.foo.body2, label %for.foo.end + +for.foo.body2: ; preds = %for.foo.cond1 + unreachable + +for.foo.end: ; preds = %for.foo.cond1 + unreachable + +for.foo.end3: ; preds = %for.foo.cond + ret i32 undef +} + +; CHECK: for.bar.body2: +; CHECK-NEXT: br label %UnifiedUnreachableBlock + +; CHECK: for.bar.end: +; CHECK-NEXT: br label %UnifiedUnreachableBlock + +; CHECK: UnifiedUnreachableBlock: +; CHECK-NEXT: unreachable + +define void @bar() { +entry: + br label %for.bar.cond + +for.bar.cond: ; preds = %entry + br i1 false, label %for.bar.body, label %for.bar.end + +for.bar.body: ; preds = %for.bar.cond + br label %for.bar.cond1 + +for.bar.cond1: ; preds = %for.bar.body + br i1 false, label %for.bar.body2, label %for.bar.end + +for.bar.body2: ; preds = %for.bar.cond1 + unreachable + +for.bar.end: ; preds = %for.bar.cond1 + unreachable +}