Index: llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4598,19 +4598,30 @@ // The trunc masks high bits while the compare may effectively mask low bits. Value *X; const APInt *C; - if (match(Op0, m_OneUse(m_Trunc(m_Value(X)))) && match(Op1, m_Power2(C))) { - if (Pred == ICmpInst::ICMP_ULT) { - // (trunc X) u< Pow2C --> (X & MaskC) == 0 - unsigned SrcBits = X->getType()->getScalarSizeInBits(); - unsigned DstBits = Op0->getType()->getScalarSizeInBits(); - APInt MaskC = APInt::getOneBitSet(SrcBits, DstBits) - C->zext(SrcBits); + if (!match(Op0, m_OneUse(m_Trunc(m_Value(X)))) || !match(Op1, m_APInt(C))) + return nullptr; + + unsigned SrcBits = X->getType()->getScalarSizeInBits(); + if (Pred == ICmpInst::ICMP_ULT) { + // If C is a power-of-2: + // (trunc X) u< C --> X & (~C + 1) == 0 (are all masked-high-bits clear?) + if (C->isPowerOf2()) { + Constant *MaskC = ConstantInt::get(X->getType(), (~*C + 1).zext(SrcBits)); Value *And = Builder.CreateAnd(X, MaskC); Constant *Zero = ConstantInt::getNullValue(X->getType()); return new ICmpInst(ICmpInst::ICMP_EQ, And, Zero); } - // TODO: Handle ugt. + // If C is a high-bit mask: + // (trunc X) u< C --> (X & C) != C (are any masked-high-bits clear?) + if ((~(*C)).isMask()) { + Constant *MaskC = ConstantInt::get(X->getType(), C->zext(SrcBits)); + Value *And = Builder.CreateAnd(X, MaskC); + return new ICmpInst(ICmpInst::ICMP_NE, And, MaskC); + } } + // TODO: Handle ugt. + return nullptr; } Index: llvm/test/Transforms/InstCombine/icmp-trunc.ll =================================================================== --- llvm/test/Transforms/InstCombine/icmp-trunc.ll +++ 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>