diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 1480a0ff9e2f8b..8e90014d24d86b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4661,20 +4661,34 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) { if (match(Op0, m_And(m_Value(B), m_LowBitMask(MaskC))) && MaskC->countTrailingOnes() == A->getType()->getScalarSizeInBits()) return new ICmpInst(Pred, A, Builder.CreateTrunc(B, A->getType())); + } - // Test if 2 values have different or same signbits: - // (X u>> BitWidth - 1) == zext (Y s> -1) --> (X ^ Y) < 0 - // (X u>> BitWidth - 1) != zext (Y s> -1) --> (X ^ Y) > -1 + // Test if 2 values have different or same signbits: + // (X u>> BitWidth - 1) == zext (Y s> -1) --> (X ^ Y) < 0 + // (X u>> BitWidth - 1) != zext (Y s> -1) --> (X ^ Y) > -1 + // (X s>> BitWidth - 1) == sext (Y s> -1) --> (X ^ Y) < 0 + // (X s>> BitWidth - 1) != sext (Y s> -1) --> (X ^ Y) > -1 + Instruction *ExtI; + if (match(Op1, m_CombineAnd(m_Instruction(ExtI), m_ZExtOrSExt(m_Value(A)))) && + (Op0->hasOneUse() || Op1->hasOneUse())) { unsigned OpWidth = Op0->getType()->getScalarSizeInBits(); + Instruction *ShiftI; Value *X, *Y; ICmpInst::Predicate Pred2; - if (match(Op0, m_LShr(m_Value(X), m_SpecificIntAllowUndef(OpWidth - 1))) && + if (match(Op0, m_CombineAnd(m_Instruction(ShiftI), + m_Shr(m_Value(X), + m_SpecificIntAllowUndef(OpWidth - 1)))) && match(A, m_ICmp(Pred2, m_Value(Y), m_AllOnes())) && Pred2 == ICmpInst::ICMP_SGT && X->getType() == Y->getType()) { - Value *Xor = Builder.CreateXor(X, Y, "xor.signbits"); - Value *R = (Pred == ICmpInst::ICMP_EQ) ? Builder.CreateIsNeg(Xor) : - Builder.CreateIsNotNeg(Xor); - return replaceInstUsesWith(I, R); + unsigned ExtOpc = ExtI->getOpcode(); + unsigned ShiftOpc = ShiftI->getOpcode(); + if ((ExtOpc == Instruction::ZExt && ShiftOpc == Instruction::LShr) || + (ExtOpc == Instruction::SExt && ShiftOpc == Instruction::AShr)) { + Value *Xor = Builder.CreateXor(X, Y, "xor.signbits"); + Value *R = (Pred == ICmpInst::ICMP_EQ) ? Builder.CreateIsNeg(Xor) + : Builder.CreateIsNotNeg(Xor); + return replaceInstUsesWith(I, R); + } } } diff --git a/llvm/test/Transforms/InstCombine/icmp-shr.ll b/llvm/test/Transforms/InstCombine/icmp-shr.ll index 0259e601fafa88..f4dfa2edfa1771 100644 --- a/llvm/test/Transforms/InstCombine/icmp-shr.ll +++ b/llvm/test/Transforms/InstCombine/icmp-shr.ll @@ -1465,10 +1465,8 @@ define i1 @exactly_one_set_signbit_wrong_pred(i8 %x, i8 %y) { define i1 @exactly_one_set_signbit_signed(i8 %x, i8 %y) { ; CHECK-LABEL: @exactly_one_set_signbit_signed( -; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7 -; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1 -; CHECK-NEXT: [[YPOSZ:%.*]] = sext i1 [[YPOS]] to i8 -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[XSIGN]], [[YPOSZ]] +; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[XOR_SIGNBITS]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %xsign = ashr i8 %x, 7 @@ -1482,9 +1480,8 @@ define i1 @exactly_one_set_signbit_use1_signed(i8 %x, i8 %y) { ; CHECK-LABEL: @exactly_one_set_signbit_use1_signed( ; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7 ; CHECK-NEXT: call void @use(i8 [[XSIGN]]) -; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1 -; CHECK-NEXT: [[YPOSZ:%.*]] = sext i1 [[YPOS]] to i8 -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[XSIGN]], [[YPOSZ]] +; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor i8 [[X]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[XOR_SIGNBITS]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %xsign = ashr i8 %x, 7 @@ -1497,10 +1494,8 @@ define i1 @exactly_one_set_signbit_use1_signed(i8 %x, i8 %y) { define <2 x i1> @same_signbit_signed(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @same_signbit_signed( -; CHECK-NEXT: [[XSIGN:%.*]] = ashr <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt <2 x i8> [[Y:%.*]], -; CHECK-NEXT: [[YPOSZ:%.*]] = sext <2 x i1> [[YPOS]] to <2 x i8> -; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[XSIGN]], [[YPOSZ]] +; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt <2 x i8> [[XOR_SIGNBITS]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %xsign = ashr <2 x i8> %x, @@ -1512,11 +1507,11 @@ define <2 x i1> @same_signbit_signed(<2 x i8> %x, <2 x i8> %y) { define i1 @same_signbit_use2_signed(i8 %x, i8 %y) { ; CHECK-LABEL: @same_signbit_use2_signed( -; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7 ; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1 ; CHECK-NEXT: [[YPOSZ:%.*]] = sext i1 [[YPOS]] to i8 ; CHECK-NEXT: call void @use(i8 [[YPOSZ]]) -; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[XSIGN]], [[YPOSZ]] +; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor i8 [[X:%.*]], [[Y]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[XOR_SIGNBITS]], -1 ; CHECK-NEXT: ret i1 [[R]] ; %xsign = ashr i8 %x, 7 @@ -1527,6 +1522,8 @@ define i1 @same_signbit_use2_signed(i8 %x, i8 %y) { ret i1 %r } +; negative test + define i1 @same_signbit_use3_signed(i8 %x, i8 %y) { ; CHECK-LABEL: @same_signbit_use3_signed( ; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7 @@ -1548,10 +1545,8 @@ define i1 @same_signbit_use3_signed(i8 %x, i8 %y) { define <2 x i1> @same_signbit_poison_elts_signed(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @same_signbit_poison_elts_signed( -; CHECK-NEXT: [[XSIGN:%.*]] = ashr <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt <2 x i8> [[Y:%.*]], -; CHECK-NEXT: [[YPOSZ:%.*]] = sext <2 x i1> [[YPOS]] to <2 x i8> -; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[XSIGN]], [[YPOSZ]] +; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt <2 x i8> [[XOR_SIGNBITS]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %xsign = ashr <2 x i8> %x, @@ -1561,6 +1556,8 @@ define <2 x i1> @same_signbit_poison_elts_signed(<2 x i8> %x, <2 x i8> %y) { ret <2 x i1> %r } +; negative test + define i1 @same_signbit_wrong_type_signed(i8 %x, i32 %y) { ; CHECK-LABEL: @same_signbit_wrong_type_signed( ; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7 @@ -1576,6 +1573,8 @@ define i1 @same_signbit_wrong_type_signed(i8 %x, i32 %y) { ret i1 %r } +; negative test + define i1 @exactly_one_set_signbit_wrong_shamt_signed(i8 %x, i8 %y) { ; CHECK-LABEL: @exactly_one_set_signbit_wrong_shamt_signed( ; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 6