Details
Diff Detail
Event Timeline
Some explanation for this patch:
1, for TODO in InstCombineSelect.cpp: because matchSelectPattern() can recognize more abs pattern, including abs(-x), then the assert in canonicalizeAbsNabs() will be hit. But we decide to canonicalize pattern abs(-x) in a separated patch, I just keep canonicalizeAbsNabs() recognize the patterns which trunk recognizes. When canonicalization patch is committed, we should solve TODO.
2, Reply the comment in D48754 in file ValueTracking.cpp at line 4671. I think matchselectpattern can only return a SelectPatternResult struct. RHS stores negated operand, LHS stores the other operand. ABS(-X) and NABS(-x) is just for good understanding?
3, testcase abs_abs_x17/abs_nabs_x17/nabs_abs_x17/nabs_nabs_x17 already be folded in trunk is because (%sub = sub nsw i32 0, %x
, %cmp = icmp sgt i32 %sub, -1) can be folded to (%sub = sub nsw i32 0, %x, %cmp = icmp slt i32 %x, 0) by visiticmp(). After this folding, the left IRs is a standard abs pattern(abx(x)), so it can be recognized. But after this patch, abs(-x) is also recognized, so visiticmp() can not fold %cmp = icmp sgt i32 %sub, -1 any more. So we get different result with trunk. But after canonicalize patch, I assume, we should also get abs(x)
llvm/lib/Analysis/ValueTracking.cpp | ||
---|---|---|
4658 | Is this better? if (match(TrueVal, MaybeSExtLHS)) { LHS = TrueVal; RHS = FalseVal; } else { LHS = FalseVal; RHS = TrueVal; } if (CmpUsesNegatedOp) std::swap(LHS, RHS); |
llvm/lib/Analysis/ValueTracking.cpp | ||
---|---|---|
4640–4641 | What happens if the cmp uses a negated and sign-extended op? I'm not sure if this is possible because of other transforms. Do we have test(s) that include that possibility? | |
llvm/test/Transforms/InstCombine/abs_abs.ll | ||
333–336 | Do you know why the scalar version above folded, but the vector version did not? Something is falsely excluding vector types. |
llvm/lib/Analysis/ValueTracking.cpp | ||
---|---|---|
4640–4641 | new patch can recognize: %ext can be any operator's result including sext. So I 2: in this case, it is the same logic with trunk, so I think there should be already test for it. (abs_canonical_5/nabs_canonical_5 in abs-1.ll) 3: for this case: @spatel Sanjay, Do you have any other pattern I have not considered about? But there should be some thing we can do for sign-extended to enlarge abs pattern scope. for example We should recognize (%tmp, %ext) as negation pair in isKnownNegation(). Maybe I will do this after I finish current work for abs. | |
llvm/test/Transforms/InstCombine/abs_abs.ll | ||
333–336 | Yes, it is also confuse me. I will look into it. Maybe there is a bug in trunk. |
llvm/lib/Analysis/ValueTracking.cpp | ||
---|---|---|
4640–4641 | The sext pattern is my only concern with this patch. Also, I think we might be able to simplify the logic a bit more. I'll send an idea. |
I think the logic is correct, but it would be easier to read if we re-organized it like this:
Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp (revision 336964) +++ lib/Analysis/ValueTracking.cpp (working copy) @@ -4627,34 +4627,49 @@ } } - // Sign-extending LHS does not change its sign, so TrueVal/FalseVal can - // match against either LHS or sext(LHS). - auto MaybeSExtLHS = m_CombineOr(m_Specific(CmpLHS), - m_SExt(m_Specific(CmpLHS))); - if ((match(TrueVal, MaybeSExtLHS) && - match(FalseVal, m_Neg(m_Specific(TrueVal)))) || - (match(FalseVal, MaybeSExtLHS) && - match(TrueVal, m_Neg(m_Specific(FalseVal))))) { - // Set LHS and RHS so that RHS is the negated operand of the select - if (match(TrueVal, MaybeSExtLHS)) { + if (isKnownNegation(TrueVal, FalseVal)) { + // Sign-extending LHS does not change its sign, so TrueVal/FalseVal can + // match against either LHS or sext(LHS). + auto MaybeSExtCmpLHS = m_CombineOr(m_Specific(CmpLHS), + m_SExt(m_Specific(CmpLHS))); + auto ZeroOrAllOnes = m_CombineOr(m_ZeroInt(), m_AllOnes()); + auto ZeroOrOne = m_CombineOr(m_ZeroInt(), m_One()); + if (match(TrueVal, MaybeSExtCmpLHS)) { + // Set the return values. If the compare uses the negated value (-X >s 0), + // swap the return values because the negated value is always 'RHS'. LHS = TrueVal; RHS = FalseVal; - } else { + if (match(CmpLHS, m_Neg(m_Specific(FalseVal)))) + std::swap(LHS, RHS); + + // (X >s 0) ? X : -X or (X >s -1) ? X : -X --> ABS(X) + // (-X >s 0) ? -X : X or (-X >s -1) ? -X : X --> ABS(X) + if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, ZeroOrAllOnes)) + return {SPF_ABS, SPNB_NA, false}; + + // (X <s 0) ? X : -X or (X <s 1) ? X : -X --> NABS(X) + // (-X <s 0) ? -X : X or (-X <s 1) ? -X : X --> NABS(X) + if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, ZeroOrOne)) + return {SPF_NABS, SPNB_NA, false}; + } + if (match(FalseVal, MaybeSExtCmpLHS)) { + // Set the return values. If the compare uses the negated value (-X >s 0), + // swap the return values because the negated value is always 'RHS'. LHS = FalseVal; RHS = TrueVal; - } + if (match(CmpLHS, m_Neg(m_Specific(TrueVal)))) + std::swap(LHS, RHS); - // (X >s 0) ? X : -X or (X >s -1) ? X : -X --> ABS(X) - // (X >s 0) ? -X : X or (X >s -1) ? -X : X --> NABS(X) - if (Pred == ICmpInst::ICMP_SGT && - match(CmpRHS, m_CombineOr(m_ZeroInt(), m_AllOnes()))) - return {(LHS == TrueVal) ? SPF_ABS : SPF_NABS, SPNB_NA, false}; + // (X >s 0) ? -X : X or (X >s -1) ? -X : X --> NABS(X) + // (-X >s 0) ? X : -X or (-X >s -1) ? X : -X --> NABS(X) + if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, ZeroOrAllOnes)) + return {SPF_NABS, SPNB_NA, false}; - // (X <s 0) ? -X : X or (X <s 1) ? -X : X --> ABS(X) - // (X <s 0) ? X : -X or (X <s 1) ? X : -X --> NABS(X) - if (Pred == ICmpInst::ICMP_SLT && - match(CmpRHS, m_CombineOr(m_ZeroInt(), m_One()))) - return {(LHS == FalseVal) ? SPF_ABS : SPF_NABS, SPNB_NA, false}; + // (X <s 0) ? -X : X or (X <s 1) ? -X : X --> ABS(X) + // (-X <s 0) ? X : -X or (-X <s 1) ? X : -X --> ABS(X) + if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, ZeroOrOne)) + return {SPF_ABS, SPNB_NA, false}; + } } if (CmpInst::isIntPredicate(Pred))
@spatel Hi Sanjay, thanks for your such detailed comments. I have updated accordingly.
What happens if the cmp uses a negated and sign-extended op? I'm not sure if this is possible because of other transforms. Do we have test(s) that include that possibility?