Skip to content

Commit 4010221

Browse files
committed
[SimplifyCFG] Fold the contiguous wrapping cases into ICmp.
1 parent dc8ea1e commit 4010221

File tree

2 files changed

+64
-26
lines changed

2 files changed

+64
-26
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5718,15 +5718,49 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) {
57185718
return Changed;
57195719
}
57205720

5721-
static bool casesAreContiguous(SmallVectorImpl<ConstantInt *> &Cases) {
5721+
static bool casesAreContiguous(Value *Condition,
5722+
SmallVectorImpl<ConstantInt *> &Cases,
5723+
ConstantInt *&ContiguousCasesMin,
5724+
ConstantInt *&ContiguousCasesMax,
5725+
bool &IsWrapping) {
57225726
assert(Cases.size() >= 1);
57235727

57245728
array_pod_sort(Cases.begin(), Cases.end(), constantIntSortPredicate);
5725-
for (size_t I = 1, E = Cases.size(); I != E; ++I) {
5726-
if (Cases[I - 1]->getValue() != Cases[I]->getValue() + 1)
5729+
auto Min = Cases.back()->getValue();
5730+
auto Max = Cases.front()->getValue();
5731+
auto Offset = Max - Min;
5732+
auto ContiguousOffset = Cases.size() - 1;
5733+
if (Offset == ContiguousOffset) {
5734+
ContiguousCasesMin = Cases.back();
5735+
ContiguousCasesMax = Cases.front();
5736+
return true;
5737+
}
5738+
ConstantRange CR = computeConstantRange(Condition, /*ForSigned=*/false);
5739+
// If this is a wrapping contiguous range, that is, [Min, OtherMin] +
5740+
// [OtherMax, Max] (also [OtherMax, OtherMin]), [OtherMin+1, OtherMax-1] is a
5741+
// contiguous range for the other destination. N.B. If CR is not a full range,
5742+
// Max+1 is not equal to Min. It's not continuous in arithmetic.
5743+
if (Max == CR.getUnsignedMax() && Min == CR.getUnsignedMin()) {
5744+
assert(Cases.size() >= 2);
5745+
auto *It =
5746+
std::adjacent_find(Cases.begin(), Cases.end(), [](auto L, auto R) {
5747+
return L->getValue() != R->getValue() + 1;
5748+
});
5749+
if (It == Cases.end())
57275750
return false;
5751+
auto *OtherMax = *It;
5752+
auto *OtherMin = *(It + 1);
5753+
if ((Max - OtherMax->getValue()) + (OtherMin->getValue() - Min) ==
5754+
Cases.size() - 2) {
5755+
ContiguousCasesMin = cast<ConstantInt>(
5756+
ConstantInt::get(OtherMin->getType(), OtherMin->getValue() + 1));
5757+
ContiguousCasesMax = cast<ConstantInt>(
5758+
ConstantInt::get(OtherMax->getType(), OtherMax->getValue() - 1));
5759+
IsWrapping = true;
5760+
return true;
5761+
}
57285762
}
5729-
return true;
5763+
return false;
57305764
}
57315765

57325766
static void createUnreachableSwitchDefault(SwitchInst *Switch,
@@ -5797,33 +5831,42 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI,
57975831
assert(!CasesA.empty() || HasDefault);
57985832

57995833
// Figure out if one of the sets of cases form a contiguous range.
5800-
SmallVectorImpl<ConstantInt *> *ContiguousCases = nullptr;
5834+
ConstantInt *ContiguousCasesMin = nullptr;
5835+
ConstantInt *ContiguousCasesMax = nullptr;
58015836
BasicBlock *ContiguousDest = nullptr;
58025837
BasicBlock *OtherDest = nullptr;
5803-
if (!CasesA.empty() && casesAreContiguous(CasesA)) {
5804-
ContiguousCases = &CasesA;
5838+
bool IsWrapping = false;
5839+
if (!CasesA.empty() &&
5840+
casesAreContiguous(SI->getCondition(), CasesA, ContiguousCasesMin,
5841+
ContiguousCasesMax, IsWrapping)) {
58055842
ContiguousDest = DestA;
58065843
OtherDest = DestB;
5807-
} else if (casesAreContiguous(CasesB)) {
5808-
ContiguousCases = &CasesB;
5844+
} else if (casesAreContiguous(SI->getCondition(), CasesB, ContiguousCasesMin,
5845+
ContiguousCasesMax, IsWrapping)) {
58095846
ContiguousDest = DestB;
58105847
OtherDest = DestA;
58115848
} else
58125849
return false;
58135850

5851+
if (IsWrapping)
5852+
std::swap(ContiguousDest, OtherDest);
5853+
58145854
// Start building the compare and branch.
58155855

5816-
Constant *Offset = ConstantExpr::getNeg(ContiguousCases->back());
5817-
Constant *NumCases =
5818-
ConstantInt::get(Offset->getType(), ContiguousCases->size());
5856+
auto ContiguousCasesSize =
5857+
(ContiguousCasesMax->getValue() - ContiguousCasesMin->getValue())
5858+
.getZExtValue() +
5859+
1;
5860+
Constant *Offset = ConstantExpr::getNeg(ContiguousCasesMin);
5861+
Constant *NumCases = ConstantInt::get(Offset->getType(), ContiguousCasesSize);
58195862

58205863
Value *Sub = SI->getCondition();
58215864
if (!Offset->isNullValue())
58225865
Sub = Builder.CreateAdd(Sub, Offset, Sub->getName() + ".off");
58235866

58245867
Value *Cmp;
58255868
// If NumCases overflowed, then all possible values jump to the successor.
5826-
if (NumCases->isNullValue() && !ContiguousCases->empty())
5869+
if (NumCases->isNullValue() && ContiguousCasesSize != 0)
58275870
Cmp = ConstantInt::getTrue(SI->getContext());
58285871
else
58295872
Cmp = Builder.CreateICmpULT(Sub, NumCases, "switch");
@@ -5853,14 +5896,14 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI,
58535896

58545897
// Prune obsolete incoming values off the successors' PHI nodes.
58555898
for (auto BBI = ContiguousDest->begin(); isa<PHINode>(BBI); ++BBI) {
5856-
unsigned PreviousEdges = ContiguousCases->size();
5899+
unsigned PreviousEdges = ContiguousCasesSize;
58575900
if (ContiguousDest == SI->getDefaultDest())
58585901
++PreviousEdges;
58595902
for (unsigned I = 0, E = PreviousEdges - 1; I != E; ++I)
58605903
cast<PHINode>(BBI)->removeIncomingValue(SI->getParent());
58615904
}
58625905
for (auto BBI = OtherDest->begin(); isa<PHINode>(BBI); ++BBI) {
5863-
unsigned PreviousEdges = SI->getNumCases() - ContiguousCases->size();
5906+
unsigned PreviousEdges = SI->getNumCases() - ContiguousCasesSize;
58645907
if (OtherDest == SI->getDefaultDest())
58655908
++PreviousEdges;
58665909
for (unsigned I = 0, E = PreviousEdges - 1; I != E; ++I)

llvm/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,9 @@ exit:
190190

191191
define i32 @wrapping_known_range(i8 range(i8 0, 6) %arg) {
192192
; CHECK-LABEL: @wrapping_known_range(
193-
; CHECK-NEXT: switch i8 [[ARG:%.*]], label [[ELSE:%.*]] [
194-
; CHECK-NEXT: i8 0, label [[IF:%.*]]
195-
; CHECK-NEXT: i8 4, label [[IF]]
196-
; CHECK-NEXT: i8 5, label [[IF]]
197-
; CHECK-NEXT: ]
193+
; CHECK-NEXT: [[ARG_OFF:%.*]] = add i8 [[ARG:%.*]], -1
194+
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[ARG_OFF]], 3
195+
; CHECK-NEXT: br i1 [[SWITCH]], label [[ELSE:%.*]], label [[IF:%.*]]
198196
; CHECK: common.ret:
199197
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[I0:%.*]], [[IF]] ], [ [[I1:%.*]], [[ELSE]] ]
200198
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
@@ -222,12 +220,9 @@ else:
222220

223221
define i32 @wrapping_range(i8 %arg) {
224222
; CHECK-LABEL: @wrapping_range(
225-
; CHECK-NEXT: switch i8 [[ARG:%.*]], label [[ELSE:%.*]] [
226-
; CHECK-NEXT: i8 0, label [[IF:%.*]]
227-
; CHECK-NEXT: i8 -3, label [[IF]]
228-
; CHECK-NEXT: i8 -2, label [[IF]]
229-
; CHECK-NEXT: i8 -1, label [[IF]]
230-
; CHECK-NEXT: ]
223+
; CHECK-NEXT: [[ARG_OFF:%.*]] = add i8 [[ARG:%.*]], -1
224+
; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[ARG_OFF]], -4
225+
; CHECK-NEXT: br i1 [[SWITCH]], label [[ELSE:%.*]], label [[IF:%.*]]
231226
; CHECK: common.ret:
232227
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[I0:%.*]], [[IF]] ], [ [[I1:%.*]], [[ELSE]] ]
233228
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]

0 commit comments

Comments
 (0)