Index: include/llvm/Analysis/ValueTracking.h =================================================================== --- include/llvm/Analysis/ValueTracking.h +++ include/llvm/Analysis/ValueTracking.h @@ -517,6 +517,9 @@ /// Pattern match integer [SU]MIN, [SU]MAX and ABS idioms, returning the kind /// and providing the out parameter results if we successfully match. /// + /// For ABS/NABS, LHS will be set to the input to the abs idiom. RHS will be + /// the negation instruction from the idiom. + /// /// If CastOp is not nullptr, also match MIN/MAX idioms where the type does /// not match that of the original select. If this is the case, the cast /// operation (one of Trunc,SExt,Zext) that must be done to transform the Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -4574,6 +4574,8 @@ if (match(CmpRHS, m_APInt(C1))) { if ((CmpLHS == TrueVal && match(FalseVal, m_Neg(m_Specific(CmpLHS)))) || (CmpLHS == FalseVal && match(TrueVal, m_Neg(m_Specific(CmpLHS))))) { + // Set RHS to the negate operand. LHS was assigned to CmpLHS earlier. + RHS = (CmpLHS == TrueVal) ? FalseVal : TrueVal; // ABS(X) ==> (X >s 0) ? X : -X and (X >s -1) ? X : -X // NABS(X) ==> (X >s 0) ? -X : X and (X >s -1) ? -X : X Index: lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- lib/Transforms/Scalar/EarlyCSE.cpp +++ lib/Transforms/Scalar/EarlyCSE.cpp @@ -155,12 +155,15 @@ SelectPatternFlavor SPF = matchSelectPattern(Inst, A, B).Flavor; // TODO: We should also detect FP min/max. if (SPF == SPF_SMIN || SPF == SPF_SMAX || - SPF == SPF_UMIN || SPF == SPF_UMAX || - SPF == SPF_ABS || SPF == SPF_NABS) { + SPF == SPF_UMIN || SPF == SPF_UMAX) { if (A > B) std::swap(A, B); return hash_combine(Inst->getOpcode(), SPF, A, B); } + if (SPF == SPF_ABS || SPF == SPF_NABS) { + // ABS/NABS always puts the input in A and its negation in B. + return hash_combine(Inst->getOpcode(), SPF, A, B); + } if (CastInst *CI = dyn_cast(Inst)) return hash_combine(CI->getOpcode(), CI->getType(), CI->getOperand(0)); @@ -230,8 +233,13 @@ LSPF == SPF_ABS || LSPF == SPF_NABS) { Value *RHSA, *RHSB; SelectPatternFlavor RSPF = matchSelectPattern(RHSI, RHSA, RHSB).Flavor; - return (LSPF == RSPF && ((LHSA == RHSA && LHSB == RHSB) || - (LHSA == RHSB && LHSB == RHSA))); + if (LSPF == RSPF) { + // Abs results are placed in a defined order by matchSelectPattern. + if (LSPF == SPF_ABS || LSPF == SPF_NABS) + return LHSA == RHSA && LHSB == RHSB; + return ((LHSA == RHSA && LHSB == RHSB) || + (LHSA == RHSB && LHSB == RHSA)); + } } return false; Index: test/Transforms/EarlyCSE/commute.ll =================================================================== --- test/Transforms/EarlyCSE/commute.ll +++ test/Transforms/EarlyCSE/commute.ll @@ -252,3 +252,39 @@ ret i8 %r } +; These two tests make sure we still consider it a match when the RHS of the +; compares are different. +define i8 @abs_different_constants(i8 %a) { +; CHECK-LABEL: @abs_different_constants( +; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, %a +; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, -1 +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, 0 +; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 [[NEG]] +; CHECK-NEXT: ret i8 [[M1]] +; + %neg = sub i8 0, %a + %cmp1 = icmp sgt i8 %a, -1 + %cmp2 = icmp slt i8 %a, 0 + %m1 = select i1 %cmp1, i8 %a, i8 %neg + %m2 = select i1 %cmp2, i8 %neg, i8 %a + %r = or i8 %m2, %m1 + ret i8 %r +} + +define i8 @nabs_different_constants(i8 %a) { +; CHECK-LABEL: @nabs_different_constants( +; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, %a +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, 0 +; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, -1 +; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 [[NEG]] +; CHECK-NEXT: ret i8 0 +; + %neg = sub i8 0, %a + %cmp1 = icmp slt i8 %a, 0 + %cmp2 = icmp sgt i8 %a, -1 + %m1 = select i1 %cmp1, i8 %a, i8 %neg + %m2 = select i1 %cmp2, i8 %neg, i8 %a + %r = xor i8 %m2, %m1 + ret i8 %r +} +