Skip to content

Commit 38b27b9

Browse files
committed
[InstCombine] Fold select to cmp with constants in
non-canonical inequalities Fold select into scmp/ucmp based on signedness of the comparison predicate. Add fold for: For constant y, inequalities aren't always canonical so we need to check the following manually: - (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 fold select into scmp/ucmp based on signedness of the comparison predicate. Resolves #143259
1 parent e620e76 commit 38b27b9

File tree

2 files changed

+61
-40
lines changed

2 files changed

+61
-40
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3632,6 +3632,55 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
36323632
if (Replace)
36333633
return replaceInstUsesWith(
36343634
SI, Builder.CreateIntrinsic(SI.getType(), IID, {LHS, RHS}));
3635+
3636+
Value *EXT_RHS;
3637+
3638+
// For constant y, inequalities aren't always canonical so we need to check
3639+
// the following manually: (x > y - 1) ? zext(x != y) : -1 (x > y - 1) ?
3640+
// zext(x > y) : -1
3641+
if (ICmpInst::isGT(Pred) && match(FV, m_AllOnes()) &&
3642+
match(TV, m_ZExt(m_c_ICmp(ExtendedCmpPredicate, m_Specific(LHS),
3643+
m_Value(EXT_RHS)))) &&
3644+
(ExtendedCmpPredicate == ICmpInst::ICMP_NE ||
3645+
ICmpInst::isGT(ExtendedCmpPredicate))) {
3646+
if (auto *C = dyn_cast<ConstantInt>(RHS)) {
3647+
if (auto *D = dyn_cast<ConstantInt>(EXT_RHS)) {
3648+
if (C->getBitWidth() != D->getBitWidth())
3649+
return nullptr;
3650+
const APInt &CVal = C->getValue();
3651+
const APInt &DVal = D->getValue();
3652+
bool Overflows;
3653+
APInt diff = (IsSigned) ? DVal.ssub_ov(CVal, Overflows)
3654+
: DVal.usub_ov(CVal, Overflows);
3655+
if (!Overflows && diff.isOne())
3656+
return replaceInstUsesWith(
3657+
SI, Builder.CreateIntrinsic(SI.getType(), IID, {LHS, EXT_RHS}));
3658+
}
3659+
}
3660+
}
3661+
3662+
// (x < y + 1) ? sext(x != y) : 1
3663+
// (x < y + 1) ? sext(x < y) : 1
3664+
if (ICmpInst::isLT(Pred) && match(FV, m_One()) &&
3665+
match(TV, m_SExt(m_c_ICmp(ExtendedCmpPredicate, m_Specific(LHS),
3666+
m_Value(EXT_RHS)))) &&
3667+
(ExtendedCmpPredicate == ICmpInst::ICMP_NE ||
3668+
ICmpInst::isLT(ExtendedCmpPredicate))) {
3669+
if (auto *C = dyn_cast<ConstantInt>(RHS)) {
3670+
if (auto *D = dyn_cast<ConstantInt>(EXT_RHS)) {
3671+
if (C->getBitWidth() != D->getBitWidth())
3672+
return nullptr;
3673+
const APInt &CVal = C->getValue();
3674+
const APInt &DVal = D->getValue();
3675+
bool Overflows;
3676+
APInt diff = (IsSigned) ? CVal.ssub_ov(DVal, Overflows)
3677+
: CVal.usub_ov(DVal, Overflows);
3678+
if (!Overflows && diff.isOne())
3679+
return replaceInstUsesWith(
3680+
SI, Builder.CreateIntrinsic(SI.getType(), IID, {LHS, EXT_RHS}));
3681+
}
3682+
}
3683+
}
36353684
return nullptr;
36363685
}
36373686

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

Lines changed: 12 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

0 commit comments

Comments
 (0)