Skip to content

Commit 99387e3

Browse files
committed
[InstCombine] Add transforms for (icmp uPred (trunc x),(truncOrZext(y)))->(icmp uPred x,y)
Three transforms (all commutative): https://alive2.llvm.org/ce/z/Bc-nh4 Closes llvm#71309
1 parent 0f3a9ef commit 99387e3

File tree

4 files changed

+81
-49
lines changed

4 files changed

+81
-49
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,6 +1512,61 @@ Instruction *InstCombinerImpl::foldICmpTruncConstant(ICmpInst &Cmp,
15121512
return nullptr;
15131513
}
15141514

1515+
/// Fold icmp (trunc X), (trunc Y).
1516+
/// Fold icmp (trunc X), (zext Y).
1517+
Instruction *
1518+
InstCombinerImpl::foldICmpTruncWithTruncOrExt(ICmpInst &Cmp,
1519+
const SimplifyQuery &Q) {
1520+
if (Cmp.isSigned())
1521+
return nullptr;
1522+
1523+
Value *X, *Y;
1524+
ICmpInst::Predicate Pred;
1525+
bool YIsZext = false;
1526+
// Try to match icmp (trunc X), (trunc Y)
1527+
if (match(&Cmp, m_ICmp(Pred, m_Trunc(m_Value(X)), m_Trunc(m_Value(Y))))) {
1528+
if (X->getType() != Y->getType() &&
1529+
(!Cmp.getOperand(0)->hasOneUse() || !Cmp.getOperand(1)->hasOneUse()))
1530+
return nullptr;
1531+
if (!isDesirableIntType(X->getType()->getScalarSizeInBits()) &&
1532+
isDesirableIntType(Y->getType()->getScalarSizeInBits())) {
1533+
std::swap(X, Y);
1534+
Pred = Cmp.getSwappedPredicate(Pred);
1535+
}
1536+
}
1537+
// Try to match icmp (trunc X), (zext Y)
1538+
else if (match(&Cmp, m_c_ICmp(Pred, m_Trunc(m_Value(X)),
1539+
m_OneUse(m_ZExt(m_Value(Y))))))
1540+
1541+
YIsZext = true;
1542+
else
1543+
return nullptr;
1544+
1545+
Type *TruncTy = Cmp.getOperand(0)->getType();
1546+
unsigned TruncBits = TruncTy->getScalarSizeInBits();
1547+
1548+
// If this transform will end up changing from desirable types -> undesirable
1549+
// types skip it.
1550+
if (isDesirableIntType(TruncBits) &&
1551+
!isDesirableIntType(X->getType()->getScalarSizeInBits()))
1552+
return nullptr;
1553+
1554+
// Check if the trunc is unneeded.
1555+
KnownBits KnownX = llvm::computeKnownBits(X, /*Depth*/ 0, Q);
1556+
if (KnownX.countMaxActiveBits() > TruncBits)
1557+
return nullptr;
1558+
1559+
if (!YIsZext) {
1560+
// If Y is also a trunc, make sure it is unneeded.
1561+
KnownBits KnownY = llvm::computeKnownBits(Y, /*Depth*/ 0, Q);
1562+
if (KnownY.countMaxActiveBits() > TruncBits)
1563+
return nullptr;
1564+
}
1565+
1566+
Value *NewY = Builder.CreateZExtOrTrunc(Y, X->getType());
1567+
return new ICmpInst(Pred, X, NewY);
1568+
}
1569+
15151570
/// Fold icmp (xor X, Y), C.
15161571
Instruction *InstCombinerImpl::foldICmpXorConstant(ICmpInst &Cmp,
15171572
BinaryOperator *Xor,
@@ -6879,6 +6934,9 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
68796934
if (Instruction *Res = foldICmpUsingKnownBits(I))
68806935
return Res;
68816936

6937+
if (Instruction *Res = foldICmpTruncWithTruncOrExt(I, Q))
6938+
return Res;
6939+
68826940
// Test if the ICmpInst instruction is used exclusively by a select as
68836941
// part of a minimum or maximum operation. If so, refrain from doing
68846942
// any other folding. This helps out other analyses which understand

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
647647
ConstantInt *C);
648648
Instruction *foldICmpTruncConstant(ICmpInst &Cmp, TruncInst *Trunc,
649649
const APInt &C);
650+
Instruction *foldICmpTruncWithTruncOrExt(ICmpInst &Cmp,
651+
const SimplifyQuery &Q);
650652
Instruction *foldICmpAndConstant(ICmpInst &Cmp, BinaryOperator *And,
651653
const APInt &C);
652654
Instruction *foldICmpXorConstant(ICmpInst &Cmp, BinaryOperator *Xor,

llvm/test/Transforms/InstCombine/eq-of-parts.ll

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -584,17 +584,8 @@ define i1 @eq_21_not_adjacent(i32 %x, i32 %y) {
584584

585585
define i1 @eq_shift_in_zeros(i32 %x, i32 %y) {
586586
; CHECK-LABEL: @eq_shift_in_zeros(
587-
; CHECK-NEXT: [[X_321:%.*]] = lshr i32 [[X:%.*]], 8
588-
; CHECK-NEXT: [[X_1:%.*]] = trunc i32 [[X_321]] to i8
589-
; CHECK-NEXT: [[X_32:%.*]] = lshr i32 [[X]], 16
590-
; CHECK-NEXT: [[X_2:%.*]] = trunc i32 [[X_32]] to i24
591-
; CHECK-NEXT: [[Y_321:%.*]] = lshr i32 [[Y:%.*]], 8
592-
; CHECK-NEXT: [[Y_1:%.*]] = trunc i32 [[Y_321]] to i8
593-
; CHECK-NEXT: [[Y_32:%.*]] = lshr i32 [[Y]], 16
594-
; CHECK-NEXT: [[Y_2:%.*]] = trunc i32 [[Y_32]] to i24
595-
; CHECK-NEXT: [[C_1:%.*]] = icmp eq i8 [[X_1]], [[Y_1]]
596-
; CHECK-NEXT: [[C_2:%.*]] = icmp eq i24 [[X_2]], [[Y_2]]
597-
; CHECK-NEXT: [[C_210:%.*]] = and i1 [[C_2]], [[C_1]]
587+
; CHECK-NEXT: [[C_210_UNSHIFTED:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
588+
; CHECK-NEXT: [[C_210:%.*]] = icmp ult i32 [[C_210_UNSHIFTED]], 256
598589
; CHECK-NEXT: ret i1 [[C_210]]
599590
;
600591
%x.321 = lshr i32 %x, 8
@@ -1249,17 +1240,8 @@ define i1 @ne_21_not_adjacent(i32 %x, i32 %y) {
12491240

12501241
define i1 @ne_shift_in_zeros(i32 %x, i32 %y) {
12511242
; CHECK-LABEL: @ne_shift_in_zeros(
1252-
; CHECK-NEXT: [[X_321:%.*]] = lshr i32 [[X:%.*]], 8
1253-
; CHECK-NEXT: [[X_1:%.*]] = trunc i32 [[X_321]] to i8
1254-
; CHECK-NEXT: [[X_32:%.*]] = lshr i32 [[X]], 16
1255-
; CHECK-NEXT: [[X_2:%.*]] = trunc i32 [[X_32]] to i24
1256-
; CHECK-NEXT: [[Y_321:%.*]] = lshr i32 [[Y:%.*]], 8
1257-
; CHECK-NEXT: [[Y_1:%.*]] = trunc i32 [[Y_321]] to i8
1258-
; CHECK-NEXT: [[Y_32:%.*]] = lshr i32 [[Y]], 16
1259-
; CHECK-NEXT: [[Y_2:%.*]] = trunc i32 [[Y_32]] to i24
1260-
; CHECK-NEXT: [[C_1:%.*]] = icmp ne i8 [[X_1]], [[Y_1]]
1261-
; CHECK-NEXT: [[C_2:%.*]] = icmp ne i24 [[X_2]], [[Y_2]]
1262-
; CHECK-NEXT: [[C_210:%.*]] = or i1 [[C_2]], [[C_1]]
1243+
; CHECK-NEXT: [[C_210_UNSHIFTED:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
1244+
; CHECK-NEXT: [[C_210:%.*]] = icmp ugt i32 [[C_210_UNSHIFTED]], 255
12631245
; CHECK-NEXT: ret i1 [[C_210]]
12641246
;
12651247
%x.321 = lshr i32 %x, 8

llvm/test/Transforms/InstCombine/icmp-of-trunc-ext.ll

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ define i1 @icmp_trunc_x_trunc_y(i32 %x, i32 %y) {
99
; CHECK-NEXT: [[Y_LB_ONLY:%.*]] = icmp ult i32 [[Y:%.*]], 65536
1010
; CHECK-NEXT: call void @llvm.assume(i1 [[X_LB_ONLY]])
1111
; CHECK-NEXT: call void @llvm.assume(i1 [[Y_LB_ONLY]])
12-
; CHECK-NEXT: [[X16:%.*]] = trunc i32 [[X]] to i16
13-
; CHECK-NEXT: [[Y16:%.*]] = trunc i32 [[Y]] to i16
14-
; CHECK-NEXT: [[R:%.*]] = icmp eq i16 [[X16]], [[Y16]]
12+
; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[X]], [[Y]]
1513
; CHECK-NEXT: ret i1 [[R]]
1614
;
1715
%x_lb_only = icmp ult i32 %x, 65536
@@ -51,9 +49,8 @@ define i1 @icmp_trunc_x_trunc_y_illegal_trunc_to_legal_anyways(i123 %x, i32 %y)
5149
; CHECK-NEXT: [[Y_LB_ONLY:%.*]] = icmp ult i32 [[Y:%.*]], 65536
5250
; CHECK-NEXT: call void @llvm.assume(i1 [[X_LB_ONLY]])
5351
; CHECK-NEXT: call void @llvm.assume(i1 [[Y_LB_ONLY]])
54-
; CHECK-NEXT: [[X16:%.*]] = trunc i123 [[X]] to i16
55-
; CHECK-NEXT: [[Y16:%.*]] = trunc i32 [[Y]] to i16
56-
; CHECK-NEXT: [[R:%.*]] = icmp eq i16 [[X16]], [[Y16]]
52+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i123 [[X]] to i32
53+
; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[TMP1]], [[Y]]
5754
; CHECK-NEXT: ret i1 [[R]]
5855
;
5956
%x_lb_only = icmp ult i123 %x, 65536
@@ -72,9 +69,8 @@ define i1 @icmp_trunc_x_trunc_y_2_illegal_anyways(i33 %x, i63 %y) {
7269
; CHECK-NEXT: [[Y_LB_ONLY:%.*]] = icmp ult i63 [[Y:%.*]], 512
7370
; CHECK-NEXT: call void @llvm.assume(i1 [[X_LB_ONLY]])
7471
; CHECK-NEXT: call void @llvm.assume(i1 [[Y_LB_ONLY]])
75-
; CHECK-NEXT: [[X16:%.*]] = trunc i33 [[X]] to i9
76-
; CHECK-NEXT: [[Y16:%.*]] = trunc i63 [[Y]] to i9
77-
; CHECK-NEXT: [[R:%.*]] = icmp ult i9 [[Y16]], [[X16]]
72+
; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i33 [[X]] to i63
73+
; CHECK-NEXT: [[R:%.*]] = icmp ugt i63 [[TMP1]], [[Y]]
7874
; CHECK-NEXT: ret i1 [[R]]
7975
;
8076
%x_lb_only = icmp ult i33 %x, 512
@@ -93,9 +89,8 @@ define i1 @icmp_trunc_x_trunc_y_3(i64 %x, i32 %y) {
9389
; CHECK-NEXT: [[Y_LB_ONLY:%.*]] = icmp ult i32 [[Y:%.*]], 256
9490
; CHECK-NEXT: call void @llvm.assume(i1 [[X_LB_ONLY]])
9591
; CHECK-NEXT: call void @llvm.assume(i1 [[Y_LB_ONLY]])
96-
; CHECK-NEXT: [[XI8:%.*]] = trunc i64 [[X]] to i8
97-
; CHECK-NEXT: [[YI8:%.*]] = trunc i32 [[Y]] to i8
98-
; CHECK-NEXT: [[R:%.*]] = icmp ule i8 [[YI8]], [[XI8]]
92+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[X]] to i32
93+
; CHECK-NEXT: [[R:%.*]] = icmp uge i32 [[TMP1]], [[Y]]
9994
; CHECK-NEXT: ret i1 [[R]]
10095
;
10196
%x_lb_only = icmp ult i64 %x, 123
@@ -156,9 +151,8 @@ define i1 @icmp_trunc_x_trunc_y_swap0(i33 %x, i32 %y) {
156151
; CHECK-NEXT: [[Y_LB_ONLY:%.*]] = icmp ult i32 [[Y:%.*]], 65536
157152
; CHECK-NEXT: call void @llvm.assume(i1 [[X_LB_ONLY]])
158153
; CHECK-NEXT: call void @llvm.assume(i1 [[Y_LB_ONLY]])
159-
; CHECK-NEXT: [[X16:%.*]] = trunc i33 [[X]] to i16
160-
; CHECK-NEXT: [[Y16:%.*]] = trunc i32 [[Y]] to i16
161-
; CHECK-NEXT: [[R:%.*]] = icmp ule i16 [[X16]], [[Y16]]
154+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i33 [[X]] to i32
155+
; CHECK-NEXT: [[R:%.*]] = icmp ule i32 [[TMP1]], [[Y]]
162156
; CHECK-NEXT: ret i1 [[R]]
163157
;
164158
%x_lb_only = icmp ult i33 %x, 65536
@@ -177,9 +171,8 @@ define i1 @icmp_trunc_x_trunc_y_swap1(i33 %x, i32 %y) {
177171
; CHECK-NEXT: [[Y_LB_ONLY:%.*]] = icmp ult i32 [[Y:%.*]], 65536
178172
; CHECK-NEXT: call void @llvm.assume(i1 [[X_LB_ONLY]])
179173
; CHECK-NEXT: call void @llvm.assume(i1 [[Y_LB_ONLY]])
180-
; CHECK-NEXT: [[X16:%.*]] = trunc i33 [[X]] to i16
181-
; CHECK-NEXT: [[Y16:%.*]] = trunc i32 [[Y]] to i16
182-
; CHECK-NEXT: [[R:%.*]] = icmp ule i16 [[Y16]], [[X16]]
174+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i33 [[X]] to i32
175+
; CHECK-NEXT: [[R:%.*]] = icmp uge i32 [[TMP1]], [[Y]]
183176
; CHECK-NEXT: ret i1 [[R]]
184177
;
185178
%x_lb_only = icmp ult i33 %x, 65536
@@ -196,9 +189,8 @@ define i1 @icmp_trunc_x_zext_y(i32 %x, i8 %y) {
196189
; CHECK-LABEL: @icmp_trunc_x_zext_y(
197190
; CHECK-NEXT: [[X_LB_ONLY:%.*]] = icmp ult i32 [[X:%.*]], 65536
198191
; CHECK-NEXT: call void @llvm.assume(i1 [[X_LB_ONLY]])
199-
; CHECK-NEXT: [[X16:%.*]] = trunc i32 [[X]] to i16
200-
; CHECK-NEXT: [[Y16:%.*]] = zext i8 [[Y:%.*]] to i16
201-
; CHECK-NEXT: [[R:%.*]] = icmp ugt i16 [[X16]], [[Y16]]
192+
; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[Y:%.*]] to i32
193+
; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[TMP1]], [[X]]
202194
; CHECK-NEXT: ret i1 [[R]]
203195
;
204196
%x_lb_only = icmp ult i32 %x, 65536
@@ -213,9 +205,8 @@ define i1 @icmp_trunc_x_zext_y_2(i32 %x, i8 %y) {
213205
; CHECK-LABEL: @icmp_trunc_x_zext_y_2(
214206
; CHECK-NEXT: [[X_LB_ONLY:%.*]] = icmp ult i32 [[X:%.*]], 65536
215207
; CHECK-NEXT: call void @llvm.assume(i1 [[X_LB_ONLY]])
216-
; CHECK-NEXT: [[X16:%.*]] = trunc i32 [[X]] to i16
217-
; CHECK-NEXT: [[Y16:%.*]] = zext i8 [[Y:%.*]] to i16
218-
; CHECK-NEXT: [[R:%.*]] = icmp uge i16 [[Y16]], [[X16]]
208+
; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[Y:%.*]] to i32
209+
; CHECK-NEXT: [[R:%.*]] = icmp uge i32 [[TMP1]], [[X]]
219210
; CHECK-NEXT: ret i1 [[R]]
220211
;
221212
%x_lb_only = icmp ult i32 %x, 65536
@@ -230,9 +221,8 @@ define i1 @icmp_trunc_x_zext_y_3(i6 %x, i32 %y) {
230221
; CHECK-LABEL: @icmp_trunc_x_zext_y_3(
231222
; CHECK-NEXT: [[Y_LB_ONLY:%.*]] = icmp ult i32 [[Y:%.*]], 65536
232223
; CHECK-NEXT: call void @llvm.assume(i1 [[Y_LB_ONLY]])
233-
; CHECK-NEXT: [[X16:%.*]] = zext i6 [[X:%.*]] to i16
234-
; CHECK-NEXT: [[Y16:%.*]] = trunc i32 [[Y]] to i16
235-
; CHECK-NEXT: [[R:%.*]] = icmp ne i16 [[Y16]], [[X16]]
224+
; CHECK-NEXT: [[TMP1:%.*]] = zext i6 [[X:%.*]] to i32
225+
; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[TMP1]], [[Y]]
236226
; CHECK-NEXT: ret i1 [[R]]
237227
;
238228
%y_lb_only = icmp ult i32 %y, 65536

0 commit comments

Comments
 (0)