From 5060f5682b011d2a8c708b3c1b16bd4e0c408afb Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 6 Aug 2020 10:45:32 +0300 Subject: [PATCH] [InstCombine] (-NSW x) s> x --> x s< 0 (PR39480) Name: (-x) s> x --> x s< 0 %neg_x = sub nsw i8 0, %x ; %x must not be INT_MIN %r = icmp sgt i8 %neg_x, %x => %r = icmp slt i8 %x, 0 https://rise4fun.com/Alive/ZslD https://bugs.llvm.org/show_bug.cgi?id=39480 --- llvm/include/llvm/IR/PatternMatch.h | 9 ++++++++ .../Transforms/InstCombine/InstCombineCompares.cpp | 24 ++++++++++++++++++++++ llvm/test/Transforms/InstCombine/cmp-x-vs-neg-x.ll | 8 +++----- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h index 4c11bc8..0850835 100644 --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -2048,6 +2048,15 @@ m_Neg(const ValTy &V) { return m_Sub(m_ZeroInt(), V); } +/// Matches a 'Neg' as 'sub nsw 0, V'. +template +inline OverflowingBinaryOp_match, ValTy, + Instruction::Sub, + OverflowingBinaryOperator::NoSignedWrap> +m_NSWNeg(const ValTy &V) { + return m_NSWSub(m_ZeroInt(), V); +} + /// Matches a 'Not' as 'xor V, -1' or 'xor -1, V'. template inline BinaryOp_match, Instruction::Xor, true> diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 7aa3126..0032b65 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3719,6 +3719,27 @@ Value *InstCombinerImpl::foldUnsignedMultiplicationOverflowCheck(ICmpInst &I) { return Res; } +Instruction *foldICmpXNegX(ICmpInst &I) { + CmpInst::Predicate Pred; + Value *X; + if (!match(&I, m_c_ICmp(Pred, m_NSWNeg(m_Value(X)), m_Deferred(X)))) + return nullptr; + + CmpInst::Predicate NewPred; + Constant *NewRHS; + switch (Pred) { + case ICmpInst::ICMP_SGT: + NewPred = ICmpInst::ICMP_SLT; + NewRHS = Constant::getNullValue(X->getType()); + break; + + default: + return nullptr; + } + + return ICmpInst::Create(Instruction::ICmp, NewPred, X, NewRHS, I.getName()); +} + /// Try to fold icmp (binop), X or icmp X, (binop). /// TODO: A large part of this logic is duplicated in InstSimplify's /// simplifyICmpWithBinOp(). We should be able to share that and avoid the code @@ -3734,6 +3755,9 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I, if (!BO0 && !BO1) return nullptr; + if (Instruction *NewICmp = foldICmpXNegX(I)) + return NewICmp; + const CmpInst::Predicate Pred = I.getPredicate(); Value *X; diff --git a/llvm/test/Transforms/InstCombine/cmp-x-vs-neg-x.ll b/llvm/test/Transforms/InstCombine/cmp-x-vs-neg-x.ll index a839ac6..485e329 100644 --- a/llvm/test/Transforms/InstCombine/cmp-x-vs-neg-x.ll +++ b/llvm/test/Transforms/InstCombine/cmp-x-vs-neg-x.ll @@ -6,8 +6,7 @@ declare void @use8(i8) define i1 @t0(i8 %x) { ; CHECK-LABEL: @t0( -; CHECK-NEXT: [[NEG_X:%.*]] = sub nsw i8 0, [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[NEG_X]], [[X]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %neg_x = sub nsw i8 0, %x @@ -18,8 +17,7 @@ define i1 @t0(i8 %x) { define i1 @t0_commutative() { ; CHECK-LABEL: @t0_commutative( ; CHECK-NEXT: [[X:%.*]] = call i8 @gen8() -; CHECK-NEXT: [[NEG_X:%.*]] = sub nsw i8 0, [[X]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], [[NEG_X]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %x = call i8 @gen8() @@ -32,7 +30,7 @@ define i1 @t0_extrause(i8 %x) { ; CHECK-LABEL: @t0_extrause( ; CHECK-NEXT: [[NEG_X:%.*]] = sub nsw i8 0, [[X:%.*]] ; CHECK-NEXT: call void @use8(i8 [[NEG_X]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[NEG_X]], [[X]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %neg_x = sub nsw i8 0, %x -- 2.7.4