Skip to content

Commit e8af134

Browse files
authored
[InstCombine] Generalize trunc-shift-icmp fold from (1 << Y) to (Pow2 << Y) (llvm#169163)
Extends the `icmp(trunc(shl))` fold to handle any power of 2 constant as the shift base, not just 1. This generalizes the following patterns by adjusting the comparison offsets by `log2(Pow2)`. ```llvm (trunc (1 << Y) to iN) == 0 --> Y u>= N (trunc (1 << Y) to iN) != 0 --> Y u< N (trunc (1 << Y) to iN) == 2**C --> Y == C (trunc (1 << Y) to iN) != 2**C --> Y != C ; to (trunc (Pow2 << Y) to iN) == 0 --> Y u>= N - log2(Pow2) (trunc (Pow2 << Y) to iN) != 0 --> Y u< N - log2(Pow2) (trunc (Pow2 << Y) to iN) == 2**C --> Y == C - log2(Pow2) (trunc (Pow2 << Y) to iN) != 2**C --> Y != C - log2(Pow2) ``` Proof: https://alive2.llvm.org/ce/z/2zwTkp
1 parent cc4dd01 commit e8af134

File tree

2 files changed

+51
-41
lines changed

2 files changed

+51
-41
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,20 +1465,24 @@ Instruction *InstCombinerImpl::foldICmpTruncConstant(ICmpInst &Cmp,
14651465
ConstantInt::get(V->getType(), 1));
14661466
}
14671467

1468-
// TODO: Handle any shifted constant by subtracting trailing zeros.
14691468
// TODO: Handle non-equality predicates.
14701469
Value *Y;
1471-
if (Cmp.isEquality() && match(X, m_Shl(m_One(), m_Value(Y)))) {
1472-
// (trunc (1 << Y) to iN) == 0 --> Y u>= N
1473-
// (trunc (1 << Y) to iN) != 0 --> Y u< N
1470+
const APInt *Pow2;
1471+
if (Cmp.isEquality() && match(X, m_Shl(m_Power2(Pow2), m_Value(Y))) &&
1472+
DstBits > Pow2->logBase2()) {
1473+
// (trunc (Pow2 << Y) to iN) == 0 --> Y u>= N - log2(Pow2)
1474+
// (trunc (Pow2 << Y) to iN) != 0 --> Y u< N - log2(Pow2)
1475+
// iff N > log2(Pow2)
14741476
if (C.isZero()) {
14751477
auto NewPred = (Pred == Cmp.ICMP_EQ) ? Cmp.ICMP_UGE : Cmp.ICMP_ULT;
1476-
return new ICmpInst(NewPred, Y, ConstantInt::get(SrcTy, DstBits));
1478+
return new ICmpInst(NewPred, Y,
1479+
ConstantInt::get(SrcTy, DstBits - Pow2->logBase2()));
14771480
}
1478-
// (trunc (1 << Y) to iN) == 2**C --> Y == C
1479-
// (trunc (1 << Y) to iN) != 2**C --> Y != C
1481+
// (trunc (Pow2 << Y) to iN) == 2**C --> Y == C - log2(Pow2)
1482+
// (trunc (Pow2 << Y) to iN) != 2**C --> Y != C - log2(Pow2)
14801483
if (C.isPowerOf2())
1481-
return new ICmpInst(Pred, Y, ConstantInt::get(SrcTy, C.logBase2()));
1484+
return new ICmpInst(
1485+
Pred, Y, ConstantInt::get(SrcTy, C.logBase2() - Pow2->logBase2()));
14821486
}
14831487

14841488
if (Cmp.isEquality() && (Trunc->hasOneUse() || Trunc->hasNoUnsignedWrap())) {

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

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -407,13 +407,9 @@ define i1 @shl1_trunc_ne0_use2(i37 %a) {
407407
ret i1 %r
408408
}
409409

410-
; TODO: A > 4
411-
412410
define i1 @shl2_trunc_eq0(i9 %a) {
413411
; CHECK-LABEL: @shl2_trunc_eq0(
414-
; CHECK-NEXT: [[SHL:%.*]] = shl i9 2, [[A:%.*]]
415-
; CHECK-NEXT: [[T:%.*]] = trunc i9 [[SHL]] to i6
416-
; CHECK-NEXT: [[R:%.*]] = icmp eq i6 [[T]], 0
412+
; CHECK-NEXT: [[R:%.*]] = icmp ugt i9 [[A:%.*]], 4
417413
; CHECK-NEXT: ret i1 [[R]]
418414
;
419415
%shl = shl i9 2, %a
@@ -424,9 +420,7 @@ define i1 @shl2_trunc_eq0(i9 %a) {
424420

425421
define i1 @shl2_trunc_ne0(i9 %a) {
426422
; CHECK-LABEL: @shl2_trunc_ne0(
427-
; CHECK-NEXT: [[SHL:%.*]] = shl i9 2, [[A:%.*]]
428-
; CHECK-NEXT: [[T:%.*]] = trunc i9 [[SHL]] to i6
429-
; CHECK-NEXT: [[R:%.*]] = icmp ne i6 [[T]], 0
423+
; CHECK-NEXT: [[R:%.*]] = icmp ult i9 [[A:%.*]], 5
430424
; CHECK-NEXT: ret i1 [[R]]
431425
;
432426
%shl = shl i9 2, %a
@@ -450,9 +444,7 @@ define i1 @shl3_trunc_eq0(i9 %a) {
450444

451445
define <2 x i1> @shl4_trunc_ne0(<2 x i8> %a) {
452446
; CHECK-LABEL: @shl4_trunc_ne0(
453-
; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i8> <i8 4, i8 poison>, [[A:%.*]]
454-
; CHECK-NEXT: [[T:%.*]] = trunc <2 x i8> [[SHL]] to <2 x i5>
455-
; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i5> [[T]], zeroinitializer
447+
; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i8> [[A:%.*]], splat (i8 3)
456448
; CHECK-NEXT: ret <2 x i1> [[R]]
457449
;
458450
%shl = shl <2 x i8> <i8 4, i8 poison>, %a
@@ -461,6 +453,16 @@ define <2 x i1> @shl4_trunc_ne0(<2 x i8> %a) {
461453
ret <2 x i1> %r
462454
}
463455

456+
define i1 @shl5_trunc_ne0(i9 %a) {
457+
; CHECK-LABEL: @shl5_trunc_ne0(
458+
; CHECK-NEXT: [[R:%.*]] = icmp ult i9 [[A:%.*]], 4
459+
; CHECK-NEXT: ret i1 [[R]]
460+
;
461+
%shl = shl i9 4, %a
462+
%t = trunc i9 %shl to i6
463+
%r = icmp ne i6 %t, 0
464+
ret i1 %r
465+
}
464466

465467
; TODO: A < 5
466468

@@ -507,17 +509,9 @@ define i1 @shl1_trunc_ne32(i8 %a) {
507509
}
508510

509511
define i1 @shl2_trunc_eq8_i32(i32 %a) {
510-
; DL64-LABEL: @shl2_trunc_eq8_i32(
511-
; DL64-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]]
512-
; DL64-NEXT: [[TMP1:%.*]] = and i32 [[SHL]], 65534
513-
; DL64-NEXT: [[R:%.*]] = icmp eq i32 [[TMP1]], 8
514-
; DL64-NEXT: ret i1 [[R]]
515-
;
516-
; DL8-LABEL: @shl2_trunc_eq8_i32(
517-
; DL8-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]]
518-
; DL8-NEXT: [[T:%.*]] = trunc i32 [[SHL]] to i16
519-
; DL8-NEXT: [[R:%.*]] = icmp eq i16 [[T]], 8
520-
; DL8-NEXT: ret i1 [[R]]
512+
; CHECK-LABEL: @shl2_trunc_eq8_i32(
513+
; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[A:%.*]], 2
514+
; CHECK-NEXT: ret i1 [[R]]
521515
;
522516
%shl = shl i32 2, %a
523517
%t = trunc i32 %shl to i16
@@ -526,24 +520,36 @@ define i1 @shl2_trunc_eq8_i32(i32 %a) {
526520
}
527521

528522
define i1 @shl2_trunc_ne8_i32(i32 %a) {
529-
; DL64-LABEL: @shl2_trunc_ne8_i32(
530-
; DL64-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]]
531-
; DL64-NEXT: [[TMP1:%.*]] = and i32 [[SHL]], 65534
532-
; DL64-NEXT: [[R:%.*]] = icmp ne i32 [[TMP1]], 8
533-
; DL64-NEXT: ret i1 [[R]]
534-
;
535-
; DL8-LABEL: @shl2_trunc_ne8_i32(
536-
; DL8-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]]
537-
; DL8-NEXT: [[T:%.*]] = trunc i32 [[SHL]] to i16
538-
; DL8-NEXT: [[R:%.*]] = icmp ne i16 [[T]], 8
539-
; DL8-NEXT: ret i1 [[R]]
523+
; CHECK-LABEL: @shl2_trunc_ne8_i32(
524+
; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[A:%.*]], 2
525+
; CHECK-NEXT: ret i1 [[R]]
540526
;
541527
%shl = shl i32 2, %a
542528
%t = trunc i32 %shl to i16
543529
%r = icmp ne i16 %t, 8
544530
ret i1 %r
545531
}
546532

533+
define i1 @neg_shl2_trunc_eq0_i8(i8 %a) {
534+
; CHECK-LABEL: @neg_shl2_trunc_eq0_i8(
535+
; CHECK-NEXT: ret i1 true
536+
;
537+
%shl = shl i8 128, %a
538+
%t = trunc i8 %shl to i6
539+
%r = icmp eq i6 %t, 0
540+
ret i1 %r
541+
}
542+
543+
define i1 @neg_shl2_trunc_ne0_i8(i8 %a) {
544+
; CHECK-LABEL: @neg_shl2_trunc_ne0_i8(
545+
; CHECK-NEXT: ret i1 false
546+
;
547+
%shl = shl i8 128, %a
548+
%t = trunc i8 %shl to i6
549+
%r = icmp ne i6 %t, 0
550+
ret i1 %r
551+
}
552+
547553
define i1 @shl1_trunc_sgt4(i32 %a) {
548554
; CHECK-LABEL: @shl1_trunc_sgt4(
549555
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 1, [[A:%.*]]

0 commit comments

Comments
 (0)