Index: llvm/include/llvm/Analysis/ValueTracking.h =================================================================== --- llvm/include/llvm/Analysis/ValueTracking.h +++ llvm/include/llvm/Analysis/ValueTracking.h @@ -101,6 +101,9 @@ const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); + /// Return true if the two given values are complement + bool isKnownComplement(const Value *LHS, const Value *RHS); + /// Returns true if the give value is known to be non-negative. bool isKnownNonNegative(const Value *V, const DataLayout &DL, unsigned Depth = 0, Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4503,6 +4503,25 @@ return {SPF_UNKNOWN, SPNB_NA, false}; } +/// Return true if LHS and RHS are complement, otherwise return false +bool llvm::isKnownComplement(const Value *LHS, const Value *RHS) { + if (!LHS || !RHS) + return false; + + // Y = sub (0, X) + if (match(LHS, m_Neg(m_Specific(RHS))) || match(RHS, m_Neg(m_Specific(LHS)))) + return true; + + // X = sub (a, b), Y = sub (b, a) + Value *X = nullptr, *Y = nullptr; + if (match(LHS, m_Sub(m_Value(X), m_Value(Y))) && + match(RHS, m_Sub(m_Specific(Y), m_Specific(X)))) + return true; + + //TODO: add more pattern here + return false; +} + static SelectPatternResult matchSelectPattern(CmpInst::Predicate Pred, FastMathFlags FMF, Value *CmpLHS, Value *CmpRHS, @@ -4608,10 +4627,8 @@ // 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))))) { + if ((match(TrueVal, MaybeSExtLHS) || match(FalseVal, MaybeSExtLHS)) && + isKnownComplement(TrueVal, FalseVal)) { // Set LHS and RHS so that RHS is the negated operand of the select if (match(TrueVal, MaybeSExtLHS)) { LHS = TrueVal; Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -823,16 +823,15 @@ // If the select operands do not change, we're done. Value *TVal = Sel.getTrueValue(); Value *FVal = Sel.getFalseValue(); + assert(isKnownComplement(TVal, FVal) && "Unexpected result from matchSelectPattern"); if (SPF == SelectPatternFlavor::SPF_NABS) { - if (TVal == LHS && match(FVal, m_Neg(m_Specific(TVal)))) + if (TVal == LHS) return &Sel; - assert(FVal == LHS && match(TVal, m_Neg(m_Specific(FVal))) && - "Unexpected results from matchSelectPattern"); + assert(FVal == LHS && "Unexpected results from matchSelectPattern"); } else { - if (FVal == LHS && match(TVal, m_Neg(m_Specific(FVal)))) + if (FVal == LHS) return &Sel; - assert(TVal == LHS && match(FVal, m_Neg(m_Specific(TVal))) && - "Unexpected results from matchSelectPattern"); + assert(TVal == LHS && "Unexpected results from matchSelectPattern"); } // We are swapping the select operands, so swap the metadata too. Index: llvm/test/Transforms/InstCombine/abs-1.ll =================================================================== --- llvm/test/Transforms/InstCombine/abs-1.ll +++ llvm/test/Transforms/InstCombine/abs-1.ll @@ -116,6 +116,37 @@ ret i32 %abs } +define i32 @abs_canonical_6(i32 %a, i32 %b) { +; CHECK-LABEL: @abs_canonical_6( +; CHECK-NEXT: [[TMP:%.*]] = sub i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP]], 0 +; CHECK-NEXT: [[NEG:%.*]] = sub i32 [[B]], [[A]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEG]], i32 [[TMP]] +; CHECK-NEXT: ret i32 [[ABS]] +; + %tmp1 = sub i32 %a, %b + %cmp = icmp sgt i32 %tmp1, -1 + %tmp2 = sub i32 %b, %a + %abs = select i1 %cmp, i32 %tmp1, i32 %tmp2 + ret i32 %abs +} + +define <2 x i8> @abs_canonical_7(<2 x i8> %a, <2 x i8 > %b) { +; CHECK-LABEL: @abs_canonical_7( +; CHECK-NEXT: [[TMP:%.*]] = sub <2 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[TMP]], zeroinitializer +; CHECK-NEXT: [[NEG:%.*]] = sub <2 x i8> [[B]], [[A]] +; CHECK-NEXT: [[ABS:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[NEG]], <2 x i8> [[TMP]] +; CHECK-NEXT: ret <2 x i8> [[ABS]] +; + %tmp = sub <2 x i8> %a, %b + %cmp = icmp sgt <2 x i8> %tmp, + %neg = sub <2 x i8> %b, %a + %abs = select <2 x i1> %cmp, <2 x i8> %tmp, <2 x i8> %neg + ret <2 x i8> %abs +} + + ; We have a canonical form of nabs to make CSE easier. define i8 @nabs_canonical_1(i8 %x) { @@ -189,6 +220,36 @@ ret i32 %abs } +define i32 @nabs_canonical_6(i32 %a, i32 %b) { +; CHECK-LABEL: @nabs_canonical_6( +; CHECK-NEXT: [[TMP:%.*]] = sub i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP]], 0 +; CHECK-NEXT: [[NEG:%.*]] = sub i32 [[B]], [[A]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[TMP]], i32 [[NEG]] +; CHECK-NEXT: ret i32 [[ABS]] +; + %tmp1 = sub i32 %a, %b + %cmp = icmp sgt i32 %tmp1, -1 + %tmp2 = sub i32 %b, %a + %abs = select i1 %cmp, i32 %tmp2, i32 %tmp1 + ret i32 %abs +} + +define <2 x i8> @nabs_canonical_7(<2 x i8> %a, <2 x i8 > %b) { +; CHECK-LABEL: @nabs_canonical_7( +; CHECK-NEXT: [[TMP:%.*]] = sub <2 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[TMP]], zeroinitializer +; CHECK-NEXT: [[NEG:%.*]] = sub <2 x i8> [[B]], [[A]] +; CHECK-NEXT: [[ABS:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[TMP]], <2 x i8> [[NEG]] +; CHECK-NEXT: ret <2 x i8> [[ABS]] +; + %tmp = sub <2 x i8> %a, %b + %cmp = icmp sgt <2 x i8> %tmp, + %neg = sub <2 x i8> %b, %a + %abs = select <2 x i1> %cmp, <2 x i8> %neg, <2 x i8> %tmp + ret <2 x i8> %abs +} + ; The following 5 tests use a shift+add+xor to implement abs(): ; B = ashr i8 A, 7 -- smear the sign bit. ; xor (add A, B), B -- add -1 and flip bits if negative