[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
Sun Jun 22 06:42:59 PDT 2025


https://github.com/spaits created https://github.com/llvm/llvm-project/pull/145233

My attempt to fix #141753 .

I was also thinking about addressing this pattern in inst combine. There was a previous commit, that adresses a very similar pattern to this https://github.com/llvm/llvm-project/commit/902acde34198bb11cc758dcf3aee00eb1cb09ceb, 
but I think it would be better if we wouldn't even get to the point of emitting this pattern.

This patch introduces a new check, that tries to decide if the conjunction of all the values uniquely identify the accepted values by the switch.

I am also open to different solution. If you think this approach is not the best and have a different idea I would also be happy to implement that.

>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] 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
+}
+



More information about the llvm-commits mailing list