Skip to content

Commit 2b6d306

Browse files
committed
[InstCombine] Fold select to cmp with constants in non-canonical inequalities
For constant y, inequalities aren't always canonical so we need to check the conditions such as - (x > y - 1) ? zext(x != y) : -1 - (x > y - 1) ? zext(x > y) : -1 - (x < y + 1) ? sext(x != y) : 1 - (x < y + 1) ? sext(x < y) : 1 and similary non-strict equalities. Fold select into scmp/ucmp based on signedness of the comparison predicate. Resolves #143259
1 parent e620e76 commit 2b6d306

File tree

2 files changed

+52
-40
lines changed

2 files changed

+52
-40
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3572,6 +3572,28 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
35723572
if (!LHS->getType()->isIntOrIntVectorTy())
35733573
return nullptr;
35743574

3575+
// If there is no -1, 0 or 1 at TV, then invert the select statement and try
3576+
// to canonicalize to one of the forms above
3577+
if (!match(TV, m_AllOnes()) && !match(TV, m_One()) && !match(TV, m_Zero())) {
3578+
if (!match(FV, m_AllOnes()) && !match(FV, m_One()) && !match(FV, m_Zero()))
3579+
return nullptr;
3580+
Pred = ICmpInst::getInverseCmpPredicate(Pred);
3581+
std::swap(TV, FV);
3582+
}
3583+
3584+
if (ICmpInst::isGE(Pred) || ICmpInst::isLE(Pred)) {
3585+
if (ConstantInt *C = dyn_cast<ConstantInt>(RHS)) {
3586+
auto FlippedPredAndConst =
3587+
getFlippedStrictnessPredicateAndConstant(Pred, C);
3588+
if (!FlippedPredAndConst)
3589+
return nullptr;
3590+
Pred = FlippedPredAndConst->first;
3591+
RHS = FlippedPredAndConst->second;
3592+
} else {
3593+
return nullptr;
3594+
}
3595+
}
3596+
35753597
// Try to swap operands and the predicate. We need to be careful when doing
35763598
// so because two of the patterns have opposite predicates, so use the
35773599
// constant inside select to determine if swapping operands would be

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

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
define i32 @scmp_x_0_inverted(i32 %x) {
77
; CHECK-LABEL: define i32 @scmp_x_0_inverted(
88
; CHECK-SAME: i32 [[X:%.*]]) {
9-
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[X]], 0
10-
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP4]] to i32
11-
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[X]], -1
12-
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 -1
9+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 0)
1310
; CHECK-NEXT: ret i32 [[TMP1]]
1411
;
1512
%2 = icmp ne i32 %x, 0
@@ -23,10 +20,7 @@ define i32 @scmp_x_0_inverted(i32 %x) {
2320
define i32 @scmp_x_0_inverted_const_neg10(i32 %x) {
2421
; CHECK-LABEL: define i32 @scmp_x_0_inverted_const_neg10(
2522
; CHECK-SAME: i32 [[X:%.*]]) {
26-
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[X]], -10
27-
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP4]] to i32
28-
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[X]], -11
29-
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 -1
23+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 -10)
3024
; CHECK-NEXT: ret i32 [[TMP1]]
3125
;
3226
%1 = icmp ne i32 %x, -10
@@ -40,10 +34,7 @@ define i32 @scmp_x_0_inverted_const_neg10(i32 %x) {
4034
define i8 @scmp_x_0_inverted_i8(i8 %x) {
4135
; CHECK-LABEL: define i8 @scmp_x_0_inverted_i8(
4236
; CHECK-SAME: i8 [[X:%.*]]) {
43-
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i8 [[X]], 7
44-
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP4]] to i8
45-
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i8 [[X]], 6
46-
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP3]], i8 [[TMP2]], i8 -1
37+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i8(i8 [[X]], i8 7)
4738
; CHECK-NEXT: ret i8 [[TMP1]]
4839
;
4940
%1 = icmp ne i8 %x, 7
@@ -57,10 +48,8 @@ define i8 @scmp_x_0_inverted_i8(i8 %x) {
5748
define i32 @scmp_x_0_inverted_i64_neq(i32 %x) {
5849
; CHECK-LABEL: define i32 @scmp_x_0_inverted_i64_neq(
5950
; CHECK-SAME: i32 [[X:%.*]]) {
60-
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X]], 0
61-
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], -1
62-
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[CMP1]] to i32
63-
; CHECK-NEXT: [[RET:%.*]] = select i1 [[CMP2]], i32 [[TMP1]], i32 -1
51+
; CHECK-NEXT: [[SEL:%.*]] = call i64 @llvm.scmp.i64.i32(i32 [[X]], i32 0)
52+
; CHECK-NEXT: [[RET:%.*]] = trunc i64 [[SEL]] to i32
6453
; CHECK-NEXT: ret i32 [[RET]]
6554
;
6655
%x64 = sext i32 %x to i64
@@ -76,10 +65,8 @@ define i32 @scmp_x_0_inverted_i64_neq(i32 %x) {
7665
define i32 @scmp_x_0_inverted_i64_sgt(i32 %x) {
7766
; CHECK-LABEL: define i32 @scmp_x_0_inverted_i64_sgt(
7867
; CHECK-SAME: i32 [[X:%.*]]) {
79-
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], 0
80-
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], -1
81-
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[CMP1]] to i32
82-
; CHECK-NEXT: [[RET:%.*]] = select i1 [[CMP2]], i32 [[TMP1]], i32 -1
68+
; CHECK-NEXT: [[SEL:%.*]] = call i64 @llvm.scmp.i64.i32(i32 [[X]], i32 0)
69+
; CHECK-NEXT: [[RET:%.*]] = trunc i64 [[SEL]] to i32
8370
; CHECK-NEXT: ret i32 [[RET]]
8471
;
8572
%x64 = sext i32 %x to i64
@@ -95,10 +82,7 @@ define i32 @scmp_x_0_inverted_i64_sgt(i32 %x) {
9582
define i32 @scmp_x_0_inverted_const_neg1000(i32 %x) {
9683
; CHECK-LABEL: define i32 @scmp_x_0_inverted_const_neg1000(
9784
; CHECK-SAME: i32 [[X:%.*]]) {
98-
; CHECK-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[X]], -1000
99-
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP4]] to i32
100-
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[X]], -1001
101-
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 -1
85+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 -1000)
10286
; CHECK-NEXT: ret i32 [[TMP1]]
10387
;
10488
%1 = icmp sgt i32 %x, -1000
@@ -112,10 +96,7 @@ define i32 @scmp_x_0_inverted_const_neg1000(i32 %x) {
11296
define i32 @scmp_x_0_inverted_const_1729_sgt(i32 %x) {
11397
; CHECK-LABEL: define i32 @scmp_x_0_inverted_const_1729_sgt(
11498
; CHECK-SAME: i32 [[X:%.*]]) {
115-
; CHECK-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[X]], 1729
116-
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP4]] to i32
117-
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[X]], 1728
118-
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 -1
99+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 1729)
119100
; CHECK-NEXT: ret i32 [[TMP1]]
120101
;
121102
%1 = icmp sgt i32 %x, 1729
@@ -129,10 +110,7 @@ define i32 @scmp_x_0_inverted_const_1729_sgt(i32 %x) {
129110
define i32 @ucmp_x_10_inverted(i32 %x) {
130111
; CHECK-LABEL: define i32 @ucmp_x_10_inverted(
131112
; CHECK-SAME: i32 [[X:%.*]]) {
132-
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[X]], 10
133-
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP4]] to i32
134-
; CHECK-NEXT: [[TMP3:%.*]] = icmp ugt i32 [[X]], 9
135-
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 -1
113+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 10)
136114
; CHECK-NEXT: ret i32 [[TMP1]]
137115
;
138116
%1 = icmp ne i32 %x, 10
@@ -146,10 +124,7 @@ define i32 @ucmp_x_10_inverted(i32 %x) {
146124
define i32 @ucmp_x_neg1_inverted(i32 %x) {
147125
; CHECK-LABEL: define i32 @ucmp_x_neg1_inverted(
148126
; CHECK-SAME: i32 [[X:%.*]]) {
149-
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[X]], -3
150-
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP4]] to i32
151-
; CHECK-NEXT: [[TMP3:%.*]] = icmp ugt i32 [[X]], -4
152-
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 -1
127+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 -3)
153128
; CHECK-NEXT: ret i32 [[TMP1]]
154129
;
155130
%1 = icmp ne i32 %x, -3
@@ -163,10 +138,7 @@ define i32 @ucmp_x_neg1_inverted(i32 %x) {
163138
define i8 @ucmp_x_neg4_i8_ugt(i8 %x) {
164139
; CHECK-LABEL: define i8 @ucmp_x_neg4_i8_ugt(
165140
; CHECK-SAME: i8 [[X:%.*]]) {
166-
; CHECK-NEXT: [[TMP4:%.*]] = icmp ugt i8 [[X]], -4
167-
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP4]] to i8
168-
; CHECK-NEXT: [[TMP3:%.*]] = icmp ugt i8 [[X]], -5
169-
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP3]], i8 [[TMP2]], i8 -1
141+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i8(i8 [[X]], i8 -4)
170142
; CHECK-NEXT: ret i8 [[TMP1]]
171143
;
172144
%1 = icmp ugt i8 %x, -4
@@ -252,3 +224,21 @@ define i32 @ucmp_x_const_u32max(i32 %x) {
252224
%4 = select i1 %3, i32 %2, i32 -1
253225
ret i32 %4
254226
}
227+
228+
; Don't fold with different signedness
229+
230+
define i32 @different_signedness_neg(i32 %x) {
231+
; CHECK-LABEL: define i32 @different_signedness_neg(
232+
; CHECK-SAME: i32 [[X:%.*]]) {
233+
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X]], -10
234+
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP1]] to i32
235+
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[X]], -11
236+
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 -1
237+
; CHECK-NEXT: ret i32 [[TMP4]]
238+
;
239+
%1 = icmp ugt i32 %x, -10
240+
%2 = zext i1 %1 to i32
241+
%3 = icmp sgt i32 %x, -11
242+
%4 = select i1 %3, i32 %2, i32 -1
243+
ret i32 %4
244+
}

0 commit comments

Comments
 (0)