From dc8ea1ec5010a044548dd33cc53bd53190e4d29a Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 27 Sep 2025 15:56:24 +0800 Subject: [PATCH 01/11] Pre-commit test cases --- .../SimplifyCFG/switch-range-to-icmp.ll | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll index 8f2ae2d054f1e..73771b48e21bc 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll @@ -188,4 +188,102 @@ exit: ret void } +define i32 @wrapping_known_range(i8 range(i8 0, 6) %arg) { +; CHECK-LABEL: @wrapping_known_range( +; CHECK-NEXT: switch i8 [[ARG:%.*]], label [[ELSE:%.*]] [ +; CHECK-NEXT: i8 0, label [[IF:%.*]] +; CHECK-NEXT: i8 4, label [[IF]] +; CHECK-NEXT: i8 5, label [[IF]] +; CHECK-NEXT: ] +; CHECK: common.ret: +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[I0:%.*]], [[IF]] ], [ [[I1:%.*]], [[ELSE]] ] +; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] +; CHECK: if: +; CHECK-NEXT: [[I0]] = call i32 @f(i32 0) +; CHECK-NEXT: br label [[COMMON_RET:%.*]] +; CHECK: else: +; CHECK-NEXT: [[I1]] = call i32 @f(i32 1) +; CHECK-NEXT: br label [[COMMON_RET]] +; + switch i8 %arg, label %else [ + i8 0, label %if + i8 4, label %if + i8 5, label %if + ] + +if: + %i0 = call i32 @f(i32 0) + ret i32 %i0 + +else: + %i1 = call i32 @f(i32 1) + ret i32 %i1 +} + +define i32 @wrapping_range(i8 %arg) { +; CHECK-LABEL: @wrapping_range( +; CHECK-NEXT: switch i8 [[ARG:%.*]], label [[ELSE:%.*]] [ +; CHECK-NEXT: i8 0, label [[IF:%.*]] +; CHECK-NEXT: i8 -3, label [[IF]] +; CHECK-NEXT: i8 -2, label [[IF]] +; CHECK-NEXT: i8 -1, label [[IF]] +; CHECK-NEXT: ] +; CHECK: common.ret: +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[I0:%.*]], [[IF]] ], [ [[I1:%.*]], [[ELSE]] ] +; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] +; CHECK: if: +; CHECK-NEXT: [[I0]] = call i32 @f(i32 0) +; CHECK-NEXT: br label [[COMMON_RET:%.*]] +; CHECK: else: +; CHECK-NEXT: [[I1]] = call i32 @f(i32 1) +; CHECK-NEXT: br label [[COMMON_RET]] +; + switch i8 %arg, label %else [ + i8 0, label %if + i8 -3, label %if + i8 -2, label %if + i8 -1, label %if + ] + +if: + %i0 = call i32 @f(i32 0) + ret i32 %i0 + +else: + %i1 = call i32 @f(i32 1) + ret i32 %i1 +} + +define i32 @no_continuous_wrapping_range(i8 %arg) { +; CHECK-LABEL: @no_continuous_wrapping_range( +; CHECK-NEXT: switch i8 [[ARG:%.*]], label [[ELSE:%.*]] [ +; CHECK-NEXT: i8 0, label [[IF:%.*]] +; CHECK-NEXT: i8 -3, label [[IF]] +; CHECK-NEXT: i8 -1, label [[IF]] +; CHECK-NEXT: ] +; CHECK: common.ret: +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[I0:%.*]], [[IF]] ], [ [[I1:%.*]], [[ELSE]] ] +; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] +; CHECK: if: +; CHECK-NEXT: [[I0]] = call i32 @f(i32 0) +; CHECK-NEXT: br label [[COMMON_RET:%.*]] +; CHECK: else: +; CHECK-NEXT: [[I1]] = call i32 @f(i32 1) +; CHECK-NEXT: br label [[COMMON_RET]] +; + switch i8 %arg, label %else [ + i8 0, label %if + i8 -3, label %if + i8 -1, label %if + ] + +if: + %i0 = call i32 @f(i32 0) + ret i32 %i0 + +else: + %i1 = call i32 @f(i32 1) + ret i32 %i1 +} + declare void @bar(ptr nonnull dereferenceable(4)) From 4010221271dcd360e36317a263c3373ea39a84b6 Mon Sep 17 00:00:00 2001 From: dianqk Date: Fri, 26 Sep 2025 23:12:09 +0800 Subject: [PATCH 02/11] [SimplifyCFG] Fold the contiguous wrapping cases into ICmp. --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 73 +++++++++++++++---- .../SimplifyCFG/switch-range-to-icmp.ll | 17 ++--- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 8bba634521e3e..a208ba610cd5b 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5718,15 +5718,49 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) { return Changed; } -static bool casesAreContiguous(SmallVectorImpl &Cases) { +static bool casesAreContiguous(Value *Condition, + SmallVectorImpl &Cases, + ConstantInt *&ContiguousCasesMin, + ConstantInt *&ContiguousCasesMax, + bool &IsWrapping) { assert(Cases.size() >= 1); array_pod_sort(Cases.begin(), Cases.end(), constantIntSortPredicate); - for (size_t I = 1, E = Cases.size(); I != E; ++I) { - if (Cases[I - 1]->getValue() != Cases[I]->getValue() + 1) + auto Min = Cases.back()->getValue(); + auto Max = Cases.front()->getValue(); + auto Offset = Max - Min; + auto ContiguousOffset = Cases.size() - 1; + if (Offset == ContiguousOffset) { + ContiguousCasesMin = Cases.back(); + ContiguousCasesMax = Cases.front(); + return true; + } + ConstantRange CR = computeConstantRange(Condition, /*ForSigned=*/false); + // If this is a wrapping contiguous range, that is, [Min, OtherMin] + + // [OtherMax, Max] (also [OtherMax, OtherMin]), [OtherMin+1, OtherMax-1] is a + // contiguous range for the other destination. N.B. If CR is not a full range, + // Max+1 is not equal to Min. It's not continuous in arithmetic. + if (Max == CR.getUnsignedMax() && Min == CR.getUnsignedMin()) { + assert(Cases.size() >= 2); + auto *It = + std::adjacent_find(Cases.begin(), Cases.end(), [](auto L, auto R) { + return L->getValue() != R->getValue() + 1; + }); + if (It == Cases.end()) return false; + auto *OtherMax = *It; + auto *OtherMin = *(It + 1); + if ((Max - OtherMax->getValue()) + (OtherMin->getValue() - Min) == + Cases.size() - 2) { + ContiguousCasesMin = cast( + ConstantInt::get(OtherMin->getType(), OtherMin->getValue() + 1)); + ContiguousCasesMax = cast( + ConstantInt::get(OtherMax->getType(), OtherMax->getValue() - 1)); + IsWrapping = true; + return true; + } } - return true; + return false; } static void createUnreachableSwitchDefault(SwitchInst *Switch, @@ -5797,25 +5831,34 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, assert(!CasesA.empty() || HasDefault); // Figure out if one of the sets of cases form a contiguous range. - SmallVectorImpl *ContiguousCases = nullptr; + ConstantInt *ContiguousCasesMin = nullptr; + ConstantInt *ContiguousCasesMax = nullptr; BasicBlock *ContiguousDest = nullptr; BasicBlock *OtherDest = nullptr; - if (!CasesA.empty() && casesAreContiguous(CasesA)) { - ContiguousCases = &CasesA; + bool IsWrapping = false; + if (!CasesA.empty() && + casesAreContiguous(SI->getCondition(), CasesA, ContiguousCasesMin, + ContiguousCasesMax, IsWrapping)) { ContiguousDest = DestA; OtherDest = DestB; - } else if (casesAreContiguous(CasesB)) { - ContiguousCases = &CasesB; + } else if (casesAreContiguous(SI->getCondition(), CasesB, ContiguousCasesMin, + ContiguousCasesMax, IsWrapping)) { ContiguousDest = DestB; OtherDest = DestA; } else return false; + if (IsWrapping) + std::swap(ContiguousDest, OtherDest); + // Start building the compare and branch. - Constant *Offset = ConstantExpr::getNeg(ContiguousCases->back()); - Constant *NumCases = - ConstantInt::get(Offset->getType(), ContiguousCases->size()); + auto ContiguousCasesSize = + (ContiguousCasesMax->getValue() - ContiguousCasesMin->getValue()) + .getZExtValue() + + 1; + Constant *Offset = ConstantExpr::getNeg(ContiguousCasesMin); + Constant *NumCases = ConstantInt::get(Offset->getType(), ContiguousCasesSize); Value *Sub = SI->getCondition(); if (!Offset->isNullValue()) @@ -5823,7 +5866,7 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, Value *Cmp; // If NumCases overflowed, then all possible values jump to the successor. - if (NumCases->isNullValue() && !ContiguousCases->empty()) + if (NumCases->isNullValue() && ContiguousCasesSize != 0) Cmp = ConstantInt::getTrue(SI->getContext()); else Cmp = Builder.CreateICmpULT(Sub, NumCases, "switch"); @@ -5853,14 +5896,14 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, // Prune obsolete incoming values off the successors' PHI nodes. for (auto BBI = ContiguousDest->begin(); isa(BBI); ++BBI) { - unsigned PreviousEdges = ContiguousCases->size(); + unsigned PreviousEdges = ContiguousCasesSize; if (ContiguousDest == SI->getDefaultDest()) ++PreviousEdges; for (unsigned I = 0, E = PreviousEdges - 1; I != E; ++I) cast(BBI)->removeIncomingValue(SI->getParent()); } for (auto BBI = OtherDest->begin(); isa(BBI); ++BBI) { - unsigned PreviousEdges = SI->getNumCases() - ContiguousCases->size(); + unsigned PreviousEdges = SI->getNumCases() - ContiguousCasesSize; if (OtherDest == SI->getDefaultDest()) ++PreviousEdges; for (unsigned I = 0, E = PreviousEdges - 1; I != E; ++I) diff --git a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll index 73771b48e21bc..c6904fe273f09 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll @@ -190,11 +190,9 @@ exit: define i32 @wrapping_known_range(i8 range(i8 0, 6) %arg) { ; CHECK-LABEL: @wrapping_known_range( -; CHECK-NEXT: switch i8 [[ARG:%.*]], label [[ELSE:%.*]] [ -; CHECK-NEXT: i8 0, label [[IF:%.*]] -; CHECK-NEXT: i8 4, label [[IF]] -; CHECK-NEXT: i8 5, label [[IF]] -; CHECK-NEXT: ] +; CHECK-NEXT: [[ARG_OFF:%.*]] = add i8 [[ARG:%.*]], -1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[ARG_OFF]], 3 +; CHECK-NEXT: br i1 [[SWITCH]], label [[ELSE:%.*]], label [[IF:%.*]] ; CHECK: common.ret: ; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[I0:%.*]], [[IF]] ], [ [[I1:%.*]], [[ELSE]] ] ; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] @@ -222,12 +220,9 @@ else: define i32 @wrapping_range(i8 %arg) { ; CHECK-LABEL: @wrapping_range( -; CHECK-NEXT: switch i8 [[ARG:%.*]], label [[ELSE:%.*]] [ -; CHECK-NEXT: i8 0, label [[IF:%.*]] -; CHECK-NEXT: i8 -3, label [[IF]] -; CHECK-NEXT: i8 -2, label [[IF]] -; CHECK-NEXT: i8 -1, label [[IF]] -; CHECK-NEXT: ] +; CHECK-NEXT: [[ARG_OFF:%.*]] = add i8 [[ARG:%.*]], -1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[ARG_OFF]], -4 +; CHECK-NEXT: br i1 [[SWITCH]], label [[ELSE:%.*]], label [[IF:%.*]] ; CHECK: common.ret: ; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[I0:%.*]], [[IF]] ], [ [[I1:%.*]], [[ELSE]] ] ; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] From c56155d16d2ffcc56ee57f94bf537b0a72d0a3ea Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 27 Sep 2025 22:35:46 +0800 Subject: [PATCH 03/11] Fix the count of pruning incoming values --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 21 ++++++++++-------- .../SimplifyCFG/switch-range-to-icmp.ll | 22 +++++++++++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index a208ba610cd5b..eae32471ad03b 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5836,6 +5836,8 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, BasicBlock *ContiguousDest = nullptr; BasicBlock *OtherDest = nullptr; bool IsWrapping = false; + SmallVectorImpl *ContiguousCases = &CasesA; + SmallVectorImpl *OtherCases = &CasesB; if (!CasesA.empty() && casesAreContiguous(SI->getCondition(), CasesA, ContiguousCasesMin, ContiguousCasesMax, IsWrapping)) { @@ -5845,20 +5847,21 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, ContiguousCasesMax, IsWrapping)) { ContiguousDest = DestB; OtherDest = DestA; + std::swap(ContiguousCases, OtherCases); } else return false; - if (IsWrapping) + if (IsWrapping) { std::swap(ContiguousDest, OtherDest); + std::swap(ContiguousCases, OtherCases); + } // Start building the compare and branch. - auto ContiguousCasesSize = - (ContiguousCasesMax->getValue() - ContiguousCasesMin->getValue()) - .getZExtValue() + - 1; Constant *Offset = ConstantExpr::getNeg(ContiguousCasesMin); - Constant *NumCases = ConstantInt::get(Offset->getType(), ContiguousCasesSize); + Constant *NumCases = ConstantInt::get(Offset->getType(), + ContiguousCasesMax->getValue() - + ContiguousCasesMin->getValue() + 1); Value *Sub = SI->getCondition(); if (!Offset->isNullValue()) @@ -5866,7 +5869,7 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, Value *Cmp; // If NumCases overflowed, then all possible values jump to the successor. - if (NumCases->isNullValue() && ContiguousCasesSize != 0) + if (NumCases->isNullValue() && !ContiguousCases->empty()) Cmp = ConstantInt::getTrue(SI->getContext()); else Cmp = Builder.CreateICmpULT(Sub, NumCases, "switch"); @@ -5896,14 +5899,14 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, // Prune obsolete incoming values off the successors' PHI nodes. for (auto BBI = ContiguousDest->begin(); isa(BBI); ++BBI) { - unsigned PreviousEdges = ContiguousCasesSize; + unsigned PreviousEdges = ContiguousCases->size(); if (ContiguousDest == SI->getDefaultDest()) ++PreviousEdges; for (unsigned I = 0, E = PreviousEdges - 1; I != E; ++I) cast(BBI)->removeIncomingValue(SI->getParent()); } for (auto BBI = OtherDest->begin(); isa(BBI); ++BBI) { - unsigned PreviousEdges = SI->getNumCases() - ContiguousCasesSize; + unsigned PreviousEdges = OtherCases->size(); if (OtherDest == SI->getDefaultDest()) ++PreviousEdges; for (unsigned I = 0, E = PreviousEdges - 1; I != E; ++I) diff --git a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll index c6904fe273f09..c9d9e9abdcba9 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll @@ -249,6 +249,28 @@ else: ret i32 %i1 } +define i8 @wrapping_range_phi(i8 %arg) { +; CHECK-LABEL: @wrapping_range_phi( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[ARG_OFF:%.*]] = add i8 [[ARG:%.*]], -1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[ARG_OFF]], -2 +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[SWITCH]], i8 0, i8 1 +; CHECK-NEXT: ret i8 [[SPEC_SELECT]] +; +entry: + switch i8 %arg, label %else [ + i8 0, label %if + i8 -1, label %if + ] + +if: + %i = phi i8 [ 0, %else ], [ 1, %entry ], [ 1, %entry ] + ret i8 %i + +else: + br label %if +} + define i32 @no_continuous_wrapping_range(i8 %arg) { ; CHECK-LABEL: @no_continuous_wrapping_range( ; CHECK-NEXT: switch i8 [[ARG:%.*]], label [[ELSE:%.*]] [ From 41c4da0887d037223b49c1f15d05e0fa743371b0 Mon Sep 17 00:00:00 2001 From: dianqk Date: Thu, 2 Oct 2025 20:28:56 +0800 Subject: [PATCH 04/11] [SimplifyCFG] Cases to the default destination cannot be contiguous cases --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index eae32471ad03b..d427aae77a75e 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5838,7 +5838,8 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, bool IsWrapping = false; SmallVectorImpl *ContiguousCases = &CasesA; SmallVectorImpl *OtherCases = &CasesB; - if (!CasesA.empty() && + // Correctness: Cases to the default destination cannot be contiguous cases. + if (!HasDefault && !CasesA.empty() && casesAreContiguous(SI->getCondition(), CasesA, ContiguousCasesMin, ContiguousCasesMax, IsWrapping)) { ContiguousDest = DestA; From 0ce3e6eac8f589686b23de75b7cbc6e9b4ca108e Mon Sep 17 00:00:00 2001 From: dianqk Date: Fri, 3 Oct 2025 13:17:01 +0800 Subject: [PATCH 05/11] Add more tests --- .../SimplifyCFG/switch-range-to-icmp.ll | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll index c9d9e9abdcba9..b715bf8d037f0 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll @@ -303,4 +303,73 @@ else: ret i32 %i1 } +define i32 @one_case_1(i32 %x) { +; CHECK-LABEL: @one_case_1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -5 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 3 +; CHECK-NEXT: br i1 [[SWITCH]], label [[A:%.*]], label [[B:%.*]] +; CHECK: common.ret: +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[TMP0:%.*]], [[A]] ], [ [[TMP1:%.*]], [[B]] ] +; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] +; CHECK: a: +; CHECK-NEXT: [[TMP0]] = call i32 @f(i32 0) +; CHECK-NEXT: br label [[COMMON_RET:%.*]] +; CHECK: b: +; CHECK-NEXT: [[TMP1]] = call i32 @f(i32 1) +; CHECK-NEXT: br label [[COMMON_RET]] +; +entry: + switch i32 %x, label %unreachable [ + i32 5, label %a + i32 6, label %a + i32 7, label %a + i32 10, label %b + ] + +unreachable: + unreachable +a: + %0 = call i32 @f(i32 0) + ret i32 %0 +b: + %1 = call i32 @f(i32 1) + ret i32 %1 +} + +define i32 @one_case_2(i32 %x) { +; CHECK-LABEL: @one_case_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -5 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 1 +; CHECK-NEXT: br i1 [[SWITCH]], label [[A:%.*]], label [[B:%.*]] +; CHECK: common.ret: +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[TMP0:%.*]], [[A]] ], [ [[TMP1:%.*]], [[B]] ] +; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] +; CHECK: a: +; CHECK-NEXT: [[TMP0]] = call i32 @f(i32 0) +; CHECK-NEXT: br label [[COMMON_RET:%.*]] +; CHECK: b: +; CHECK-NEXT: [[TMP1]] = call i32 @f(i32 1) +; CHECK-NEXT: br label [[COMMON_RET]] +; +entry: + switch i32 %x, label %unreachable [ + i32 5, label %a + i32 10, label %b + i32 11, label %b + i32 12, label %b + i32 13, label %b + ] + +unreachable: + unreachable +a: + %0 = call i32 @f(i32 0) + ret i32 %0 +b: + %1 = call i32 @f(i32 1) + ret i32 %1 +} + declare void @bar(ptr nonnull dereferenceable(4)) From dd4fdf60a9d11b96b3162ad143d709144ae78946 Mon Sep 17 00:00:00 2001 From: dianqk Date: Fri, 3 Oct 2025 13:18:45 +0800 Subject: [PATCH 06/11] [SimplifyCFG] Improve one case --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 20 ++++++++++++++++--- .../SimplifyCFG/switch-range-to-icmp.ll | 6 +++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index d427aae77a75e..0f3f1befd6c05 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5838,10 +5838,24 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, bool IsWrapping = false; SmallVectorImpl *ContiguousCases = &CasesA; SmallVectorImpl *OtherCases = &CasesB; + + // Only one icmp is needed when there is only one case. + if (!HasDefault && CasesA.size() == 1) { + ContiguousCasesMax = CasesA[0]; + ContiguousCasesMin = CasesA[0]; + ContiguousDest = DestA; + OtherDest = DestB; + } else if (CasesB.size() == 1) { + ContiguousCasesMax = CasesB[0]; + ContiguousCasesMin = CasesB[0]; + ContiguousDest = DestB; + OtherDest = DestA; + std::swap(ContiguousCases, OtherCases); + } // Correctness: Cases to the default destination cannot be contiguous cases. - if (!HasDefault && !CasesA.empty() && - casesAreContiguous(SI->getCondition(), CasesA, ContiguousCasesMin, - ContiguousCasesMax, IsWrapping)) { + else if (!HasDefault && !CasesA.empty() && + casesAreContiguous(SI->getCondition(), CasesA, ContiguousCasesMin, + ContiguousCasesMax, IsWrapping)) { ContiguousDest = DestA; OtherDest = DestB; } else if (casesAreContiguous(SI->getCondition(), CasesB, ContiguousCasesMin, diff --git a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll index b715bf8d037f0..9cb24904b6a18 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll @@ -306,11 +306,11 @@ else: define i32 @one_case_1(i32 %x) { ; CHECK-LABEL: @one_case_1( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -5 -; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 3 +; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -10 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 1 ; CHECK-NEXT: br i1 [[SWITCH]], label [[A:%.*]], label [[B:%.*]] ; CHECK: common.ret: -; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[TMP0:%.*]], [[A]] ], [ [[TMP1:%.*]], [[B]] ] +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[TMP0:%.*]], [[B]] ], [ [[TMP1:%.*]], [[A]] ] ; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] ; CHECK: a: ; CHECK-NEXT: [[TMP0]] = call i32 @f(i32 0) From bfc9e920f57c69e1e288399b9feaa043e768fc83 Mon Sep 17 00:00:00 2001 From: dianqk Date: Fri, 3 Oct 2025 13:50:22 +0800 Subject: [PATCH 07/11] Add more tests --- .../SimplifyCFG/switch-range-to-icmp.ll | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll index 9cb24904b6a18..c9438133352da 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll @@ -218,6 +218,38 @@ else: ret i32 %i1 } +define i32 @wrapping_known_range_2(i8 range(i8 0, 6) %arg) { +; CHECK-LABEL: @wrapping_known_range_2( +; CHECK-NEXT: [[ARG_OFF:%.*]] = add i8 [[ARG:%.*]], -1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[ARG_OFF]], 1 +; CHECK-NEXT: br i1 [[SWITCH]], label [[ELSE:%.*]], label [[IF:%.*]] +; CHECK: common.ret: +; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[I0:%.*]], [[IF]] ], [ [[I1:%.*]], [[ELSE]] ] +; CHECK-NEXT: ret i32 [[COMMON_RET_OP]] +; CHECK: if: +; CHECK-NEXT: [[I0]] = call i32 @f(i32 0) +; CHECK-NEXT: br label [[COMMON_RET:%.*]] +; CHECK: else: +; CHECK-NEXT: [[I1]] = call i32 @f(i32 1) +; CHECK-NEXT: br label [[COMMON_RET]] +; + switch i8 %arg, label %else [ + i8 0, label %if + i8 2, label %if + i8 3, label %if + i8 4, label %if + i8 5, label %if + ] + +if: + %i0 = call i32 @f(i32 0) + ret i32 %i0 + +else: + %i1 = call i32 @f(i32 1) + ret i32 %i1 +} + define i32 @wrapping_range(i8 %arg) { ; CHECK-LABEL: @wrapping_range( ; CHECK-NEXT: [[ARG_OFF:%.*]] = add i8 [[ARG:%.*]], -1 From 9864e17297498ca100cf8c3d56beb05f7e36ea13 Mon Sep 17 00:00:00 2001 From: dianqk Date: Fri, 3 Oct 2025 18:46:14 +0800 Subject: [PATCH 08/11] [SimplifyCFG] Use icmp eq for one case --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 26 +++++++++++-------- .../Coroutines/coro-catchswitch-cleanuppad.ll | 4 +-- .../SimplifyCFG/switch-dead-default.ll | 12 +++------ .../SimplifyCFG/switch-range-to-icmp.ll | 9 +++---- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 0f3f1befd6c05..c51e7ae89dac0 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5877,18 +5877,22 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, Constant *NumCases = ConstantInt::get(Offset->getType(), ContiguousCasesMax->getValue() - ContiguousCasesMin->getValue() + 1); - - Value *Sub = SI->getCondition(); - if (!Offset->isNullValue()) - Sub = Builder.CreateAdd(Sub, Offset, Sub->getName() + ".off"); - - Value *Cmp; + BranchInst *NewBI; + if (NumCases->isOneValue()) { + assert(ContiguousCasesMax->getValue() == ContiguousCasesMin->getValue()); + Value *Cmp = Builder.CreateICmpEQ(SI->getCondition(), ContiguousCasesMin); + NewBI = Builder.CreateCondBr(Cmp, ContiguousDest, OtherDest); + } // If NumCases overflowed, then all possible values jump to the successor. - if (NumCases->isNullValue() && !ContiguousCases->empty()) - Cmp = ConstantInt::getTrue(SI->getContext()); - else - Cmp = Builder.CreateICmpULT(Sub, NumCases, "switch"); - BranchInst *NewBI = Builder.CreateCondBr(Cmp, ContiguousDest, OtherDest); + else if (NumCases->isNullValue() && !ContiguousCases->empty()) { + NewBI = Builder.CreateBr(ContiguousDest); + } else { + Value *Sub = SI->getCondition(); + if (!Offset->isNullValue()) + Sub = Builder.CreateAdd(Sub, Offset, Sub->getName() + ".off"); + Value *Cmp = Builder.CreateICmpULT(Sub, NumCases, "switch"); + NewBI = Builder.CreateCondBr(Cmp, ContiguousDest, OtherDest); + } // Update weight for the newly-created conditional branch. if (hasBranchWeightMD(*SI)) { diff --git a/llvm/test/Transforms/Coroutines/coro-catchswitch-cleanuppad.ll b/llvm/test/Transforms/Coroutines/coro-catchswitch-cleanuppad.ll index d0e7c1c29eb32..e1e1611ee3362 100644 --- a/llvm/test/Transforms/Coroutines/coro-catchswitch-cleanuppad.ll +++ b/llvm/test/Transforms/Coroutines/coro-catchswitch-cleanuppad.ll @@ -80,8 +80,8 @@ cleanup2: ; CHECK: cleanup2.corodispatch: ; CHECK: %1 = phi i8 [ 0, %handler2 ], [ 1, %catch.dispatch.2 ] ; CHECK: %2 = cleanuppad within %h1 [] -; CHECK: %switch = icmp ult i8 %1, 1 -; CHECK: br i1 %switch, label %cleanup2.from.handler2, label %cleanup2.from.catch.dispatch.2 +; CHECK: %3 = icmp eq i8 %1, 0 +; CHECK: br i1 %3, label %cleanup2.from.handler2, label %cleanup2.from.catch.dispatch.2 ; CHECK: cleanup2.from.handler2: ; CHECK: %valueB.reload = load i32, ptr %valueB.spill.addr, align 4 diff --git a/llvm/test/Transforms/SimplifyCFG/switch-dead-default.ll b/llvm/test/Transforms/SimplifyCFG/switch-dead-default.ll index 4a457cc177e85..a0e29dd19dd84 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch-dead-default.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch-dead-default.ll @@ -7,8 +7,7 @@ declare void @foo(i32) define void @test(i1 %a) { ; CHECK-LABEL: define void @test( ; CHECK-SAME: i1 [[A:%.*]]) { -; CHECK-NEXT: [[A_OFF:%.*]] = add i1 [[A]], true -; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i1 [[A_OFF]], true +; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i1 [[A]], true ; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: common.ret: ; CHECK-NEXT: ret void @@ -209,8 +208,7 @@ define void @test5(i8 %a) { ; CHECK-SAME: i8 [[A:%.*]]) { ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[A]], 2 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) -; CHECK-NEXT: [[A_OFF:%.*]] = add i8 [[A]], -1 -; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[A_OFF]], 1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i8 [[A]], 1 ; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: common.ret: ; CHECK-NEXT: ret void @@ -243,8 +241,7 @@ define void @test6(i8 %a) { ; CHECK-NEXT: [[AND:%.*]] = and i8 [[A]], -2 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[AND]], -2 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) -; CHECK-NEXT: [[A_OFF:%.*]] = add i8 [[A]], 1 -; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[A_OFF]], 1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i8 [[A]], -1 ; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: common.ret: ; CHECK-NEXT: ret void @@ -279,8 +276,7 @@ define void @test7(i8 %a) { ; CHECK-NEXT: [[AND:%.*]] = and i8 [[A]], -2 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[AND]], -2 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) -; CHECK-NEXT: [[A_OFF:%.*]] = add i8 [[A]], 1 -; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[A_OFF]], 1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i8 [[A]], -1 ; CHECK-NEXT: br i1 [[SWITCH]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: common.ret: ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll index c9438133352da..0fc3c19edd1f3 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll @@ -220,8 +220,7 @@ else: define i32 @wrapping_known_range_2(i8 range(i8 0, 6) %arg) { ; CHECK-LABEL: @wrapping_known_range_2( -; CHECK-NEXT: [[ARG_OFF:%.*]] = add i8 [[ARG:%.*]], -1 -; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[ARG_OFF]], 1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i8 [[ARG:%.*]], 1 ; CHECK-NEXT: br i1 [[SWITCH]], label [[ELSE:%.*]], label [[IF:%.*]] ; CHECK: common.ret: ; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[I0:%.*]], [[IF]] ], [ [[I1:%.*]], [[ELSE]] ] @@ -338,8 +337,7 @@ else: define i32 @one_case_1(i32 %x) { ; CHECK-LABEL: @one_case_1( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -10 -; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i32 [[X:%.*]], 10 ; CHECK-NEXT: br i1 [[SWITCH]], label [[A:%.*]], label [[B:%.*]] ; CHECK: common.ret: ; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[TMP0:%.*]], [[B]] ], [ [[TMP1:%.*]], [[A]] ] @@ -372,8 +370,7 @@ b: define i32 @one_case_2(i32 %x) { ; CHECK-LABEL: @one_case_2( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X:%.*]], -5 -; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 1 +; CHECK-NEXT: [[SWITCH:%.*]] = icmp eq i32 [[X:%.*]], 5 ; CHECK-NEXT: br i1 [[SWITCH]], label [[A:%.*]], label [[B:%.*]] ; CHECK: common.ret: ; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[TMP0:%.*]], [[A]] ], [ [[TMP1:%.*]], [[B]] ] From 2288724c860a9380f13ed6010a29df5aaefcf378 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 4 Oct 2025 14:23:37 +0800 Subject: [PATCH 09/11] Address feedback --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 153 ++++++++++++---------- 1 file changed, 83 insertions(+), 70 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index c51e7ae89dac0..fc24246718d2b 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5718,22 +5718,35 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) { return Changed; } -static bool casesAreContiguous(Value *Condition, - SmallVectorImpl &Cases, - ConstantInt *&ContiguousCasesMin, - ConstantInt *&ContiguousCasesMax, - bool &IsWrapping) { +struct ContiguousCasesResult { + ConstantInt *Min; + ConstantInt *Max; + BasicBlock *Dest; + BasicBlock *OtherDest; + SmallVectorImpl *Cases; + SmallVectorImpl *OtherCases; +}; + +static std::optional +findContiguousCases(Value *Condition, SmallVectorImpl &Cases, + SmallVectorImpl &OtherCases, + BasicBlock *Dest, BasicBlock *OtherDest) { assert(Cases.size() >= 1); array_pod_sort(Cases.begin(), Cases.end(), constantIntSortPredicate); - auto Min = Cases.back()->getValue(); - auto Max = Cases.front()->getValue(); - auto Offset = Max - Min; - auto ContiguousOffset = Cases.size() - 1; + APInt Min = Cases.back()->getValue(); + APInt Max = Cases.front()->getValue(); + APInt Offset = Max - Min; + size_t ContiguousOffset = Cases.size() - 1; if (Offset == ContiguousOffset) { - ContiguousCasesMin = Cases.back(); - ContiguousCasesMax = Cases.front(); - return true; + return ContiguousCasesResult{ + /*Min=*/Cases.back(), + /*Max=*/Cases.front(), + /*Dest=*/Dest, + /*OtherDest=*/OtherDest, + /*Cases=*/&Cases, + /*OtherCases=*/&OtherCases, + }; } ConstantRange CR = computeConstantRange(Condition, /*ForSigned=*/false); // If this is a wrapping contiguous range, that is, [Min, OtherMin] + @@ -5747,20 +5760,24 @@ static bool casesAreContiguous(Value *Condition, return L->getValue() != R->getValue() + 1; }); if (It == Cases.end()) - return false; - auto *OtherMax = *It; - auto *OtherMin = *(It + 1); + return std::nullopt; + auto [OtherMax, OtherMin] = std::make_pair(*It, *std::next(It)); if ((Max - OtherMax->getValue()) + (OtherMin->getValue() - Min) == Cases.size() - 2) { - ContiguousCasesMin = cast( - ConstantInt::get(OtherMin->getType(), OtherMin->getValue() + 1)); - ContiguousCasesMax = cast( - ConstantInt::get(OtherMax->getType(), OtherMax->getValue() - 1)); - IsWrapping = true; - return true; + return ContiguousCasesResult{ + /*Min=*/cast( + ConstantInt::get(OtherMin->getType(), OtherMin->getValue() + 1)), + /*Max=*/ + cast( + ConstantInt::get(OtherMax->getType(), OtherMax->getValue() - 1)), + /*Dest=*/OtherDest, + /*OtherDest=*/Dest, + /*Cases=*/&OtherCases, + /*OtherCases=*/&Cases, + }; } } - return false; + return std::nullopt; } static void createUnreachableSwitchDefault(SwitchInst *Switch, @@ -5797,7 +5814,6 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, bool HasDefault = !SI->defaultDestUnreachable(); auto *BB = SI->getParent(); - // Partition the cases into two sets with different destinations. BasicBlock *DestA = HasDefault ? SI->getDefaultDest() : nullptr; BasicBlock *DestB = nullptr; @@ -5831,67 +5847,64 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, assert(!CasesA.empty() || HasDefault); // Figure out if one of the sets of cases form a contiguous range. - ConstantInt *ContiguousCasesMin = nullptr; - ConstantInt *ContiguousCasesMax = nullptr; - BasicBlock *ContiguousDest = nullptr; - BasicBlock *OtherDest = nullptr; - bool IsWrapping = false; - SmallVectorImpl *ContiguousCases = &CasesA; - SmallVectorImpl *OtherCases = &CasesB; + std::optional ContiguousCases; // Only one icmp is needed when there is only one case. - if (!HasDefault && CasesA.size() == 1) { - ContiguousCasesMax = CasesA[0]; - ContiguousCasesMin = CasesA[0]; - ContiguousDest = DestA; - OtherDest = DestB; - } else if (CasesB.size() == 1) { - ContiguousCasesMax = CasesB[0]; - ContiguousCasesMin = CasesB[0]; - ContiguousDest = DestB; - OtherDest = DestA; - std::swap(ContiguousCases, OtherCases); - } + if (!HasDefault && CasesA.size() == 1) + ContiguousCases = ContiguousCasesResult{ + /*Min=*/CasesA[0], + /*Max=*/CasesA[0], + /*Dest=*/DestA, + /*OtherDest=*/DestB, + /*Cases=*/&CasesA, + /*OtherCases=*/&CasesB, + }; + else if (CasesB.size() == 1) + ContiguousCases = ContiguousCasesResult{ + /*Min=*/CasesB[0], + /*Max=*/CasesB[0], + /*Dest=*/DestB, + /*OtherDest=*/DestA, + /*Cases=*/&CasesB, + /*OtherCases=*/&CasesA, + }; + // Correctness: Cases to the default destination cannot be contiguous cases. - else if (!HasDefault && !CasesA.empty() && - casesAreContiguous(SI->getCondition(), CasesA, ContiguousCasesMin, - ContiguousCasesMax, IsWrapping)) { - ContiguousDest = DestA; - OtherDest = DestB; - } else if (casesAreContiguous(SI->getCondition(), CasesB, ContiguousCasesMin, - ContiguousCasesMax, IsWrapping)) { - ContiguousDest = DestB; - OtherDest = DestA; - std::swap(ContiguousCases, OtherCases); - } else + if (!ContiguousCases && !HasDefault && !CasesA.empty()) + if (auto Result = findContiguousCases(SI->getCondition(), CasesA, CasesB, + DestA, DestB)) + ContiguousCases = *Result; + + if (!ContiguousCases) + if (auto Result = findContiguousCases(SI->getCondition(), CasesB, CasesA, + DestB, DestA)) + ContiguousCases = *Result; + + if (!ContiguousCases) return false; - if (IsWrapping) { - std::swap(ContiguousDest, OtherDest); - std::swap(ContiguousCases, OtherCases); - } + auto [Min, Max, Dest, OtherDest, Cases, OtherCases] = *ContiguousCases; // Start building the compare and branch. - Constant *Offset = ConstantExpr::getNeg(ContiguousCasesMin); + Constant *Offset = ConstantExpr::getNeg(Min); Constant *NumCases = ConstantInt::get(Offset->getType(), - ContiguousCasesMax->getValue() - - ContiguousCasesMin->getValue() + 1); + Max->getValue() - Min->getValue() + 1); BranchInst *NewBI; if (NumCases->isOneValue()) { - assert(ContiguousCasesMax->getValue() == ContiguousCasesMin->getValue()); - Value *Cmp = Builder.CreateICmpEQ(SI->getCondition(), ContiguousCasesMin); - NewBI = Builder.CreateCondBr(Cmp, ContiguousDest, OtherDest); + assert(Max->getValue() == Min->getValue()); + Value *Cmp = Builder.CreateICmpEQ(SI->getCondition(), Min); + NewBI = Builder.CreateCondBr(Cmp, Dest, OtherDest); } // If NumCases overflowed, then all possible values jump to the successor. - else if (NumCases->isNullValue() && !ContiguousCases->empty()) { - NewBI = Builder.CreateBr(ContiguousDest); + else if (NumCases->isNullValue() && !Cases->empty()) { + NewBI = Builder.CreateBr(Dest); } else { Value *Sub = SI->getCondition(); if (!Offset->isNullValue()) Sub = Builder.CreateAdd(Sub, Offset, Sub->getName() + ".off"); Value *Cmp = Builder.CreateICmpULT(Sub, NumCases, "switch"); - NewBI = Builder.CreateCondBr(Cmp, ContiguousDest, OtherDest); + NewBI = Builder.CreateCondBr(Cmp, Dest, OtherDest); } // Update weight for the newly-created conditional branch. @@ -5902,7 +5915,7 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, uint64_t TrueWeight = 0; uint64_t FalseWeight = 0; for (size_t I = 0, E = Weights.size(); I != E; ++I) { - if (SI->getSuccessor(I) == ContiguousDest) + if (SI->getSuccessor(I) == Dest) TrueWeight += Weights[I]; else FalseWeight += Weights[I]; @@ -5917,9 +5930,9 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, } // Prune obsolete incoming values off the successors' PHI nodes. - for (auto BBI = ContiguousDest->begin(); isa(BBI); ++BBI) { - unsigned PreviousEdges = ContiguousCases->size(); - if (ContiguousDest == SI->getDefaultDest()) + for (auto BBI = Dest->begin(); isa(BBI); ++BBI) { + unsigned PreviousEdges = Cases->size(); + if (Dest == SI->getDefaultDest()) ++PreviousEdges; for (unsigned I = 0, E = PreviousEdges - 1; I != E; ++I) cast(BBI)->removeIncomingValue(SI->getParent()); From 7c8dcd05d9f63ad33897a1cb04be48f2ac319a04 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sun, 5 Oct 2025 14:33:08 +0800 Subject: [PATCH 10/11] Address feedback --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index fc24246718d2b..075f1186bfbfd 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5868,17 +5868,14 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI, /*Cases=*/&CasesB, /*OtherCases=*/&CasesA, }; - // Correctness: Cases to the default destination cannot be contiguous cases. - if (!ContiguousCases && !HasDefault && !CasesA.empty()) - if (auto Result = findContiguousCases(SI->getCondition(), CasesA, CasesB, - DestA, DestB)) - ContiguousCases = *Result; + else if (!HasDefault) + ContiguousCases = + findContiguousCases(SI->getCondition(), CasesA, CasesB, DestA, DestB); if (!ContiguousCases) - if (auto Result = findContiguousCases(SI->getCondition(), CasesB, CasesA, - DestB, DestA)) - ContiguousCases = *Result; + ContiguousCases = + findContiguousCases(SI->getCondition(), CasesB, CasesA, DestB, DestA); if (!ContiguousCases) return false; From b89285e2098ff83d48ea3a088ae48c04b3786d48 Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 6 Oct 2025 12:28:38 +0800 Subject: [PATCH 11/11] Address feedback --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 075f1186bfbfd..debfe914ec803 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5734,8 +5734,8 @@ findContiguousCases(Value *Condition, SmallVectorImpl &Cases, assert(Cases.size() >= 1); array_pod_sort(Cases.begin(), Cases.end(), constantIntSortPredicate); - APInt Min = Cases.back()->getValue(); - APInt Max = Cases.front()->getValue(); + const APInt &Min = Cases.back()->getValue(); + const APInt &Max = Cases.front()->getValue(); APInt Offset = Max - Min; size_t ContiguousOffset = Cases.size() - 1; if (Offset == ContiguousOffset) {