Skip to content

Commit a9e0877

Browse files
committed
[InstCombine] Fold select to cmp for weak inequalities
and for comparisons with constant on RHS. Fold select into scmp/ucmp based on signedness of the comparison predicate. Add fold for: Weak inequalities and their logical inverses: - (x <= y - 1) ? -1 : zext(x != y) | (x > y - 1) ? zext(x != y) : -1 - (x <= y - 1) ? -1 : zext(x > y) | (x > y - 1) ? zext(x > y) : -1 - (x >= y + 1) ? 1 : sext(x != y) | (x < y - 1) ? sext(x != y) : 1 - (x >= y + 1) ? 1 : sext(x < y) | (x < y - 1) ? sext(x < y) : 1 and strict version of above inequalities and their logical inverses. Resolves #143259
1 parent 6c41e13 commit a9e0877

File tree

2 files changed

+76
-61
lines changed

2 files changed

+76
-61
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3554,10 +3554,11 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder,
35543554
}
35553555

35563556
// This function tries to fold the following operations:
3557-
// (x < y) ? -1 : zext(x != y)
3558-
// (x < y) ? -1 : zext(x > y)
3559-
// (x > y) ? 1 : sext(x != y)
3560-
// (x > y) ? 1 : sext(x < y)
3557+
// (x < y) ? -1 : zext(x != y) | (x <= y - 1) ? -1 : zext(x != y)
3558+
// (x < y) ? -1 : zext(x > y) | (x <= y - 1) ? -1 : zext(x > y)
3559+
// (x > y) ? 1 : sext(x != y) | (x >= y + 1) ? 1: sext(x != y)
3560+
// (x > y) ? 1 : sext(x < y) | (x >= y + 1) ? 1: sext(x < y)
3561+
// and their logical inverses
35613562
// Into ucmp/scmp(x, y), where signedness is determined by the signedness
35623563
// of the comparison in the original sequence.
35633564
Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
@@ -3572,36 +3573,90 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
35723573
if (!LHS->getType()->isIntOrIntVectorTy())
35733574
return nullptr;
35743575

3576+
// If the select instrction doesn't have 1/-1 for the TV check if FV has 1/-1.
3577+
// If it does, then use the inverted inequality and swap TV and FV
3578+
if (!match(TV, m_AllOnes()) && !match(TV, m_One())) {
3579+
if (match(FV, m_AllOnes()) || match(FV, m_One())) {
3580+
Pred = ICmpInst::getInversePredicate(Pred);
3581+
std::swap(TV, FV);
3582+
}
3583+
}
3584+
35753585
// Try to swap operands and the predicate. We need to be careful when doing
35763586
// so because two of the patterns have opposite predicates, so use the
35773587
// constant inside select to determine if swapping operands would be
35783588
// beneficial to us.
3579-
if ((ICmpInst::isGT(Pred) && match(TV, m_AllOnes())) ||
3580-
(ICmpInst::isLT(Pred) && match(TV, m_One()))) {
3589+
if (((ICmpInst::isGT(Pred) || ICmpInst::isGE(Pred)) &&
3590+
match(TV, m_AllOnes())) ||
3591+
((ICmpInst::isLT(Pred) || ICmpInst::isLE(Pred)) && match(TV, m_One()))) {
35813592
Pred = ICmpInst::getSwappedPredicate(Pred);
35823593
std::swap(LHS, RHS);
35833594
}
35843595
bool IsSigned = ICmpInst::isSigned(Pred);
35853596

35863597
bool Replace = false;
35873598
CmpPredicate ExtendedCmpPredicate;
3599+
Value *FV_RHS;
3600+
3601+
// (x <= y - 1) ? -1 : zext(x != y)
3602+
// (x <= y - 1) ? -1 : zext(x > y)
3603+
if (ICmpInst::isLE(Pred) && match(TV, m_AllOnes()) &&
3604+
match(FV, m_ZExt(m_c_ICmp(ExtendedCmpPredicate, m_Specific(LHS),
3605+
m_Value(FV_RHS)))) &&
3606+
(ExtendedCmpPredicate == ICmpInst::ICMP_NE ||
3607+
ICmpInst::getInversePredicate(ExtendedCmpPredicate) == Pred)) {
3608+
if (match(RHS, m_Add(m_Specific(FV_RHS), m_AllOnes())) ||
3609+
match(FV_RHS, m_Add(m_Specific(RHS), m_One())))
3610+
Replace = true;
3611+
else if (auto *C = dyn_cast<ConstantInt>(RHS)) {
3612+
if (auto *D = dyn_cast<ConstantInt>(FV_RHS)) {
3613+
if ((IsSigned && C->getSExtValue() + 1 == D->getSExtValue()) ||
3614+
(!IsSigned && C->getZExtValue() + 1 == D->getZExtValue()))
3615+
Replace = true;
3616+
}
3617+
}
3618+
}
3619+
35883620
// (x < y) ? -1 : zext(x != y)
35893621
// (x < y) ? -1 : zext(x > y)
35903622
if (ICmpInst::isLT(Pred) && match(TV, m_AllOnes()) &&
35913623
match(FV, m_ZExt(m_c_ICmp(ExtendedCmpPredicate, m_Specific(LHS),
35923624
m_Specific(RHS)))) &&
35933625
(ExtendedCmpPredicate == ICmpInst::ICMP_NE ||
3594-
ICmpInst::getSwappedPredicate(ExtendedCmpPredicate) == Pred))
3626+
ICmpInst::getSwappedPredicate(ExtendedCmpPredicate) == Pred)) {
3627+
FV_RHS = RHS;
35953628
Replace = true;
3629+
}
3630+
3631+
// (x >= y + 1) ? 1 : sext(x != y)
3632+
// (x >= y + 1) ? 1 : sext(x < y)
3633+
if (ICmpInst::isGE(Pred) && match(TV, m_One()) &&
3634+
match(FV, m_SExt(m_c_ICmp(ExtendedCmpPredicate, m_Specific(LHS),
3635+
m_Value(FV_RHS)))) &&
3636+
(ExtendedCmpPredicate == ICmpInst::ICMP_NE ||
3637+
ICmpInst::getInversePredicate(ExtendedCmpPredicate) == Pred)) {
3638+
if (match(RHS, m_Add(m_Specific(FV_RHS), m_One())) ||
3639+
match(FV_RHS, m_Add(m_Specific(RHS), m_AllOnes())))
3640+
Replace = true;
3641+
else if (auto *C = dyn_cast<ConstantInt>(RHS)) {
3642+
if (auto *D = dyn_cast<ConstantInt>(FV_RHS)) {
3643+
if ((IsSigned && C->getSExtValue() == D->getSExtValue() + 1) ||
3644+
(!IsSigned && C->getZExtValue() == D->getZExtValue() + 1))
3645+
Replace = true;
3646+
}
3647+
}
3648+
}
35963649

35973650
// (x > y) ? 1 : sext(x != y)
35983651
// (x > y) ? 1 : sext(x < y)
35993652
if (ICmpInst::isGT(Pred) && match(TV, m_One()) &&
36003653
match(FV, m_SExt(m_c_ICmp(ExtendedCmpPredicate, m_Specific(LHS),
36013654
m_Specific(RHS)))) &&
36023655
(ExtendedCmpPredicate == ICmpInst::ICMP_NE ||
3603-
ICmpInst::getSwappedPredicate(ExtendedCmpPredicate) == Pred))
3656+
ICmpInst::getSwappedPredicate(ExtendedCmpPredicate) == Pred)) {
3657+
FV_RHS = RHS;
36043658
Replace = true;
3659+
}
36053660

36063661
// (x == y) ? 0 : (x > y ? 1 : -1)
36073662
CmpPredicate FalseBranchSelectPredicate;
@@ -3624,14 +3679,15 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
36243679
if (ICmpInst::isGT(FalseBranchSelectPredicate) && InnerTV->isOne() &&
36253680
InnerFV->isAllOnes()) {
36263681
IsSigned = ICmpInst::isSigned(FalseBranchSelectPredicate);
3682+
FV_RHS = RHS;
36273683
Replace = true;
36283684
}
36293685
}
36303686

36313687
Intrinsic::ID IID = IsSigned ? Intrinsic::scmp : Intrinsic::ucmp;
36323688
if (Replace)
36333689
return replaceInstUsesWith(
3634-
SI, Builder.CreateIntrinsic(SI.getType(), IID, {LHS, RHS}));
3690+
SI, Builder.CreateIntrinsic(SI.getType(), IID, {LHS, FV_RHS}));
36353691
return nullptr;
36363692
}
36373693

llvm/test/Transforms/InstCombine/select-to-cmp.ll

Lines changed: 11 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,7 @@ define i32 @scmp_x_y_from_gt_sext_lt(i32 %x, i32 %y) {
6161
define i32 @ucmp_x_y_from_le_sub_zext_ne(i32 %x, i32 %y) {
6262
; CHECK-LABEL: define i32 @ucmp_x_y_from_le_sub_zext_ne(
6363
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
64-
; CHECK-NEXT: [[YM1:%.*]] = add i32 [[Y]], -1
65-
; CHECK-NEXT: [[CMP1_NOT:%.*]] = icmp ugt i32 [[X]], [[YM1]]
66-
; CHECK-NEXT: [[NEQ:%.*]] = icmp ne i32 [[X]], [[Y]]
67-
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[NEQ]] to i32
68-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1_NOT]], i32 [[ZEXT]], i32 -1
64+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
6965
; CHECK-NEXT: ret i32 [[SEL]]
7066
;
7167
%ym1 = sub i32 %y, 1
@@ -80,11 +76,7 @@ define i32 @ucmp_x_y_from_le_sub_zext_ne(i32 %x, i32 %y) {
8076
define i32 @ucmp_x_y_from_le_sub_zext_gt(i32 %x, i32 %y) {
8177
; CHECK-LABEL: define i32 @ucmp_x_y_from_le_sub_zext_gt(
8278
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
83-
; CHECK-NEXT: [[YM1:%.*]] = add i32 [[Y]], -1
84-
; CHECK-NEXT: [[CMP1_NOT:%.*]] = icmp ugt i32 [[X]], [[YM1]]
85-
; CHECK-NEXT: [[GT:%.*]] = icmp ugt i32 [[X]], [[Y]]
86-
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[GT]] to i32
87-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1_NOT]], i32 [[ZEXT]], i32 -1
79+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
8880
; CHECK-NEXT: ret i32 [[SEL]]
8981
;
9082
%ym1 = sub i32 %y, 1
@@ -99,11 +91,7 @@ define i32 @ucmp_x_y_from_le_sub_zext_gt(i32 %x, i32 %y) {
9991
define i32 @ucmp_x_y_from_ge_add_sext_ne(i32 %x, i32 %y) {
10092
; CHECK-LABEL: define i32 @ucmp_x_y_from_ge_add_sext_ne(
10193
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
102-
; CHECK-NEXT: [[YP1:%.*]] = add i32 [[Y]], 1
103-
; CHECK-NEXT: [[CMP1_NOT:%.*]] = icmp ult i32 [[X]], [[YP1]]
104-
; CHECK-NEXT: [[NEQ:%.*]] = icmp ne i32 [[X]], [[Y]]
105-
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[NEQ]] to i32
106-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1_NOT]], i32 [[SEXT]], i32 1
94+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
10795
; CHECK-NEXT: ret i32 [[SEL]]
10896
;
10997
%yp1 = add i32 %y, 1
@@ -118,11 +106,7 @@ define i32 @ucmp_x_y_from_ge_add_sext_ne(i32 %x, i32 %y) {
118106
define i32 @ucmp_x_y_from_ge_add_sext_lt(i32 %x, i32 %y) {
119107
; CHECK-LABEL: define i32 @ucmp_x_y_from_ge_add_sext_lt(
120108
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
121-
; CHECK-NEXT: [[YP1:%.*]] = add i32 [[Y]], 1
122-
; CHECK-NEXT: [[CMP1_NOT:%.*]] = icmp ult i32 [[X]], [[YP1]]
123-
; CHECK-NEXT: [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
124-
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[LT]] to i32
125-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1_NOT]], i32 [[SEXT]], i32 1
109+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
126110
; CHECK-NEXT: ret i32 [[SEL]]
127111
;
128112
%yp1 = add i32 %y, 1
@@ -137,11 +121,7 @@ define i32 @ucmp_x_y_from_ge_add_sext_lt(i32 %x, i32 %y) {
137121
define i32 @scmp_x_y_from_gt_sub_zext_ne(i32 %x, i32 %y) {
138122
; CHECK-LABEL: define i32 @scmp_x_y_from_gt_sub_zext_ne(
139123
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
140-
; CHECK-NEXT: [[YM1:%.*]] = add i32 [[Y]], -1
141-
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], [[YM1]]
142-
; CHECK-NEXT: [[NE:%.*]] = icmp ne i32 [[X]], [[Y]]
143-
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[NE]] to i32
144-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[ZEXT]], i32 -1
124+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
145125
; CHECK-NEXT: ret i32 [[SEL]]
146126
;
147127
%ym1 = sub i32 %y, 1
@@ -156,11 +136,7 @@ define i32 @scmp_x_y_from_gt_sub_zext_ne(i32 %x, i32 %y) {
156136
define i32 @ucmp_x_y_from_gt_sub_zext_gt(i32 %x, i32 %y) {
157137
; CHECK-LABEL: define i32 @ucmp_x_y_from_gt_sub_zext_gt(
158138
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
159-
; CHECK-NEXT: [[YM1:%.*]] = add i32 [[Y]], -1
160-
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[X]], [[YM1]]
161-
; CHECK-NEXT: [[GT:%.*]] = icmp ugt i32 [[X]], [[Y]]
162-
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[GT]] to i32
163-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[ZEXT]], i32 -1
139+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
164140
; CHECK-NEXT: ret i32 [[SEL]]
165141
;
166142
%ym1 = sub i32 %y, 1
@@ -175,11 +151,7 @@ define i32 @ucmp_x_y_from_gt_sub_zext_gt(i32 %x, i32 %y) {
175151
define i32 @scmp_x_y_from_lt_add_sext_ne(i32 %x, i32 %y) {
176152
; CHECK-LABEL: define i32 @scmp_x_y_from_lt_add_sext_ne(
177153
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
178-
; CHECK-NEXT: [[YP1:%.*]] = add i32 [[Y]], 1
179-
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X]], [[YP1]]
180-
; CHECK-NEXT: [[NE:%.*]] = icmp ne i32 [[X]], [[Y]]
181-
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[NE]] to i32
182-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[SEXT]], i32 1
154+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
183155
; CHECK-NEXT: ret i32 [[SEL]]
184156
;
185157
%yp1 = add i32 %y, 1
@@ -194,11 +166,7 @@ define i32 @scmp_x_y_from_lt_add_sext_ne(i32 %x, i32 %y) {
194166
define i32 @ucmp_x_y_from_lt_add_sext_lt(i32 %x, i32 %y) {
195167
; CHECK-LABEL: define i32 @ucmp_x_y_from_lt_add_sext_lt(
196168
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
197-
; CHECK-NEXT: [[YP1:%.*]] = add i32 [[Y]], 1
198-
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X]], [[YP1]]
199-
; CHECK-NEXT: [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
200-
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[LT]] to i32
201-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[SEXT]], i32 1
169+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
202170
; CHECK-NEXT: ret i32 [[SEL]]
203171
;
204172
%yp1 = add i32 %y, 1
@@ -214,10 +182,7 @@ define i32 @ucmp_x_y_from_lt_add_sext_lt(i32 %x, i32 %y) {
214182
define i32 @scmp_x_0_inverted(i32 %x) {
215183
; CHECK-LABEL: define i32 @scmp_x_0_inverted(
216184
; CHECK-SAME: i32 [[X:%.*]]) {
217-
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[X]], 0
218-
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP4]] to i32
219-
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[X]], -1
220-
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 -1
185+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 0)
221186
; CHECK-NEXT: ret i32 [[TMP1]]
222187
;
223188
%2 = icmp ne i32 %x, 0
@@ -230,10 +195,7 @@ define i32 @scmp_x_0_inverted(i32 %x) {
230195
define i32 @scmp_x_neg_6_sgt_form(i32 %x) {
231196
; CHECK-LABEL: define i32 @scmp_x_neg_6_sgt_form(
232197
; CHECK-SAME: i32 [[X:%.*]]) {
233-
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], -6
234-
; CHECK-NEXT: [[NE:%.*]] = icmp ne i32 [[X]], -5
235-
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[NE]] to i32
236-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[ZEXT]], i32 -1
198+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 -5)
237199
; CHECK-NEXT: ret i32 [[SEL]]
238200
;
239201
%cmp1 = icmp sgt i32 %x, -6
@@ -246,10 +208,7 @@ define i32 @scmp_x_neg_6_sgt_form(i32 %x) {
246208
define i32 @ucmp_x_5_ult_form(i32 %x) {
247209
; CHECK-LABEL: define i32 @ucmp_x_5_ult_form(
248210
; CHECK-SAME: i32 [[X:%.*]]) {
249-
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X]], 6
250-
; CHECK-NEXT: [[NE:%.*]] = icmp ne i32 [[X]], 5
251-
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[NE]] to i32
252-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[SEXT]], i32 1
211+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 5)
253212
; CHECK-NEXT: ret i32 [[SEL]]
254213
;
255214
%cmp1 = icmp ult i32 %x, 6

0 commit comments

Comments
 (0)