[llvm] [SimplifyCFG] Removed the conditional branch (PR #146445)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 30 19:22:48 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: David Zheng (davidzhengyes)

<details>
<summary>Changes</summary>

This pull request responds to my issue #<!-- -->146442. I track StronglyKnownValues in an unordered_set, meaning that we can determine the value on the edge, and also that value is an instruction that belongs to the `From` basic block.

---
Full diff: https://github.com/llvm/llvm-project/pull/146445.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/Utils/SimplifyCFG.cpp (+34-6) 
- (added) llvm/test/Transforms/SimplifyCFG/EliminateDeadPhi.ll (+74) 


``````````diff
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 147d2060e8509..fb54b854c6da5 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -87,6 +87,7 @@
 #include <optional>
 #include <set>
 #include <tuple>
+#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -3436,7 +3437,7 @@ static bool blockIsSimpleEnoughToThreadThrough(BasicBlock *BB) {
 }
 
 static ConstantInt *getKnownValueOnEdge(Value *V, BasicBlock *From,
-                                        BasicBlock *To) {
+                                        BasicBlock *To, bool Strong = false) {
   // Don't look past the block defining the value, we might get the value from
   // a previous loop iteration.
   auto *I = dyn_cast<Instruction>(V);
@@ -3446,10 +3447,18 @@ static ConstantInt *getKnownValueOnEdge(Value *V, BasicBlock *From,
   // We know the value if the From block branches on it.
   auto *BI = dyn_cast<BranchInst>(From->getTerminator());
   if (BI && BI->isConditional() && BI->getCondition() == V &&
-      BI->getSuccessor(0) != BI->getSuccessor(1))
-    return BI->getSuccessor(0) == To ? ConstantInt::getTrue(BI->getContext())
-                                     : ConstantInt::getFalse(BI->getContext());
-
+      BI->getSuccessor(0) != BI->getSuccessor(1)) {
+    ConstantInt *KnownValue = 
+              BI->getSuccessor(0) == To ? ConstantInt::getTrue(BI->getContext())
+                                        : ConstantInt::getFalse(BI->getContext());
+    if (Strong) {
+      Value *Cond = BI->getCondition();
+      Instruction *CondInst = dyn_cast<Instruction>(Cond);
+      return (CondInst && CondInst->getParent() == From) ? KnownValue : nullptr; 
+    } else {
+      return KnownValue;
+    }
+  }
   return nullptr;
 }
 
@@ -3461,6 +3470,7 @@ foldCondBranchOnValueKnownInPredecessorImpl(BranchInst *BI, DomTreeUpdater *DTU,
                                             const DataLayout &DL,
                                             AssumptionCache *AC) {
   SmallMapVector<ConstantInt *, SmallSetVector<BasicBlock *, 2>, 2> KnownValues;
+  std::unordered_set<ConstantInt *> StronglyKnownValues;
   BasicBlock *BB = BI->getParent();
   Value *Cond = BI->getCondition();
   PHINode *PN = dyn_cast<PHINode>(Cond);
@@ -3476,8 +3486,12 @@ foldCondBranchOnValueKnownInPredecessorImpl(BranchInst *BI, DomTreeUpdater *DTU,
         KnownValues[CB].insert(PN->getIncomingBlock(U));
   } else {
     for (BasicBlock *Pred : predecessors(BB)) {
-      if (ConstantInt *CB = getKnownValueOnEdge(Cond, Pred, BB))
+      if (ConstantInt *CB = getKnownValueOnEdge(Cond, Pred, BB)) {
         KnownValues[CB].insert(Pred);
+        if (getKnownValueOnEdge(Cond, Pred, BB, true)) {
+          StronglyKnownValues.insert(CB);
+        }
+      }
     }
   }
 
@@ -3593,11 +3607,20 @@ foldCondBranchOnValueKnownInPredecessorImpl(BranchInst *BI, DomTreeUpdater *DTU,
     BranchInst *EdgeBI = cast<BranchInst>(EdgeBB->getTerminator());
     EdgeBI->setSuccessor(0, RealDest);
     EdgeBI->setDebugLoc(BI->getDebugLoc());
+    
+    bool RemoveCondBr = StronglyKnownValues.count(CB);
+    if (RemoveCondBr) {
+      RealDest->removePredecessor(BB);
+      ReplaceInstWithInst(BI, BranchInst::Create(BI->getSuccessor(CB->getZExtValue())));
+    }
 
     if (DTU) {
       SmallVector<DominatorTree::UpdateType, 2> Updates;
       Updates.push_back({DominatorTree::Delete, EdgeBB, BB});
       Updates.push_back({DominatorTree::Insert, EdgeBB, RealDest});
+      if (RemoveCondBr) {
+        Updates.push_back({DominatorTree::Delete, BB, RealDest});
+      }
       DTU->applyUpdates(Updates);
     }
 
@@ -3607,6 +3630,11 @@ foldCondBranchOnValueKnownInPredecessorImpl(BranchInst *BI, DomTreeUpdater *DTU,
     // bypass the check for trivial cycles above.
     MergeBlockIntoPredecessor(EdgeBB, DTU);
 
+    // If we remove the conditional branch, cannot keep simplifying.
+    if (RemoveCondBr) {
+      return true; 
+    }
+
     // Signal repeat, simplifying any other constants.
     return std::nullopt;
   }
diff --git a/llvm/test/Transforms/SimplifyCFG/EliminateDeadPhi.ll b/llvm/test/Transforms/SimplifyCFG/EliminateDeadPhi.ll
new file mode 100644
index 0000000000000..2877d759b4940
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/EliminateDeadPhi.ll
@@ -0,0 +1,74 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=simplifycfg -S | FileCheck %s
+
+
+define void @mainfunc(i16 %0) {
+; CHECK-LABEL: define void @mainfunc(
+; CHECK-SAME: i16 [[TMP0:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i16 [[TMP0]], 10
+; CHECK-NEXT:    br i1 [[TMP1]], label %[[OTHERLOOPEND:.*]], label %[[FOR_BODY_CRITEDGE:.*]]
+; CHECK:       [[OTHERLOOPEND]]:
+; CHECK-NEXT:    [[OTHERLOOPIV:%.*]] = call i16 @ivfunc()
+; CHECK-NEXT:    [[OTHERLOOPPRED:%.*]] = icmp slt i16 [[OTHERLOOPIV]], 100
+; CHECK-NEXT:    br i1 [[OTHERLOOPPRED]], label %[[OTHERLOOPEND]], label %[[VADDEXIT:.*]]
+; CHECK:       [[VADDEXIT]]:
+; CHECK-NEXT:    call void @voidfunc()
+; CHECK-NEXT:    br label %[[END:.*]]
+; CHECK:       [[FOR_BODY_CRITEDGE]]:
+; CHECK-NEXT:    call void @voidfunc()
+; CHECK-NEXT:    br label %[[FOR_BODY:.*]]
+; CHECK:       [[FOR_BODY]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ [[IV_NEXT:%.*]], %[[FOR_BODY]] ], [ 0, %[[FOR_BODY_CRITEDGE]] ]
+; CHECK-NEXT:    [[VAL:%.*]] = tail call <256 x i1> @helperfunc()
+; CHECK-NEXT:    [[VAL2:%.*]] = tail call <1 x i32> @helperfunc2()
+; CHECK-NEXT:    [[IV_NEXT]] = add i16 [[IV]], 1
+; CHECK-NEXT:    [[PRED:%.*]] = icmp slt i16 [[IV_NEXT]], 100
+; CHECK-NEXT:    br i1 [[PRED]], label %[[FOR_BODY]], label %[[END]]
+; CHECK:       [[END]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %otherlooppreheader
+
+otherlooppreheader:
+  %1 = icmp ugt i16 %0, 10
+  br i1 %1, label %otherloopend, label %VAddExit
+
+otherloopend:
+  %otherloopiv = call i16 @ivfunc()
+  %otherLoopPred = icmp slt i16 %otherloopiv, 100
+  br i1 %otherLoopPred, label %otherloopend, label %VAddExit
+
+
+VAddExit:
+  call void @voidfunc()
+  br i1 %1, label %end, label %for.body
+
+for.body:
+  %iv = phi i16 [ %iv.next, %VMulExit ], [ 0, %VAddExit ]
+  %val = tail call <256 x i1> @helperfunc()
+  br label %for.body.inner
+
+for.body.inner:
+  %val2 = tail call <1 x i32> @helperfunc2()
+  br label %VMulExit
+
+VMulExit:
+  %iv.next = add i16 %iv, 1
+  %pred = icmp slt i16 %iv.next, 100
+  br i1 %pred, label %for.body, label %end
+
+end:
+  ret void
+
+}
+
+
+declare i16 @ivfunc()
+
+declare <256 x i1> @helperfunc()
+
+declare <1 x i32> @helperfunc2()
+
+declare void @voidfunc()

``````````

</details>


https://github.com/llvm/llvm-project/pull/146445


More information about the llvm-commits mailing list