Index: llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4074,20 +4074,36 @@ return Res; } -static Instruction *foldICmpXNegX(ICmpInst &I) { +static Instruction *foldICmpXNegX(ICmpInst &I, + InstCombiner::BuilderTy &Builder) { CmpInst::Predicate Pred; Value *X; - if (!match(&I, m_c_ICmp(Pred, m_NSWNeg(m_Value(X)), m_Deferred(X)))) - return nullptr; + if (match(&I, m_c_ICmp(Pred, m_NSWNeg(m_Value(X)), m_Deferred(X)))) { - if (ICmpInst::isSigned(Pred)) - Pred = ICmpInst::getSwappedPredicate(Pred); - else if (ICmpInst::isUnsigned(Pred)) - Pred = ICmpInst::getSignedPredicate(Pred); - // else for equality-comparisons just keep the predicate. + if (ICmpInst::isSigned(Pred)) + Pred = ICmpInst::getSwappedPredicate(Pred); + else if (ICmpInst::isUnsigned(Pred)) + Pred = ICmpInst::getSignedPredicate(Pred); + // else for equality-comparisons just keep the predicate. - return ICmpInst::Create(Instruction::ICmp, Pred, X, - Constant::getNullValue(X->getType()), I.getName()); + return ICmpInst::Create(Instruction::ICmp, Pred, X, + Constant::getNullValue(X->getType()), I.getName()); + } + + // A value is not equal to its negation unless that value is 0 or + // MinSignedValue, ie: a != -a --> (a & MaxSignedVal) != 0 + if (match(&I, m_c_ICmp(Pred, m_Neg(m_Value(X)), m_Deferred(X))) && + (Pred == ICmpInst::ICMP_NE || Pred == ICmpInst::ICMP_EQ)) { + Type *Ty = X->getType(); + uint32_t BitWidth = cast(Ty)->getBitWidth(); + Constant *MaxSignedVal = + ConstantInt::get(Ty, APInt::getSignedMaxValue(BitWidth)); + Value *And = Builder.CreateAnd(X, MaxSignedVal); + Constant *Zero = Constant::getNullValue(Ty); + return CmpInst::Create(Instruction::ICmp, I.getPredicate(), And, Zero); + } + + return nullptr; } /// Try to fold icmp (binop), X or icmp X, (binop). @@ -4105,7 +4121,7 @@ if (!BO0 && !BO1) return nullptr; - if (Instruction *NewICmp = foldICmpXNegX(I)) + if (Instruction *NewICmp = foldICmpXNegX(I, Builder)) return NewICmp; const CmpInst::Predicate Pred = I.getPredicate(); Index: llvm/test/Transforms/InstCombine/icmp-sub.ll =================================================================== --- llvm/test/Transforms/InstCombine/icmp-sub.ll +++ llvm/test/Transforms/InstCombine/icmp-sub.ll @@ -561,3 +561,30 @@ bb_exit: ret void } + +; https://alive2.llvm.org/ce/z/D2Aph4 +define i1 @PR60818_ne(i32 %a) { +; CHECK-LABEL: @PR60818_ne( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = and i32 [[A:%.*]], 2147483647 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP0]], 0 +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %sub = sub i32 0, %a + %cmp = icmp ne i32 %sub, %a + ret i1 %cmp +} + +define i1 @PR60818_eq(i32 %a) { +; CHECK-LABEL: @PR60818_eq( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = and i32 [[A:%.*]], 2147483647 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0 +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %sub = sub i32 0, %a + %cmp = icmp eq i32 %sub, %a + ret i1 %cmp +}