[llvm] [SimplifyCFG] Simplify cond br on select (PR #173876)

Kunqiu Chen via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 29 08:56:02 PST 2025


https://github.com/Camsyn created https://github.com/llvm/llvm-project/pull/173876

Previously, `simplifycfg` could simplify "switch on select" (see `simplifySwitchOnSelect`) but could not simplify a similar, yet simpler, "cond br on select".

This PR makes `simplifycfg` support simplifying "cond br on select" as uncond br, as follows:

```diff
   %select = select i1 %v, i8 3, i8 2
-  %cond = icmp eq i8 %select, 0
-  br i1 %cond, label %TrueBB, label %FalseBB
+  br label %FalseBB
```

Although `instcombine` + `simplifycfg` can also simplify this case, I think this PR is still valuable when there is no `instcombine` after this "cond br on select" first appears on optimization pipelines.

---

- Found in https://github.com/dtcxzyw/llvm-opt-benchmark/pull/3233#discussion_r2650670627
- IR diff:
- CompTime impact:



>From e72d004666ebf12a0ab7cb5ce37d21527e95df2e Mon Sep 17 00:00:00 2001
From: Camsyn <camsyn at foxmail.com>
Date: Tue, 30 Dec 2025 00:42:17 +0800
Subject: [PATCH 1/3] Before-commit test

---
 .../SimplifyCFG/cond-br-on-const-select.ll    | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 llvm/test/Transforms/SimplifyCFG/cond-br-on-const-select.ll

diff --git a/llvm/test/Transforms/SimplifyCFG/cond-br-on-const-select.ll b/llvm/test/Transforms/SimplifyCFG/cond-br-on-const-select.ll
new file mode 100644
index 0000000000000..2188adf8b3fc3
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/cond-br-on-const-select.ll
@@ -0,0 +1,33 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=simplifycfg -S | FileCheck %s
+
+
+declare void @use()
+
+; Reduced from _ZN12_GLOBAL__N_116AArch64AsmParser20parseRegisterInRangeERjjjj @ llvm/AArch64AsmParser.ll
+define fastcc i1 @foo(i1 %v) {
+; CHECK-LABEL: define fastcc i1 @foo(
+; CHECK-SAME: i1 [[V:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[V]], i8 3, i8 2
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[SELECT]], 0
+; CHECK-NEXT:    br i1 [[COND]], label %[[TRUEBB:.*]], label %[[COMMON_RET:.*]]
+; CHECK:       [[COMMON_RET]]:
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ true, %[[TRUEBB]] ], [ false, %[[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK:       [[TRUEBB]]:
+; CHECK-NEXT:    call void @use()
+; CHECK-NEXT:    br label %[[COMMON_RET]]
+;
+entry:
+  %select = select i1 %v, i8 3, i8 2
+  %cond = icmp eq i8 %select, 0
+  br i1 %cond, label %TrueBB, label %FalseBB
+
+TrueBB:                                           ; preds = %entry
+  call void @use()
+  ret i1 true
+
+FalseBB:                                          ; preds = %entry
+  ret i1 false
+}

>From c90e2e0815058a517c772b9104716ab1435b5a47 Mon Sep 17 00:00:00 2001
From: Camsyn <camsyn at foxmail.com>
Date: Tue, 30 Dec 2025 00:42:39 +0800
Subject: [PATCH 2/3] Simplify cond br on select

---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 42 +++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 2a957737697c3..f6cf1e5b0f6ed 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -316,6 +316,8 @@ class SimplifyCFGOpt {
                                   uint32_t TrueWeight, uint32_t FalseWeight);
   bool simplifyBranchOnICmpChain(BranchInst *BI, IRBuilder<> &Builder,
                                  const DataLayout &DL);
+  bool simplifyCondCondOnICmpSelect(BranchInst *BI, const CmpPredicate Pred,
+                                    const APInt &CmpC, SelectInst *Select);
   bool simplifySwitchOnSelect(SwitchInst *SI, SelectInst *Select);
   bool simplifyIndirectBrOnSelect(IndirectBrInst *IBI, SelectInst *SI);
   bool turnSwitchRangeIntoICmp(SwitchInst *SI, IRBuilder<> &Builder);
@@ -4949,6 +4951,32 @@ bool SimplifyCFGOpt::simplifyTerminatorOnSelect(Instruction *OldTerm,
   return true;
 }
 
+// Try to replaces
+//   (br (icmp Pred, (select cond, X, Y), Z), TrueBB, FalseBB) 
+// on constant X, Y, Z with a unconditional branch.
+bool SimplifyCFGOpt::simplifyCondCondOnICmpSelect(BranchInst *BI, const CmpPredicate Pred,
+                                  const APInt &CmpC, SelectInst *Select) {
+  // Check for constant integer values in the select.
+  const APInt *TrueVal, *FalseVal;
+  if (!match(Select, m_Select(m_Value(), m_APInt(TrueVal), m_APInt(FalseVal))))
+    return false;
+
+  assert(BI->isConditional() && BI->getNumSuccessors() == 2 &&
+         "Expected conditional branch with 2 successors");
+
+  ConstantRange CmpCR = ConstantRange::makeExactICmpRegion(Pred, CmpC);
+  BasicBlock *TargetBB;
+  if (CmpCR.contains(*TrueVal) && CmpCR.contains(*FalseVal))
+    TargetBB = BI->getSuccessor(0); // br label %TrueBB
+  else if (!CmpCR.contains(*TrueVal) && !CmpCR.contains(*FalseVal))
+    TargetBB = BI->getSuccessor(1); // br label %FalseBB
+  else
+    return false;
+  
+  // Perform the actual simplification.
+  return simplifyTerminatorOnSelect(BI, nullptr, TargetBB, TargetBB, 0, 0);
+}
+
 // Replaces
 //   (switch (select cond, X, Y)) on constant X, Y
 // with a branch - conditional if X and Y lead to distinct BBs,
@@ -8545,6 +8573,20 @@ bool SimplifyCFGOpt::simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder) {
       if (simplifyEqualityComparisonWithOnlyPredecessor(BI, OnlyPred, Builder))
         return requestResimplify();
 
+    Instruction *Select;
+    CmpPredicate Pred;
+    const APInt *CmpC;
+    // Match the pattern:
+    // %select = select ...
+    // %cmp = icmp [Pred], %select, [C]
+    // br i1 %cmp, label ..., label ...
+    if (match(BI, m_Br(m_c_ICmp(Pred, m_Instruction(Select), m_APInt(CmpC)),
+                       m_Value(), m_Value())) &&
+        isa<SelectInst>(Select))
+      if (simplifyCondCondOnICmpSelect(BI, Pred, *CmpC,
+                                       cast<SelectInst>(Select)))
+        return requestResimplify();
+
     // This block must be empty, except for the setcond inst, if it exists.
     // Ignore dbg and pseudo intrinsics.
     auto I = BB->instructionsWithoutDebug(true).begin();

>From 24b8550eb4393b9a28a8c7bd917d444cd4111e09 Mon Sep 17 00:00:00 2001
From: Camsyn <camsyn at foxmail.com>
Date: Tue, 30 Dec 2025 00:42:57 +0800
Subject: [PATCH 3/3] After-commit test

---
 .../SimplifyCFG/cond-br-on-const-select.ll           | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/llvm/test/Transforms/SimplifyCFG/cond-br-on-const-select.ll b/llvm/test/Transforms/SimplifyCFG/cond-br-on-const-select.ll
index 2188adf8b3fc3..42d9680dac1aa 100644
--- a/llvm/test/Transforms/SimplifyCFG/cond-br-on-const-select.ll
+++ b/llvm/test/Transforms/SimplifyCFG/cond-br-on-const-select.ll
@@ -8,16 +8,8 @@ declare void @use()
 define fastcc i1 @foo(i1 %v) {
 ; CHECK-LABEL: define fastcc i1 @foo(
 ; CHECK-SAME: i1 [[V:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[V]], i8 3, i8 2
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[SELECT]], 0
-; CHECK-NEXT:    br i1 [[COND]], label %[[TRUEBB:.*]], label %[[COMMON_RET:.*]]
-; CHECK:       [[COMMON_RET]]:
-; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ true, %[[TRUEBB]] ], [ false, %[[ENTRY]] ]
-; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
-; CHECK:       [[TRUEBB]]:
-; CHECK-NEXT:    call void @use()
-; CHECK-NEXT:    br label %[[COMMON_RET]]
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    ret i1 false
 ;
 entry:
   %select = select i1 %v, i8 3, i8 2



More information about the llvm-commits mailing list