Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1759,6 +1759,24 @@ } } + // (X & (signbit >> Z)) == 0 -> (X << Z) >= 0 + // (X & (signbit >> Z)) != 0 -> (X << Z) < 0 + Value *Z; + bool IsYShift = true; + BinaryOperator *Shift = dyn_cast(Y); + if (!Shift || !Shift->isShift()) { + Shift = dyn_cast(X); + IsYShift = false; + } + if (Shift && Shift->isShift() && And->hasOneUse() && C.isNullValue() && + match(IsYShift ? Y : X, m_LShr(m_SignMask(), m_Value(Z)))) { + Constant *Zero = Constant::getNullValue(Z->getType()); + Value *NewShift = Builder.CreateShl(IsYShift ? X : Y, Z); + auto NewPred = Cmp.getPredicate() == CmpInst::ICMP_EQ ? CmpInst::ICMP_SGE + : CmpInst::ICMP_SLT; + return new ICmpInst(NewPred, NewShift, Zero); + } + return nullptr; } @@ -2616,6 +2634,9 @@ return nullptr; if (auto *BO = dyn_cast(Cmp.getOperand(0))) { + if (Instruction *I = foldICmpBinOpEqualityWithConstant(Cmp, BO, *C)) + return I; + switch (BO->getOpcode()) { case Instruction::Xor: if (Instruction *I = foldICmpXorConstant(Cmp, BO, *C)) @@ -2661,9 +2682,6 @@ default: break; } - // TODO: These folds could be refactored to be part of the above calls. - if (Instruction *I = foldICmpBinOpEqualityWithConstant(Cmp, BO, *C)) - return I; } // Match against CmpInst LHS being instructions other than binary operators. Index: test/Transforms/InstCombine/exact.ll =================================================================== --- test/Transforms/InstCombine/exact.ll +++ test/Transforms/InstCombine/exact.ll @@ -176,7 +176,7 @@ define i1 @udiv_icmp1(i64 %X) { ; CHECK-LABEL: @udiv_icmp1( -; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 %X, 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i64 %X, 4 ; CHECK-NEXT: ret i1 [[TMP1]] ; %A = udiv exact i64 %X, 5 ; X/5 @@ -186,7 +186,7 @@ define <2 x i1> @udiv_icmp1_vec(<2 x i64> %X) { ; CHECK-LABEL: @udiv_icmp1_vec( -; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i64> %X, zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt <2 x i64> %X, ; CHECK-NEXT: ret <2 x i1> [[TMP1]] ; %A = udiv exact <2 x i64> %X, @@ -196,7 +196,7 @@ define i1 @udiv_icmp2(i64 %X) { ; CHECK-LABEL: @udiv_icmp2( -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 %X, 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 %X, 5 ; CHECK-NEXT: ret i1 [[TMP1]] ; %A = udiv exact i64 %X, 5 ; X/5 == 0 --> x == 0 @@ -206,7 +206,7 @@ define <2 x i1> @udiv_icmp2_vec(<2 x i64> %X) { ; CHECK-LABEL: @udiv_icmp2_vec( -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i64> %X, zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult <2 x i64> %X, ; CHECK-NEXT: ret <2 x i1> [[TMP1]] ; %A = udiv exact <2 x i64> %X, Index: test/Transforms/InstCombine/icmp-shift-and-signbit.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/icmp-shift-and-signbit.ll @@ -0,0 +1,27 @@ +; RUN: opt %s -instcombine -S | FileCheck %s + +; CHECK-LABEL: shl-and-signbit +; CHECK: [[SUB:%.*]] = add nsw i32 %x, -1 +; CHECK-NEXT: [[SHL:%.*]] = shl i32 %y, [[SUB]] +; CHECK-NEXT icmp slt i32 [[SHL]], 0 +define dso_local i32 @shl-and-signbit(i32 %x, i32 %y, i32 %a, i32 %b) { +entry: + %sub = sub nsw i32 %x, 1 + %shl = shl i32 %y, %sub + %and = and i32 %shl, -2147483648 + %tobool = icmp ne i32 %and, 0 + %selv = select i1 %tobool, i32 %a, i32 %b + ret i32 %selv +} + +; CHECK-LABEL: and-signbit-shr +; CHECK: [[SHL:%.*]] = shl i32 %x, %y +; CHECK-NEXT icmp slt i32 [[SHL]], 0 +define dso_local i32 @and-signbit-shr(i32 %x, i32 %y, i32 %a, i32 %b) { +entry: + %shr = lshr i32 -2147483648, %y + %and = and i32 %shr, %x + %tobool = icmp ne i32 %and, 0 + %selv = select i1 %tobool, i32 %a, i32 %b + ret i32 %selv +} Index: test/Transforms/InstCombine/pr17827.ll =================================================================== --- test/Transforms/InstCombine/pr17827.ll +++ test/Transforms/InstCombine/pr17827.ll @@ -66,8 +66,8 @@ ; Unsigned compare allows a transformation to compare against 0. define i1 @test_shift_and_cmp_changed2(i8 %p) { ; CHECK-LABEL: @test_shift_and_cmp_changed2( -; CHECK-NEXT: [[ANDP:%.*]] = and i8 %p, 6 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[ANDP]], 0 +; CHECK-NEXT: [[SHLP:%.*]] = shl i8 %p, 5 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[SHLP]], 64 ; CHECK-NEXT: ret i1 [[CMP]] ; %shlp = shl i8 %p, 5 @@ -78,8 +78,8 @@ define <2 x i1> @test_shift_and_cmp_changed2_vec(<2 x i8> %p) { ; CHECK-LABEL: @test_shift_and_cmp_changed2_vec( -; CHECK-NEXT: [[ANDP:%.*]] = and <2 x i8> %p, -; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[ANDP]], zeroinitializer +; CHECK-NEXT: [[SHLP:%.*]] = shl <2 x i8> %p, +; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[SHLP]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %shlp = shl <2 x i8> %p,