From f14e62c9a53b20ed6ed3486588c5ac730cf50442 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 21 May 2018 18:42:42 +0000 Subject: [PATCH] [EarlyCSE] Improve EarlyCSE of some absolute value cases. Change matchSelectPattern to return X and -X for ABS/NABS in a well defined order. Adjust EarlyCSE to account for this. Ensure the SPF result is some kind of min/max and not abs/nabs in one place in InstCombine that made me nervous. Prevously we returned the two operands of the compare part of the abs pattern. The RHS is always going to be a 0i, 1 or -1 constant. This isn't a very meaningful thing to return for any one. There's also some freedom in the abs pattern as to what happens when the value is equal to 0. This freedom led to early cse failing to match when different constants were used in otherwise equivalent operations. By returning the input and its negation in a defined order we can ensure an exact match. This also makes sure both patterns use the exact same subtract instruction for the negation. I believe CSE should evebntually make this happen and properly merge the nsw/nuw flags. But I'm not familiar with CSE and what order it does things in so it seemed like it might be good to really enforce that they were the same. Differential Revision: https://reviews.llvm.org/D47037 llvm-svn: 332865 --- llvm/include/llvm/Analysis/ValueTracking.h | 3 ++ llvm/lib/Analysis/ValueTracking.cpp | 2 ++ llvm/lib/Transforms/Scalar/EarlyCSE.cpp | 16 +++++++--- llvm/test/Transforms/EarlyCSE/commute.ll | 36 ++++++++++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 71637ec7028e..e76603599619 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -517,6 +517,9 @@ class Value; /// 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 diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 811c50165298..4442df8cfd5c 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4574,6 +4574,8 @@ static SelectPatternResult matchSelectPattern(CmpInst::Predicate Pred, 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 diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp index d19ceab38890..a65d15567046 100644 --- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp +++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp @@ -155,12 +155,15 @@ unsigned DenseMapInfo::getHashValue(SimpleValue Val) { 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 @@ bool DenseMapInfo::isEqual(SimpleValue LHS, SimpleValue RHS) { 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; diff --git a/llvm/test/Transforms/EarlyCSE/commute.ll b/llvm/test/Transforms/EarlyCSE/commute.ll index f2d317ff9910..b6a33a75b68a 100644 --- a/llvm/test/Transforms/EarlyCSE/commute.ll +++ b/llvm/test/Transforms/EarlyCSE/commute.ll @@ -252,3 +252,39 @@ define i8 @nabs_swapped(i8 %a) { 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 +} +