[llvm] [SimplifyCFG] Transform switch to select when common bits uniquely identify one case (PR #145233)
Gábor Spaits via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 23 11:10:34 PDT 2025
https://github.com/spaits updated https://github.com/llvm/llvm-project/pull/145233
>From 8a57f890d9b6464f2670a4e69c9a817c5b093904 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Sun, 22 Jun 2025 15:32:07 +0200
Subject: [PATCH 1/3] Transform switch to select when common bits uniquely
identify one case
---
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 31 ++++++-
.../SimplifyCFG/switch-to-select-two-case.ll | 88 +++++++++++++++++++
2 files changed, 117 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index e221022bb8361..24d43b63dea41 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6290,10 +6290,37 @@ static Value *foldSwitchToSelect(const SwitchCaseResultVectorTy &ResultVector,
// case 0,2,8,10 -> Cond & 0b1..0101 == 0 ? result : default
if (isPowerOf2_32(CaseCount)) {
ConstantInt *MinCaseVal = CaseValues[0];
- // Find mininal value.
- for (auto *Case : CaseValues)
+ // In case, there are bits, that can only be present in the CaseValues we
+ // can transform the switch into a select if the conjunction of
+ // all the values uniquely identify the CaseValues.
+ APInt AndMask = APInt::getAllOnes(MinCaseVal->getBitWidth());
+
+ for (auto *Case : CaseValues) {
if (Case->getValue().slt(MinCaseVal->getValue()))
MinCaseVal = Case;
+ AndMask &= Case->getValue();
+ }
+
+ ConstantRange CR = computeConstantRange(
+ Condition, /* ForSigned */ Condition->getType()->isSingleValueType());
+ unsigned int ConditionWidth = Condition->getType()->getIntegerBitWidth();
+ APInt ActiveBits = APInt(ConditionWidth, CR.getActiveBits(),
+ Condition->getType()->isSingleValueType());
+
+ APInt One(ConditionWidth, 1, false);
+ APInt ActiveBitsMask = (One << ActiveBits) - 1;
+
+ // To make sure, that the representation of the accepted values is
+ // actually unique we check, wheter the conjucted bits and the another
+ // conjuction with the input value will only be true for exactly CaseCount
+ // number times.
+ if ((One << ActiveBits) - (One << (ActiveBits - AndMask.popcount())) ==
+ CaseCount) {
+ Value *And = Builder.CreateAnd(Condition, AndMask);
+ Value *Cmp =
+ Builder.CreateICmpNE(And, Constant::getNullValue(And->getType()));
+ return Builder.CreateSelect(Cmp, ResultVector[0].first, DefaultResult);
+ }
// Mark the bits case number touched.
APInt BitMask = APInt::getZero(MinCaseVal->getBitWidth());
diff --git a/llvm/test/Transforms/SimplifyCFG/switch-to-select-two-case.ll b/llvm/test/Transforms/SimplifyCFG/switch-to-select-two-case.ll
index 50998e447b71d..638bda990bc87 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch-to-select-two-case.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch-to-select-two-case.ll
@@ -309,3 +309,91 @@ end:
%t0 = phi i8 [ 42, %case1 ], [ 42, %case2 ], [ 44, %case3 ], [ 44, %case4 ]
ret i8 %t0
}
+
+define i1 @range0to4odd(i8 range(i8 0, 4) %f) {
+; CHECK-LABEL: @range0to4odd(
+; CHECK-NEXT: bb3:
+; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[F:%.*]], 1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[TMP0]], 0
+; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i1 true, i1 false
+; CHECK-NEXT: ret i1 [[TMP2]]
+;
+ switch i8 %f, label %bb1 [
+ i8 1, label %bb2
+ i8 3, label %bb2
+ ]
+bb1:
+ br label %bb3
+bb2:
+ br label %bb3
+bb3:
+ %_0.sroa.0.0 = phi i1 [ false, %bb1 ], [ true, %bb2 ]
+ ret i1 %_0.sroa.0.0
+}
+
+define i1 @range1to4odd(i8 range(i8 1, 4) %f) {
+; CHECK-LABEL: @range1to4odd(
+; CHECK-NEXT: bb3:
+; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[F:%.*]], 1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[TMP0]], 0
+; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i1 true, i1 false
+; CHECK-NEXT: ret i1 [[TMP2]]
+;
+ switch i8 %f, label %bb1 [
+ i8 1, label %bb2
+ i8 3, label %bb2
+ ]
+bb1:
+ br label %bb3
+bb2:
+ br label %bb3
+bb3:
+ %_0.sroa.0.0 = phi i1 [ false, %bb1 ], [ true, %bb2 ]
+ ret i1 %_0.sroa.0.0
+}
+
+define i1 @range0to8odd(i8 range(i8 0, 8) %f) {
+; CHECK-LABEL: @range0to8odd(
+; CHECK-NEXT: bb3:
+; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[F:%.*]], 1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[TMP0]], 0
+; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i1 true, i1 false
+; CHECK-NEXT: ret i1 [[TMP2]]
+;
+ switch i8 %f, label %bb1 [
+ i8 1, label %bb2
+ i8 3, label %bb2
+ i8 5, label %bb2
+ i8 7, label %bb2
+ ]
+bb1:
+ br label %bb3
+bb2:
+ br label %bb3
+bb3:
+ %_0.sroa.0.0 = phi i1 [ false, %bb1 ], [ true, %bb2 ]
+ ret i1 %_0.sroa.0.0
+}
+
+define i1 @negative_range0to5even(i8 range(i8 0, 5) %f) {
+; CHECK-LABEL: @negative_range0to5even(
+; CHECK-NEXT: bb3:
+; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[F:%.*]], 2
+; CHECK-NEXT: [[SWITCH_AND:%.*]] = and i8 [[TMP0]], -3
+; CHECK-NEXT: [[SWITCH_SELECTCMP:%.*]] = icmp eq i8 [[SWITCH_AND]], 0
+; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[SWITCH_SELECTCMP]], i1 true, i1 false
+; CHECK-NEXT: ret i1 [[TMP1]]
+;
+ switch i8 %f, label %bb1 [
+ i8 2, label %bb2
+ i8 4, label %bb2
+ ]
+bb1:
+ br label %bb3
+bb2:
+ br label %bb3
+bb3:
+ %_0.sroa.0.0 = phi i1 [ false, %bb1 ], [ true, %bb2 ]
+ ret i1 %_0.sroa.0.0
+}
+
>From d6806b536c5bf89229873d239c53a02cc3e22a4a Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Mon, 23 Jun 2025 12:59:38 +0200
Subject: [PATCH 2/3] ActiveBitsMask isn't needed
---
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 24d43b63dea41..ab8c63e5b312c 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6308,8 +6308,6 @@ static Value *foldSwitchToSelect(const SwitchCaseResultVectorTy &ResultVector,
Condition->getType()->isSingleValueType());
APInt One(ConditionWidth, 1, false);
- APInt ActiveBitsMask = (One << ActiveBits) - 1;
-
// To make sure, that the representation of the accepted values is
// actually unique we check, wheter the conjucted bits and the another
// conjuction with the input value will only be true for exactly CaseCount
>From fd05b6a1100715d58bed62656ad37031b3e8b220 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Mon, 23 Jun 2025 20:08:59 +0200
Subject: [PATCH 3/3] Use computeKnownBits insted of computeConstantRange
---
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index ab8c63e5b312c..b31e517c91d00 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6254,7 +6254,7 @@ static bool initializeUniqueCases(SwitchInst *SI, PHINode *&PHI,
// TODO: Handle switches with more than 2 cases that map to the same result.
static Value *foldSwitchToSelect(const SwitchCaseResultVectorTy &ResultVector,
Constant *DefaultResult, Value *Condition,
- IRBuilder<> &Builder) {
+ IRBuilder<> &Builder, const DataLayout &DL) {
// If we are selecting between only two cases transform into a simple
// select or a two-way select if default is possible.
// Example:
@@ -6301,10 +6301,9 @@ static Value *foldSwitchToSelect(const SwitchCaseResultVectorTy &ResultVector,
AndMask &= Case->getValue();
}
- ConstantRange CR = computeConstantRange(
- Condition, /* ForSigned */ Condition->getType()->isSingleValueType());
+ KnownBits Known = computeKnownBits(Condition, DL);
unsigned int ConditionWidth = Condition->getType()->getIntegerBitWidth();
- APInt ActiveBits = APInt(ConditionWidth, CR.getActiveBits(),
+ APInt ActiveBits = APInt(ConditionWidth, Known.countMaxActiveBits(),
Condition->getType()->isSingleValueType());
APInt One(ConditionWidth, 1, false);
@@ -6406,7 +6405,7 @@ static bool trySwitchToSelect(SwitchInst *SI, IRBuilder<> &Builder,
assert(PHI != nullptr && "PHI for value select not found");
Builder.SetInsertPoint(SI);
Value *SelectValue =
- foldSwitchToSelect(UniqueResults, DefaultResult, Cond, Builder);
+ foldSwitchToSelect(UniqueResults, DefaultResult, Cond, Builder, DL);
if (!SelectValue)
return false;
More information about the llvm-commits
mailing list