diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4627,16 +4627,39 @@ unsigned SrcBits = X->getType()->getScalarSizeInBits(); if (Pred == ICmpInst::ICMP_ULT) { if (C->isPowerOf2()) { - // If C is a power-of-2: + // If C is a power-of-2 (one set bit): // (trunc X) u< C --> (X & -C) == 0 (are all masked-high-bits clear?) Constant *MaskC = ConstantInt::get(X->getType(), (-*C).zext(SrcBits)); Value *And = Builder.CreateAnd(X, MaskC); Constant *Zero = ConstantInt::getNullValue(X->getType()); return new ICmpInst(ICmpInst::ICMP_EQ, And, Zero); } - // TODO: Handle C is negative-power-of-2. + // If C is a negative power-of-2 (high-bit mask): + // (trunc X) u< C --> (X & C) != C (are any masked-high-bits clear?) + if (C->isNegatedPowerOf2()) { + Constant *MaskC = ConstantInt::get(X->getType(), C->zext(SrcBits)); + Value *And = Builder.CreateAnd(X, MaskC); + return new ICmpInst(ICmpInst::ICMP_NE, And, MaskC); + } + } + + if (Pred == ICmpInst::ICMP_UGT) { + // If C is a low-bit-mask (C+1 is a power-of-2): + // (trunc X) u> C --> (X & ~C) != 0 (are any masked-high-bits set?) + if (C->isMask()) { + Constant *MaskC = ConstantInt::get(X->getType(), (~*C).zext(SrcBits)); + Value *And = Builder.CreateAnd(X, MaskC); + Constant *Zero = ConstantInt::getNullValue(X->getType()); + return new ICmpInst(ICmpInst::ICMP_NE, And, Zero); + } + // If C is not-of-power-of-2 (one clear bit): + // (trunc X) u> C --> (X & (C+1)) == C+1 (are all masked-high-bits set?) + if ((~*C).isPowerOf2()) { + Constant *MaskC = ConstantInt::get(X->getType(), (*C + 1).zext(SrcBits)); + Value *And = Builder.CreateAnd(X, MaskC); + return new ICmpInst(ICmpInst::ICMP_EQ, And, MaskC); + } } - // TODO: Handle ugt. return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/icmp-trunc.ll b/llvm/test/Transforms/InstCombine/icmp-trunc.ll --- a/llvm/test/Transforms/InstCombine/icmp-trunc.ll +++ b/llvm/test/Transforms/InstCombine/icmp-trunc.ll @@ -71,8 +71,8 @@ define i1 @ult_192(i32 %x) { ; CHECK-LABEL: @ult_192( -; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 -; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[T]], -64 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 192 +; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[TMP1]], 192 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 @@ -82,8 +82,8 @@ define <2 x i1> @ult_2044_splat(<2 x i16> %x) { ; CHECK-LABEL: @ult_2044_splat( -; CHECK-NEXT: [[T:%.*]] = trunc <2 x i16> [[X:%.*]] to <2 x i11> -; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i11> [[T]], +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i16> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t = trunc <2 x i16> %x to <2 x i11> @@ -91,6 +91,8 @@ ret <2 x i1> %r } +; negative test - need high-bit-mask constant + define i1 @ult_96(i32 %x) { ; CHECK-LABEL: @ult_96( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 @@ -102,6 +104,8 @@ ret i1 %r } +; negative test - no extra use allowed + define i1 @ult_192_use(i32 %x) { ; CHECK-LABEL: @ult_192_use( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 @@ -117,8 +121,8 @@ define i1 @ugt_3(i32 %x) { ; CHECK-LABEL: @ugt_3( -; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 -; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[T]], 3 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 252 +; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 @@ -128,8 +132,8 @@ define <2 x i1> @ugt_7_splat(<2 x i16> %x) { ; CHECK-LABEL: @ugt_7_splat( -; CHECK-NEXT: [[T:%.*]] = trunc <2 x i16> [[X:%.*]] to <2 x i11> -; CHECK-NEXT: [[R:%.*]] = icmp ugt <2 x i11> [[T]], +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i16> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t = trunc <2 x i16> %x to <2 x i11> @@ -137,6 +141,8 @@ ret <2 x i1> %r } +; negative test - need low-bit-mask constant + define i1 @ugt_4(i32 %x) { ; CHECK-LABEL: @ugt_4( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 @@ -148,6 +154,8 @@ ret i1 %r } +; negative test - no extra use allowed + define i1 @ugt_3_use(i32 %x) { ; CHECK-LABEL: @ugt_3_use( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 @@ -163,8 +171,8 @@ define i1 @ugt_253(i32 %x) { ; CHECK-LABEL: @ugt_253( -; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 -; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[T]], -3 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 254 +; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[TMP1]], 254 ; CHECK-NEXT: ret i1 [[R]] ; %t = trunc i32 %x to i8 @@ -174,8 +182,8 @@ define <2 x i1> @ugt_2043_splat(<2 x i16> %x) { ; CHECK-LABEL: @ugt_2043_splat( -; CHECK-NEXT: [[T:%.*]] = trunc <2 x i16> [[X:%.*]] to <2 x i11> -; CHECK-NEXT: [[R:%.*]] = icmp ugt <2 x i11> [[T]], +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i16> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t = trunc <2 x i16> %x to <2 x i11> @@ -183,6 +191,8 @@ ret <2 x i1> %r } +; negative test - need not-of-power-of-2 constant + define i1 @ugt_252(i32 %x) { ; CHECK-LABEL: @ugt_252( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8 @@ -194,6 +204,8 @@ ret i1 %r } +; negative test - no extra use allowed + define i1 @ugt_253_use(i32 %x) { ; CHECK-LABEL: @ugt_253_use( ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8