Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4623,6 +4623,41 @@ } } +// Transform pattern like: +// (1 << Y) u<= X +// (1 << Y) u> X +// Into: +// (X l>> Y) != 0 +// (X l>> Y) == 0 +static Instruction *foldICmpWithHighBitMask(ICmpInst &Cmp, + InstCombiner::BuilderTy &Builder) { + ICmpInst::Predicate Pred; + Value *X, *Y; + if (!match(&Cmp, + m_c_ICmp(Pred, m_OneUse(m_Shl(m_One(), m_Value(Y))), m_Value(X)))) + return nullptr; + + // We want X to be the icmp's second operand, so swap predicate if it is not. + if (Cmp.getOperand(0) == X) + Pred = Cmp.getSwappedPredicate(); + + ICmpInst::Predicate NewPred; + switch (Pred) { + case ICmpInst::ICMP_ULE: + NewPred = ICmpInst::ICMP_NE; + break; + case ICmpInst::ICMP_UGT: + NewPred = ICmpInst::ICMP_EQ; + break; + default: + return nullptr; + } + + Value *NewX = Builder.CreateLShr(X, Y, X->getName() + ".highbits"); + Constant *Zero = Constant::getNullValue(NewX->getType()); + return CmpInst::Create(Instruction::ICmp, NewPred, NewX, Zero); +} + static Instruction *foldVectorCmp(CmpInst &Cmp, InstCombiner::BuilderTy &Builder) { // If both arguments of the cmp are shuffles that use the same mask and @@ -4913,6 +4948,9 @@ return foldICmpAddOpConst(X, *C, I.getSwappedPredicate()); } + if (Instruction *Res = foldICmpWithHighBitMask(I, Builder)) + return Res; + if (I.getType()->isVectorTy()) if (Instruction *Res = foldVectorCmp(I, Builder)) return Res; Index: test/Transforms/InstCombine/icmp-ugt-of-shl-1-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll =================================================================== --- test/Transforms/InstCombine/icmp-ugt-of-shl-1-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll +++ test/Transforms/InstCombine/icmp-ugt-of-shl-1-by-bits-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll @@ -14,8 +14,8 @@ define i1 @p0(i8 %val, i8 %bits) { ; CHECK-LABEL: @p0( -; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[T0]], [[VAL:%.*]] +; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[VAL_HIGHBITS]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t0 = shl i8 1, %bits @@ -29,8 +29,8 @@ define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) { ; CHECK-LABEL: @p1_vec( -; CHECK-NEXT: [[T0:%.*]] = shl <2 x i8> , [[BITS:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ugt <2 x i8> [[T0]], [[VAL:%.*]] +; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr <2 x i8> [[VAL:%.*]], [[BITS:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[VAL_HIGHBITS]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t0 = shl <2 x i8> , %bits @@ -40,8 +40,8 @@ define <3 x i1> @p2_vec_undef(<3 x i8> %val, <3 x i8> %bits) { ; CHECK-LABEL: @p2_vec_undef( -; CHECK-NEXT: [[T0:%.*]] = shl <3 x i8> , [[BITS:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ugt <3 x i8> [[T0]], [[VAL:%.*]] +; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp eq <3 x i8> [[VAL_HIGHBITS]], zeroinitializer ; CHECK-NEXT: ret <3 x i1> [[R]] ; %t0 = shl <3 x i8> , %bits @@ -57,9 +57,9 @@ define i1 @c0(i8 %bits) { ; CHECK-LABEL: @c0( -; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS:%.*]] ; CHECK-NEXT: [[VAL:%.*]] = call i8 @gen8() -; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[VAL]], [[T0]] +; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL]], [[BITS:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[VAL_HIGHBITS]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t0 = shl i8 1, %bits Index: test/Transforms/InstCombine/icmp-ule-of-shl-1-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll =================================================================== --- test/Transforms/InstCombine/icmp-ule-of-shl-1-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll +++ test/Transforms/InstCombine/icmp-ule-of-shl-1-by-bits-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll @@ -14,8 +14,8 @@ define i1 @p0(i8 %val, i8 %bits) { ; CHECK-LABEL: @p0( -; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ule i8 [[T0]], [[VAL:%.*]] +; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t0 = shl i8 1, %bits @@ -29,8 +29,8 @@ define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) { ; CHECK-LABEL: @p1_vec( -; CHECK-NEXT: [[T0:%.*]] = shl <2 x i8> , [[BITS:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ule <2 x i8> [[T0]], [[VAL:%.*]] +; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr <2 x i8> [[VAL:%.*]], [[BITS:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[VAL_HIGHBITS]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %t0 = shl <2 x i8> , %bits @@ -40,8 +40,8 @@ define <3 x i1> @p2_vec_undef(<3 x i8> %val, <3 x i8> %bits) { ; CHECK-LABEL: @p2_vec_undef( -; CHECK-NEXT: [[T0:%.*]] = shl <3 x i8> , [[BITS:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ule <3 x i8> [[T0]], [[VAL:%.*]] +; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer ; CHECK-NEXT: ret <3 x i1> [[R]] ; %t0 = shl <3 x i8> , %bits @@ -57,9 +57,9 @@ define i1 @c0(i8 %bits) { ; CHECK-LABEL: @c0( -; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[BITS:%.*]] ; CHECK-NEXT: [[VAL:%.*]] = call i8 @gen8() -; CHECK-NEXT: [[R:%.*]] = icmp uge i8 [[VAL]], [[T0]] +; CHECK-NEXT: [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL]], [[BITS:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %t0 = shl i8 1, %bits