diff --git a/include/llvm/Transforms/Utils/Local.h b/include/llvm/Transforms/Utils/Local.h index e61dcb347c8..c9d29168217 100644 --- a/include/llvm/Transforms/Utils/Local.h +++ b/include/llvm/Transforms/Utils/Local.h @@ -43,8 +43,10 @@ template class SmallVectorImpl; /// constant value, convert it into an unconditional branch to the constant /// destination. This is a nontrivial operation because the successors of this /// basic block must have their PHI nodes updated. -/// -bool ConstantFoldTerminator(BasicBlock *BB); +/// Also calls RecursivelyDeleteTriviallyDeadInstructions() on any branch/switch +/// conditions and indirectbr addresses this might make dead if +/// DeleteDeadConditions is true. +bool ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions = false); //===----------------------------------------------------------------------===// // Local dead code elimination. diff --git a/lib/Transforms/Scalar/CodeGenPrepare.cpp b/lib/Transforms/Scalar/CodeGenPrepare.cpp index 01843901855..483bfe36552 100644 --- a/lib/Transforms/Scalar/CodeGenPrepare.cpp +++ b/lib/Transforms/Scalar/CodeGenPrepare.cpp @@ -147,7 +147,7 @@ bool CodeGenPrepare::runOnFunction(Function &F) { if (!DisableBranchOpts) { MadeChange = false; for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) - MadeChange |= ConstantFoldTerminator(BB); + MadeChange |= ConstantFoldTerminator(BB, true); if (MadeChange) ModifiedDT = true; diff --git a/lib/Transforms/Scalar/JumpThreading.cpp b/lib/Transforms/Scalar/JumpThreading.cpp index 5a8f4ca192d..cf18ff040bd 100644 --- a/lib/Transforms/Scalar/JumpThreading.cpp +++ b/lib/Transforms/Scalar/JumpThreading.cpp @@ -706,7 +706,7 @@ bool JumpThreading::ProcessBlock(BasicBlock *BB) { DEBUG(dbgs() << " In block '" << BB->getName() << "' folding terminator: " << *BB->getTerminator() << '\n'); ++NumFolds; - ConstantFoldTerminator(BB); + ConstantFoldTerminator(BB, true); return true; } diff --git a/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/lib/Transforms/Scalar/SimplifyCFGPass.cpp index 1137c2b23f9..eccafea3aa8 100644 --- a/lib/Transforms/Scalar/SimplifyCFGPass.cpp +++ b/lib/Transforms/Scalar/SimplifyCFGPass.cpp @@ -163,7 +163,7 @@ static bool MarkAliveBlocks(BasicBlock *BB, Changed = true; } - Changed |= ConstantFoldTerminator(BB); + Changed |= ConstantFoldTerminator(BB, true); for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI) Worklist.push_back(*SI); } while (!Worklist.empty()); diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp index 12e15b07c79..f5a8adacd5a 100644 --- a/lib/Transforms/Utils/Local.cpp +++ b/lib/Transforms/Utils/Local.cpp @@ -44,11 +44,14 @@ using namespace llvm; // Local constant propagation. // -// ConstantFoldTerminator - If a terminator instruction is predicated on a -// constant value, convert it into an unconditional branch to the constant -// destination. -// -bool llvm::ConstantFoldTerminator(BasicBlock *BB) { +/// ConstantFoldTerminator - If a terminator instruction is predicated on a +/// constant value, convert it into an unconditional branch to the constant +/// destination. This is a nontrivial operation because the successors of this +/// basic block must have their PHI nodes updated. +/// Also calls RecursivelyDeleteTriviallyDeadInstructions() on any branch/switch +/// conditions and indirectbr addresses this might make dead if +/// DeleteDeadConditions is true. +bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions) { TerminatorInst *T = BB->getTerminator(); IRBuilder<> Builder(T); @@ -89,7 +92,10 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB) { // Replace the conditional branch with an unconditional one. Builder.CreateBr(Dest1); + Value *Cond = BI->getCondition(); BI->eraseFromParent(); + if (DeleteDeadConditions) + RecursivelyDeleteTriviallyDeadInstructions(Cond); return true; } return false; @@ -152,7 +158,10 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB) { } // Delete the old switch. - BB->getInstList().erase(SI); + Value *Cond = SI->getCondition(); + SI->eraseFromParent(); + if (DeleteDeadConditions) + RecursivelyDeleteTriviallyDeadInstructions(Cond); return true; } @@ -186,7 +195,10 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB) { else IBI->getDestination(i)->removePredecessor(IBI->getParent()); } + Value *Address = IBI->getAddress(); IBI->eraseFromParent(); + if (DeleteDeadConditions) + RecursivelyDeleteTriviallyDeadInstructions(Address); // If we didn't find our destination in the IBI successor list, then we // have undefined behavior. Replace the unconditional branch with an diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index 2c032d5d129..5ab9a2877cd 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -2651,7 +2651,7 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { // Check to see if we can constant propagate this terminator instruction // away... - Changed |= ConstantFoldTerminator(BB); + Changed |= ConstantFoldTerminator(BB, true); // Check for and eliminate duplicate PHI nodes in this block. Changed |= EliminateDuplicatePHINodes(BB); diff --git a/test/Transforms/SimplifyCFG/dce-cond-after-folding-terminator.ll b/test/Transforms/SimplifyCFG/dce-cond-after-folding-terminator.ll new file mode 100644 index 00000000000..3996efd82b5 --- /dev/null +++ b/test/Transforms/SimplifyCFG/dce-cond-after-folding-terminator.ll @@ -0,0 +1,52 @@ +; RUN: opt -S <%s -simplifycfg | FileCheck %s + +define void @test_br(i32 %x) { +entry: +; CHECK: @test_br +; CHECK-NEXT: entry: +; CHECK-NEXT: ret void + %cmp = icmp eq i32 %x, 10 + br i1 %cmp, label %if.then, label %if.then + +if.then: ; preds = %entry + br label %if.end + +if.end: ; preds = %if.else, %if.then + ret void +} + +define void @test_switch(i32 %x) nounwind { +entry: +; CHECK: @test_switch +; CHECK-NEXT: entry: +; CHECK-NEXT: ret void + %rem = srem i32 %x, 3 + switch i32 %rem, label %sw.bb [ + i32 1, label %sw.bb + i32 10, label %sw.bb + ] + +sw.bb: ; preds = %sw.default, %entry, %entry + br label %sw.epilog + +sw.epilog: ; preds = %sw.bb + ret void +} + +define void @test_indirectbr(i32 %x) { +entry: +; CHECK: @test_indirectbr +; CHECK-NEXT: entry: +; Ideally this should now check: +; CHK-NEXT: ret void +; But that doesn't happen yet. Instead: +; CHECK-NEXT: br label %L1 + + %label = bitcast i8* blockaddress(@test_indirectbr, %L1) to i8* + indirectbr i8* %label, [label %L1, label %L2] + +L1: ; preds = %entry + ret void +L2: ; preds = %entry + ret void +}