[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