Skip to content

Commit 38c3aa8

Browse files
committed
[InstCombine] Add a >= b - a<=b to scmp and ucmp folds
https://alive2.llvm.org/ce/z/QiMA_i
1 parent 9b205a1 commit 38c3aa8

File tree

2 files changed

+59
-51
lines changed

2 files changed

+59
-51
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,7 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
16601660
return replaceInstUsesWith(I, Constant::getNullValue(I.getType()));
16611661

16621662
// sext(A < B) + zext(A > B) => ucmp/scmp(A, B)
1663+
// sext(A <= B) + zext(A >= B) => ucmp/scmp(A, B)
16631664
CmpPredicate LTPred, GTPred;
16641665
if (match(&I,
16651666
m_c_Add(m_SExt(m_c_ICmp(LTPred, m_Value(A), m_Value(B))),
@@ -1670,13 +1671,56 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
16701671
std::swap(A, B);
16711672
}
16721673

1673-
if (ICmpInst::isLT(LTPred) && ICmpInst::isGT(GTPred) &&
1674-
ICmpInst::isSigned(LTPred) == ICmpInst::isSigned(GTPred))
1674+
if (ICmpInst::isSigned(LTPred) == ICmpInst::isSigned(GTPred)) {
1675+
Intrinsic::ID IID =
1676+
ICmpInst::isSigned(LTPred) ? Intrinsic::scmp : Intrinsic::ucmp;
1677+
1678+
// Handle strict inequalities: sext(A < B) + zext(A > B) => scmp/ucmp(A,
1679+
// B)
1680+
if (ICmpInst::isLT(LTPred) && ICmpInst::isGT(GTPred)) {
1681+
return replaceInstUsesWith(I, Builder.CreateIntrinsic(Ty, IID, {A, B}));
1682+
}
1683+
1684+
// Handle non-strict inequalities: sext(A <= B) + zext(A >= B) =>
1685+
// scmp/ucmp(A, B)
1686+
if (ICmpInst::isLE(LTPred) && ICmpInst::isGE(GTPred)) {
1687+
return replaceInstUsesWith(I, Builder.CreateIntrinsic(Ty, IID, {A, B}));
1688+
}
1689+
}
1690+
}
1691+
1692+
// Handle constant case: sext/zext(x > C1) + zext/sext(x < C2) where C2 = C1 +
1693+
// 2 This represents (x >= C1+1) - (x <= C1+1) => scmp/ucmp(x, C1+1)
1694+
Value *X;
1695+
ConstantInt *Const1, *Const2;
1696+
CmpPredicate Pred1, Pred2;
1697+
if (match(&I,
1698+
m_c_Add(
1699+
m_SExt(m_ICmp(Pred1, m_Value(X), m_ConstantInt(Const1))),
1700+
m_ZExt(m_ICmp(Pred2, m_Deferred(X), m_ConstantInt(Const2))))) &&
1701+
X->getType()->isIntOrIntVectorTy()) {
1702+
1703+
// Case 1: sext(x > C1) + zext(x < C2) where C2 = C1 + 2
1704+
if (ICmpInst::isGT(Pred1) && ICmpInst::isLT(Pred2) &&
1705+
Const2->getValue() == Const1->getValue() + 2) {
1706+
Intrinsic::ID IID =
1707+
ICmpInst::isSigned(Pred1) ? Intrinsic::scmp : Intrinsic::ucmp;
1708+
Constant *C1Plus1 =
1709+
ConstantInt::get(Const1->getType(), Const1->getValue() + 1);
16751710
return replaceInstUsesWith(
1676-
I, Builder.CreateIntrinsic(
1677-
Ty,
1678-
ICmpInst::isSigned(LTPred) ? Intrinsic::scmp : Intrinsic::ucmp,
1679-
{A, B}));
1711+
I, Builder.CreateIntrinsic(Ty, IID, {X, C1Plus1}));
1712+
}
1713+
1714+
// Case 2: sext(x < C1) + zext(x > C2) where C1 = C2 + 2
1715+
if (ICmpInst::isLT(Pred1) && ICmpInst::isGT(Pred2) &&
1716+
Const1->getValue() == Const2->getValue() + 2) {
1717+
Intrinsic::ID IID =
1718+
ICmpInst::isSigned(Pred1) ? Intrinsic::scmp : Intrinsic::ucmp;
1719+
Constant *C2Plus1 =
1720+
ConstantInt::get(Const2->getType(), Const2->getValue() + 1);
1721+
return replaceInstUsesWith(
1722+
I, Builder.CreateIntrinsic(Ty, IID, {X, C2Plus1}));
1723+
}
16801724
}
16811725

16821726
// A+B --> A|B iff A and B have no bits set in common.

llvm/test/Transforms/InstCombine/sext-a-lt-b-plus-zext-a-gt-b-to-uscmp.ll

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,7 @@ define i8 @signed_add_neg5(i32 %a, i32 %b) {
187187
define i8 @signed_add_ge_le(i32 %a, i32 %b) {
188188
; CHECK-LABEL: define i8 @signed_add_ge_le(
189189
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
190-
; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[A]], [[B]]
191-
; CHECK-NEXT: [[LE8:%.*]] = sext i1 [[LE]] to i8
192-
; CHECK-NEXT: [[GE:%.*]] = icmp sge i32 [[A]], [[B]]
193-
; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
194-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8]], [[GE8]]
190+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A]], i32 [[B]])
195191
; CHECK-NEXT: ret i8 [[R]]
196192
;
197193
%le = icmp sle i32 %a, %b
@@ -206,11 +202,7 @@ define i8 @signed_add_ge_le(i32 %a, i32 %b) {
206202
define i8 @unsigned_add_ge_le(i32 %a, i32 %b) {
207203
; CHECK-LABEL: define i8 @unsigned_add_ge_le(
208204
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
209-
; CHECK-NEXT: [[LE:%.*]] = icmp ule i32 [[A]], [[B]]
210-
; CHECK-NEXT: [[LE8:%.*]] = sext i1 [[LE]] to i8
211-
; CHECK-NEXT: [[GE:%.*]] = icmp uge i32 [[A]], [[B]]
212-
; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
213-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8]], [[GE8]]
205+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
214206
; CHECK-NEXT: ret i8 [[R]]
215207
;
216208
%le = icmp ule i32 %a, %b
@@ -225,11 +217,7 @@ define i8 @unsigned_add_ge_le(i32 %a, i32 %b) {
225217
define i8 @signed_sub_ge_le(i32 %a, i32 %b) {
226218
; CHECK-LABEL: define i8 @signed_sub_ge_le(
227219
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
228-
; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[A]], [[B]]
229-
; CHECK-NEXT: [[LE8_NEG:%.*]] = sext i1 [[LE]] to i8
230-
; CHECK-NEXT: [[GE:%.*]] = icmp sge i32 [[A]], [[B]]
231-
; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
232-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8_NEG]], [[GE8]]
220+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A]], i32 [[B]])
233221
; CHECK-NEXT: ret i8 [[R]]
234222
;
235223
%le = icmp sle i32 %a, %b
@@ -244,11 +232,7 @@ define i8 @signed_sub_ge_le(i32 %a, i32 %b) {
244232
define i8 @unsigned_sub_ge_le(i32 %a, i32 %b) {
245233
; CHECK-LABEL: define i8 @unsigned_sub_ge_le(
246234
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
247-
; CHECK-NEXT: [[LE:%.*]] = icmp ule i32 [[A]], [[B]]
248-
; CHECK-NEXT: [[LE8_NEG:%.*]] = sext i1 [[LE]] to i8
249-
; CHECK-NEXT: [[GE:%.*]] = icmp uge i32 [[A]], [[B]]
250-
; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
251-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8_NEG]], [[GE8]]
235+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
252236
; CHECK-NEXT: ret i8 [[R]]
253237
;
254238
%le = icmp ule i32 %a, %b
@@ -263,11 +247,7 @@ define i8 @unsigned_sub_ge_le(i32 %a, i32 %b) {
263247
define i8 @signed_sub_const_canonicalization(i32 %a) {
264248
; CHECK-LABEL: define i8 @signed_sub_const_canonicalization(
265249
; CHECK-SAME: i32 [[A:%.*]]) {
266-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 6
267-
; CHECK-NEXT: [[LT8_NEG:%.*]] = sext i1 [[LT]] to i8
268-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], 4
269-
; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
270-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8_NEG]], [[GT8]]
250+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A]], i32 5)
271251
; CHECK-NEXT: ret i8 [[R]]
272252
;
273253
%lt = icmp slt i32 %a, 6
@@ -282,11 +262,7 @@ define i8 @signed_sub_const_canonicalization(i32 %a) {
282262
define i8 @signed_sub_const_canonicalization2(i32 %a) {
283263
; CHECK-LABEL: define i8 @signed_sub_const_canonicalization2(
284264
; CHECK-SAME: i32 [[A:%.*]]) {
285-
; CHECK-NEXT: [[LE:%.*]] = icmp slt i32 [[A]], 6
286-
; CHECK-NEXT: [[LE8_NEG:%.*]] = sext i1 [[LE]] to i8
287-
; CHECK-NEXT: [[GE:%.*]] = icmp sgt i32 [[A]], 4
288-
; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
289-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8_NEG]], [[GE8]]
265+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A]], i32 5)
290266
; CHECK-NEXT: ret i8 [[R]]
291267
;
292268
%le = icmp sle i32 %a, 5
@@ -301,11 +277,7 @@ define i8 @signed_sub_const_canonicalization2(i32 %a) {
301277
define i8 @unsigned_sub_const_canonicalization(i32 %a) {
302278
; CHECK-LABEL: define i8 @unsigned_sub_const_canonicalization(
303279
; CHECK-SAME: i32 [[A:%.*]]) {
304-
; CHECK-NEXT: [[LT:%.*]] = icmp ult i32 [[A]], 6
305-
; CHECK-NEXT: [[LT8_NEG:%.*]] = sext i1 [[LT]] to i8
306-
; CHECK-NEXT: [[GT:%.*]] = icmp ugt i32 [[A]], 4
307-
; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
308-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8_NEG]], [[GT8]]
280+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 5)
309281
; CHECK-NEXT: ret i8 [[R]]
310282
;
311283
%lt = icmp ult i32 %a, 6
@@ -320,11 +292,7 @@ define i8 @unsigned_sub_const_canonicalization(i32 %a) {
320292
define i8 @signed_sub_const_canonicalization_ge_le(i32 %a) {
321293
; CHECK-LABEL: define i8 @signed_sub_const_canonicalization_ge_le(
322294
; CHECK-SAME: i32 [[A:%.*]]) {
323-
; CHECK-NEXT: [[LE:%.*]] = icmp slt i32 [[A]], 6
324-
; CHECK-NEXT: [[LE8_NEG:%.*]] = sext i1 [[LE]] to i8
325-
; CHECK-NEXT: [[GE:%.*]] = icmp sgt i32 [[A]], 4
326-
; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
327-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8_NEG]], [[GE8]]
295+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A]], i32 5)
328296
; CHECK-NEXT: ret i8 [[R]]
329297
;
330298
%le = icmp sle i32 %a, 5
@@ -339,11 +307,7 @@ define i8 @signed_sub_const_canonicalization_ge_le(i32 %a) {
339307
define i8 @signed_sub_const_canonicalization3(i32 %a) {
340308
; CHECK-LABEL: define i8 @signed_sub_const_canonicalization3(
341309
; CHECK-SAME: i32 [[A:%.*]]) {
342-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 4
343-
; CHECK-NEXT: [[LT8_NEG:%.*]] = sext i1 [[LT]] to i8
344-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], 2
345-
; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
346-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8_NEG]], [[GT8]]
310+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A]], i32 3)
347311
; CHECK-NEXT: ret i8 [[R]]
348312
;
349313
%lt = icmp slt i32 %a, 4

0 commit comments

Comments
 (0)