diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp --- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -1251,6 +1251,17 @@ return false; Value *Cond = BI->getCondition(); + // Assuming that predecessor's branch was taken, if pred's branch condition + // (V) implies Cond, Cond can be either true, undef, or poison. In this case, + // freeze(Cond) is either true or a nondeterministic value. + // If freeze(Cond) has only one use, we can freely fold freeze(Cond) to true + // without affecting other instructions. + auto *FICond = dyn_cast(Cond); + if (FICond && FICond->hasOneUse()) + Cond = FICond->getOperand(0); + else + FICond = nullptr; + BasicBlock *CurrentBB = BB; BasicBlock *CurrentPred = BB->getSinglePredecessor(); unsigned Iter = 0; @@ -1267,6 +1278,15 @@ bool CondIsTrue = PBI->getSuccessor(0) == CurrentBB; Optional Implication = isImpliedCondition(PBI->getCondition(), Cond, DL, CondIsTrue); + + // If the branch condition of BB (which is Cond) and CurrentPred are + // exactly the same freeze instruction, Cond can be folded into CondIsTrue. + if (!Implication && FICond && isa(PBI->getCondition())) { + if (cast(PBI->getCondition())->getOperand(0) == + FICond->getOperand(0)) + Implication = CondIsTrue; + } + if (Implication) { BasicBlock *KeepSucc = BI->getSuccessor(*Implication ? 0 : 1); BasicBlock *RemoveSucc = BI->getSuccessor(*Implication ? 1 : 0); @@ -1275,6 +1295,9 @@ UncondBI->setDebugLoc(BI->getDebugLoc()); ++NumFolds; BI->eraseFromParent(); + if (FICond) + FICond->eraseFromParent(); + DTU->applyUpdatesPermissive({{DominatorTree::Delete, BB, RemoveSucc}}); if (HasProfileData) BPI->eraseBlock(BB); diff --git a/llvm/test/Transforms/JumpThreading/freeze-impliescond.ll b/llvm/test/Transforms/JumpThreading/freeze-impliescond.ll --- a/llvm/test/Transforms/JumpThreading/freeze-impliescond.ll +++ b/llvm/test/Transforms/JumpThreading/freeze-impliescond.ll @@ -42,20 +42,12 @@ ; CHECK-NEXT: [[COND_FR0:%.*]] = freeze i1 [[COND:%.*]] ; CHECK-NEXT: br i1 [[COND_FR0]], label [[A:%.*]], label [[B:%.*]] ; CHECK: A: -; CHECK-NEXT: br i1 [[DUMMYCOND:%.*]], label [[A2:%.*]], label [[DUMMY:%.*]] -; CHECK: A2: -; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND]] -; CHECK-NEXT: br i1 [[COND_FR]], label [[REACHABLE:%.*]], label [[UNREACHABLE:%.*]] +; CHECK-NEXT: br i1 [[DUMMYCOND:%.*]], label [[REACHABLE:%.*]], label [[DUMMY:%.*]] ; CHECK: B: -; CHECK-NEXT: br i1 [[DUMMYCOND]], label [[B2:%.*]], label [[DUMMY]] -; CHECK: B2: -; CHECK-NEXT: [[COND_FR2:%.*]] = freeze i1 [[COND]] -; CHECK-NEXT: br i1 [[COND_FR2]], label [[UNREACHABLE]], label [[REACHABLE]] +; CHECK-NEXT: br i1 [[DUMMYCOND]], label [[REACHABLE]], label [[DUMMY]] ; CHECK: REACHABLE: ; CHECK-NEXT: call void @f() ; CHECK-NEXT: ret void -; CHECK: UNREACHABLE: -; CHECK-NEXT: ret void ; CHECK: DUMMY: ; CHECK-NEXT: ret void ; @@ -81,6 +73,14 @@ ret void } +; In this specific example, it is still correct to fold %cond.fr into true. +; This case is unsupported because it is unclear what is the result of +; isImpliedCondition if LHS is poison or undef. +; If isImpliedCondition(poison, any value) is true, +; isImpliedCondition(and true, poison, false) is also true because 'and' propagates poison. +; However, freeze(and true, poison) does not imply false because the former can +; be frozen to true. Therefore, we cannot look through the argument of freeze (%cond.fr0) +; in general under this isImpliedCondition definition. define void @and_noopt(i32 %x, i1 %cond2, i1 %dummycond) { ; CHECK-LABEL: @and_noopt( ; CHECK-NEXT: [[COND1:%.*]] = icmp slt i32 0, [[X:%.*]] @@ -135,10 +135,7 @@ ; CHECK-NEXT: [[COND:%.*]] = and i1 [[COND1]], [[COND2:%.*]] ; CHECK-NEXT: br i1 [[COND]], label [[A:%.*]], label [[B:%.*]] ; CHECK: A: -; CHECK-NEXT: br i1 [[DUMMYCOND:%.*]], label [[A2:%.*]], label [[DUMMY:%.*]] -; CHECK: A2: -; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND1]] -; CHECK-NEXT: br i1 [[COND_FR]], label [[REACHABLE:%.*]], label [[UNREACHABLE:%.*]] +; CHECK-NEXT: br i1 [[DUMMYCOND:%.*]], label [[REACHABLE:%.*]], label [[DUMMY:%.*]] ; CHECK: B: ; CHECK-NEXT: br i1 [[DUMMYCOND]], label [[B2:%.*]], label [[DUMMY]] ; CHECK: B2: @@ -150,8 +147,6 @@ ; CHECK: REACHABLE2: ; CHECK-NEXT: call void @f() ; CHECK-NEXT: ret void -; CHECK: UNREACHABLE: -; CHECK-NEXT: ret void ; CHECK: DUMMY: ; CHECK-NEXT: ret void ;