diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2630,6 +2630,29 @@ } } + // match naive pattern for checking if two values share same sign, + // an example of the pattern: + // (icmp slt (X & Y), 0) | (icmp sgt (X | Y), -1) -> (icmp sgt (X ^ Y), -1) + // first, check if icmp on both sides are sign-bit-checks + bool TrueIfSignedL, TrueIfSignedR; + if (!IsAnd && InstCombiner::isSignBitCheck(PredL, *LHSC, TrueIfSignedL) && + InstCombiner::isSignBitCheck(PredR, *RHSC, TrueIfSignedR)) { + Value *LHSX, *LHSY, *RHSX, *RHSY; + if (((TrueIfSignedL && !TrueIfSignedR && + match(LHS0, m_And(m_Value(LHSX), m_Value(LHSY))) && + match(RHS0, m_Or(m_Value(RHSX), m_Value(RHSY)))) || + (!TrueIfSignedL && TrueIfSignedR && + match(RHS0, m_And(m_Value(RHSX), m_Value(RHSY))) && + match(LHS0, m_Or(m_Value(LHSX), m_Value(LHSY))))) && + ((LHSX == RHSX && LHSY == RHSY) || (LHSX == RHSY && LHSY == RHSX))) { + // build return inst + Value *NewXor = Builder.CreateXor(LHSX, LHSY); + APInt W = APInt(32, -1, true); + Value *NewC = ConstantInt::get(NewXor->getType(), W); + return Builder.CreateICmp(ICmpInst::ICMP_SGT, NewXor, NewC); + } + } + return foldAndOrOfICmpsUsingRanges(LHS, RHS, IsAnd); } diff --git a/llvm/test/Transforms/InstCombine/same-sign-naive.ll b/llvm/test/Transforms/InstCombine/same-sign-naive.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/same-sign-naive.ll @@ -0,0 +1,14 @@ +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +define i1 @samesign(i32 %x, i32 %y) { +; CHECK-LABEL: @samesign( +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[x:%.*]], [[y:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1 +; CHECK-NEXT: ret i1 [[TMP2]] + %a = and i32 %x, %y + %lt = icmp slt i32 %a, 0 + %o = or i32 %x, %y + %gt = icmp sgt i32 %o, -1 + %r = or i1 %lt, %gt + ret i1 %r +}