From e137fbea357598d1582923d53e6d239c0946b5a1 Mon Sep 17 00:00:00 2001 From: Pedro Lobo Date: Sat, 22 Nov 2025 12:31:35 +0000 Subject: [PATCH 1/3] Pre-commit tests --- .../test/Transforms/InstCombine/icmp-trunc.ll | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/llvm/test/Transforms/InstCombine/icmp-trunc.ll b/llvm/test/Transforms/InstCombine/icmp-trunc.ll index ad76ef7329b0a..ebd5346e67c1c 100644 --- a/llvm/test/Transforms/InstCombine/icmp-trunc.ll +++ b/llvm/test/Transforms/InstCombine/icmp-trunc.ll @@ -407,8 +407,6 @@ define i1 @shl1_trunc_ne0_use2(i37 %a) { ret i1 %r } -; TODO: A > 4 - define i1 @shl2_trunc_eq0(i9 %a) { ; CHECK-LABEL: @shl2_trunc_eq0( ; CHECK-NEXT: [[SHL:%.*]] = shl i9 2, [[A:%.*]] @@ -461,6 +459,18 @@ define <2 x i1> @shl4_trunc_ne0(<2 x i8> %a) { ret <2 x i1> %r } +define i1 @shl5_trunc_ne0(i9 %a) { +; CHECK-LABEL: @shl5_trunc_ne0( +; CHECK-NEXT: [[SHL:%.*]] = shl i9 4, [[A:%.*]] +; CHECK-NEXT: [[T:%.*]] = trunc i9 [[SHL]] to i6 +; CHECK-NEXT: [[R:%.*]] = icmp ne i6 [[T]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %shl = shl i9 4, %a + %t = trunc i9 %shl to i6 + %r = icmp ne i6 %t, 0 + ret i1 %r +} ; TODO: A < 5 @@ -544,6 +554,26 @@ define i1 @shl2_trunc_ne8_i32(i32 %a) { ret i1 %r } +define i1 @neg_shl2_trunc_eq0_i8(i8 %a) { +; CHECK-LABEL: @neg_shl2_trunc_eq0_i8( +; CHECK-NEXT: ret i1 true +; + %shl = shl i8 256, %a + %t = trunc i8 %shl to i6 + %r = icmp eq i6 %t, 0 + ret i1 %r +} + +define i1 @neg_shl2_trunc_ne0_i8(i8 %a) { +; CHECK-LABEL: @neg_shl2_trunc_ne0_i8( +; CHECK-NEXT: ret i1 false +; + %shl = shl i8 128, %a + %t = trunc i8 %shl to i6 + %r = icmp ne i6 %t, 0 + ret i1 %r +} + define i1 @shl1_trunc_sgt4(i32 %a) { ; CHECK-LABEL: @shl1_trunc_sgt4( ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 1, [[A:%.*]] From 237ba9a0c119c666455d5b7eca494cd3d20d999a Mon Sep 17 00:00:00 2001 From: Pedro Lobo Date: Sat, 22 Nov 2025 12:31:36 +0000 Subject: [PATCH 2/3] [InstCombine] Generalize trunc-shift-icmp fold from (1 << Y) to (Pow2 << Y) 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 --- .../InstCombine/InstCombineCompares.cpp | 20 +++++---- .../test/Transforms/InstCombine/icmp-trunc.ll | 44 +++++-------------- 2 files changed, 22 insertions(+), 42 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index f153db177cac1..cf6e7315114dc 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1465,20 +1465,24 @@ Instruction *InstCombinerImpl::foldICmpTruncConstant(ICmpInst &Cmp, ConstantInt::get(V->getType(), 1)); } - // TODO: Handle any shifted constant by subtracting trailing zeros. // TODO: Handle non-equality predicates. Value *Y; - if (Cmp.isEquality() && match(X, m_Shl(m_One(), m_Value(Y)))) { - // (trunc (1 << Y) to iN) == 0 --> Y u>= N - // (trunc (1 << Y) to iN) != 0 --> Y u< N + const APInt *Pow2; + if (Cmp.isEquality() && match(X, m_Shl(m_Power2(Pow2), m_Value(Y))) && + DstBits > Pow2->logBase2()) { + // (trunc (Pow2 << Y) to iN) == 0 --> Y u>= N - log2(Pow2) + // (trunc (Pow2 << Y) to iN) != 0 --> Y u< N - log2(Pow2) + // iff N > log2(Pow2) if (C.isZero()) { auto NewPred = (Pred == Cmp.ICMP_EQ) ? Cmp.ICMP_UGE : Cmp.ICMP_ULT; - return new ICmpInst(NewPred, Y, ConstantInt::get(SrcTy, DstBits)); + return new ICmpInst(NewPred, Y, + ConstantInt::get(SrcTy, DstBits - Pow2->logBase2())); } - // (trunc (1 << Y) to iN) == 2**C --> Y == C - // (trunc (1 << Y) to iN) != 2**C --> Y != C + // (trunc (Pow2 << Y) to iN) == 2**C --> Y == C - log2(Pow2) + // (trunc (Pow2 << Y) to iN) != 2**C --> Y != C - log2(Pow2) if (C.isPowerOf2()) - return new ICmpInst(Pred, Y, ConstantInt::get(SrcTy, C.logBase2())); + return new ICmpInst( + Pred, Y, ConstantInt::get(SrcTy, C.logBase2() - Pow2->logBase2())); } if (Cmp.isEquality() && (Trunc->hasOneUse() || Trunc->hasNoUnsignedWrap())) { diff --git a/llvm/test/Transforms/InstCombine/icmp-trunc.ll b/llvm/test/Transforms/InstCombine/icmp-trunc.ll index ebd5346e67c1c..6e7b63cfd9589 100644 --- a/llvm/test/Transforms/InstCombine/icmp-trunc.ll +++ b/llvm/test/Transforms/InstCombine/icmp-trunc.ll @@ -409,9 +409,7 @@ define i1 @shl1_trunc_ne0_use2(i37 %a) { define i1 @shl2_trunc_eq0(i9 %a) { ; CHECK-LABEL: @shl2_trunc_eq0( -; CHECK-NEXT: [[SHL:%.*]] = shl i9 2, [[A:%.*]] -; CHECK-NEXT: [[T:%.*]] = trunc i9 [[SHL]] to i6 -; CHECK-NEXT: [[R:%.*]] = icmp eq i6 [[T]], 0 +; CHECK-NEXT: [[R:%.*]] = icmp ugt i9 [[A:%.*]], 4 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i9 2, %a @@ -422,9 +420,7 @@ define i1 @shl2_trunc_eq0(i9 %a) { define i1 @shl2_trunc_ne0(i9 %a) { ; CHECK-LABEL: @shl2_trunc_ne0( -; CHECK-NEXT: [[SHL:%.*]] = shl i9 2, [[A:%.*]] -; CHECK-NEXT: [[T:%.*]] = trunc i9 [[SHL]] to i6 -; CHECK-NEXT: [[R:%.*]] = icmp ne i6 [[T]], 0 +; CHECK-NEXT: [[R:%.*]] = icmp ult i9 [[A:%.*]], 5 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i9 2, %a @@ -448,9 +444,7 @@ define i1 @shl3_trunc_eq0(i9 %a) { define <2 x i1> @shl4_trunc_ne0(<2 x i8> %a) { ; CHECK-LABEL: @shl4_trunc_ne0( -; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i8> , [[A:%.*]] -; CHECK-NEXT: [[T:%.*]] = trunc <2 x i8> [[SHL]] to <2 x i5> -; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i5> [[T]], zeroinitializer +; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i8> [[A:%.*]], splat (i8 3) ; CHECK-NEXT: ret <2 x i1> [[R]] ; %shl = shl <2 x i8> , %a @@ -461,9 +455,7 @@ define <2 x i1> @shl4_trunc_ne0(<2 x i8> %a) { define i1 @shl5_trunc_ne0(i9 %a) { ; CHECK-LABEL: @shl5_trunc_ne0( -; CHECK-NEXT: [[SHL:%.*]] = shl i9 4, [[A:%.*]] -; CHECK-NEXT: [[T:%.*]] = trunc i9 [[SHL]] to i6 -; CHECK-NEXT: [[R:%.*]] = icmp ne i6 [[T]], 0 +; CHECK-NEXT: [[R:%.*]] = icmp ult i9 [[A:%.*]], 4 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i9 4, %a @@ -517,17 +509,9 @@ define i1 @shl1_trunc_ne32(i8 %a) { } define i1 @shl2_trunc_eq8_i32(i32 %a) { -; DL64-LABEL: @shl2_trunc_eq8_i32( -; DL64-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]] -; DL64-NEXT: [[TMP1:%.*]] = and i32 [[SHL]], 65534 -; DL64-NEXT: [[R:%.*]] = icmp eq i32 [[TMP1]], 8 -; DL64-NEXT: ret i1 [[R]] -; -; DL8-LABEL: @shl2_trunc_eq8_i32( -; DL8-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]] -; DL8-NEXT: [[T:%.*]] = trunc i32 [[SHL]] to i16 -; DL8-NEXT: [[R:%.*]] = icmp eq i16 [[T]], 8 -; DL8-NEXT: ret i1 [[R]] +; CHECK-LABEL: @shl2_trunc_eq8_i32( +; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[A:%.*]], 2 +; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i32 2, %a %t = trunc i32 %shl to i16 @@ -536,17 +520,9 @@ define i1 @shl2_trunc_eq8_i32(i32 %a) { } define i1 @shl2_trunc_ne8_i32(i32 %a) { -; DL64-LABEL: @shl2_trunc_ne8_i32( -; DL64-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]] -; DL64-NEXT: [[TMP1:%.*]] = and i32 [[SHL]], 65534 -; DL64-NEXT: [[R:%.*]] = icmp ne i32 [[TMP1]], 8 -; DL64-NEXT: ret i1 [[R]] -; -; DL8-LABEL: @shl2_trunc_ne8_i32( -; DL8-NEXT: [[SHL:%.*]] = shl i32 2, [[A:%.*]] -; DL8-NEXT: [[T:%.*]] = trunc i32 [[SHL]] to i16 -; DL8-NEXT: [[R:%.*]] = icmp ne i16 [[T]], 8 -; DL8-NEXT: ret i1 [[R]] +; CHECK-LABEL: @shl2_trunc_ne8_i32( +; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[A:%.*]], 2 +; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i32 2, %a %t = trunc i32 %shl to i16 From bfc44d047407483adf11a2d747b775c546600d9a Mon Sep 17 00:00:00 2001 From: Pedro Lobo Date: Sat, 22 Nov 2025 13:32:39 +0000 Subject: [PATCH 3/3] Fix test --- llvm/test/Transforms/InstCombine/icmp-trunc.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/Transforms/InstCombine/icmp-trunc.ll b/llvm/test/Transforms/InstCombine/icmp-trunc.ll index 6e7b63cfd9589..431fc2b4f062c 100644 --- a/llvm/test/Transforms/InstCombine/icmp-trunc.ll +++ b/llvm/test/Transforms/InstCombine/icmp-trunc.ll @@ -534,7 +534,7 @@ define i1 @neg_shl2_trunc_eq0_i8(i8 %a) { ; CHECK-LABEL: @neg_shl2_trunc_eq0_i8( ; CHECK-NEXT: ret i1 true ; - %shl = shl i8 256, %a + %shl = shl i8 128, %a %t = trunc i8 %shl to i6 %r = icmp eq i6 %t, 0 ret i1 %r