diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp --- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp +++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp @@ -28,6 +28,7 @@ #include "llvm/Analysis/MemorySSAUpdater.h" #include "llvm/Analysis/MustExecute.h" #include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" @@ -199,11 +200,14 @@ ArrayRef Invariants, bool Direction, BasicBlock &UnswitchedSucc, - BasicBlock &NormalSucc) { + BasicBlock &NormalSucc, + bool InsertFreeze) { IRBuilder<> IRB(&BB); Value *Cond = Direction ? IRB.CreateOr(Invariants) : IRB.CreateAnd(Invariants); + if (InsertFreeze) + Cond = IRB.CreateFreeze(Cond, Cond->getName() + ".fr"); IRB.CreateCondBr(Cond, Direction ? &UnswitchedSucc : &NormalSucc, Direction ? &NormalSucc : &UnswitchedSucc); } @@ -564,7 +568,7 @@ "Must have an `and` of `i1`s or `select i1 X, Y, false`s for the" " condition!"); buildPartialUnswitchConditionalBranch(*OldPH, Invariants, ExitDirection, - *UnswitchedBB, *NewPH); + *UnswitchedBB, *NewPH, false); } // Update the dominator tree with the added edge. @@ -2117,6 +2121,10 @@ SE->forgetTopmostLoop(&L); } + ICFLoopSafetyInfo SafetyInfo; + SafetyInfo.computeLoopSafetyInfo(&L); + bool InsertFreeze = !SafetyInfo.isGuaranteedToExecute(TI, &DT, &L); + // If the edge from this terminator to a successor dominates that successor, // store a map from each block in its dominator subtree to it. This lets us // tell when cloning for a particular successor if a block is dominated by @@ -2191,6 +2199,11 @@ BasicBlock *ClonedPH = ClonedPHs.begin()->second; BI->setSuccessor(ClonedSucc, ClonedPH); BI->setSuccessor(1 - ClonedSucc, LoopPH); + if (InsertFreeze) { + auto Cond = BI->getCondition(); + if (!isGuaranteedNotToBeUndefOrPoison(Cond, &AC, BI, &DT)) + BI->setCondition(new FreezeInst(Cond, Cond->getName() + ".fr", BI)); + } DTUpdates.push_back({DominatorTree::Insert, SplitBB, ClonedPH}); } else { assert(SI && "Must either be a branch or switch!"); @@ -2205,6 +2218,11 @@ else Case.setSuccessor(ClonedPHs.find(Case.getCaseSuccessor())->second); + if (InsertFreeze) { + auto Cond = SI->getCondition(); + if (!isGuaranteedNotToBeUndefOrPoison(Cond, &AC, SI, &DT)) + SI->setCondition(new FreezeInst(Cond, Cond->getName() + ".fr", SI)); + } // We need to use the set to populate domtree updates as even when there // are multiple cases pointing at the same successor we only want to // remove and insert one edge in the domtree. @@ -2285,7 +2303,7 @@ *SplitBB, Invariants, Direction, *ClonedPH, *LoopPH, L, MSSAU); else buildPartialUnswitchConditionalBranch(*SplitBB, Invariants, Direction, - *ClonedPH, *LoopPH); + *ClonedPH, *LoopPH, InsertFreeze); DTUpdates.push_back({DominatorTree::Insert, SplitBB, ClonedPH}); if (MSSAU) { diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll b/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll --- a/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll +++ b/llvm/test/Transforms/SimpleLoopUnswitch/ARM/nontrivial-unswitch-cost.ll @@ -55,7 +55,8 @@ define void @test_unswitch(i1* %ptr, i1 %cond) { ; CHECK-LABEL: @test_unswitch( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] +; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] ; CHECK: entry.split.us: ; CHECK-NEXT: br label [[LOOP_BEGIN_US:%.*]] ; CHECK: loop_begin.us: @@ -153,7 +154,8 @@ define void @test_unswitch_non_dup_code(i1* %ptr, i1 %cond) { ; CHECK-LABEL: @test_unswitch_non_dup_code( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] +; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] ; CHECK: entry.split.us: ; CHECK-NEXT: br label [[LOOP_BEGIN_US:%.*]] ; CHECK: loop_begin.us: @@ -275,7 +277,8 @@ define void @test_unswitch_non_dup_code_in_cfg(i1* %ptr, i1 %cond) { ; CHECK-LABEL: @test_unswitch_non_dup_code_in_cfg( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] +; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] ; CHECK: entry.split.us: ; CHECK-NEXT: br label [[LOOP_BEGIN_US:%.*]] ; CHECK: loop_begin.us: @@ -503,7 +506,8 @@ define void @test_unswitch_large_exit(i1* %ptr, i1 %cond) { ; CHECK-LABEL: @test_unswitch_large_exit( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] +; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] ; CHECK: entry.split.us: ; CHECK-NEXT: br label [[LOOP_BEGIN_US:%.*]] ; CHECK: loop_begin.us: @@ -567,7 +571,8 @@ define void @test_unswitch_dedicated_exiting(i1* %ptr, i1 %cond) { ; CHECK-LABEL: @test_unswitch_dedicated_exiting( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 [[COND:%.*]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] +; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[COND_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] ; CHECK: entry.split.us: ; CHECK-NEXT: br label [[LOOP_BEGIN_US:%.*]] ; CHECK: loop_begin.us: diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/implicit-null-checks.ll b/llvm/test/Transforms/SimpleLoopUnswitch/implicit-null-checks.ll --- a/llvm/test/Transforms/SimpleLoopUnswitch/implicit-null-checks.ll +++ b/llvm/test/Transforms/SimpleLoopUnswitch/implicit-null-checks.ll @@ -13,8 +13,8 @@ ; CHECK-LABEL: @test_should_drop_make_implicit( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null -; CHECK-NOT: !make.implicit -; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] +; CHECK-NEXT: [[NULL_CHECK_FR:%.*]] = freeze i1 [[NULL_CHECK]] +; CHECK-NEXT: br i1 [[NULL_CHECK_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] ; CHECK: entry.split.us: ; CHECK-NEXT: br label [[LOOP_US:%.*]] ; CHECK: loop.us: @@ -210,8 +210,8 @@ ; CHECK-LABEL: @test_should_drop_make_implicit_exiting_call( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null -; CHECK-NOT: !make.implicit -; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] +; CHECK-NEXT: [[NULL_CHECK_FR:%.*]] = freeze i1 [[NULL_CHECK]] +; CHECK-NEXT: br i1 [[NULL_CHECK_FR]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] ; CHECK: entry.split.us: ; CHECK-NEXT: br label [[LOOP_US:%.*]] ; CHECK: loop.us: