From 9884964af18384471ccb0787d901f272bacc3f73 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Fri, 5 Jan 2018 19:01:17 +0000 Subject: [PATCH] [InstCombine] add folds for min(~a, b) --> ~max(a, b) Besides the bug of omitting the inverse transform of max(~a, ~b) --> ~min(a, b), the use checking and operand creation were off. We were potentially creating repeated identical instructions of existing values. This led to infinite looping after I added the extra folds. By using the simpler m_Not matcher and not creating new 'not' ops for a and b, we avoid that problem. It's possible that not using IsFreeToInvert() here is more limiting than the simpler matcher, but there are no tests for anything more exotic. It's also possible that we should relax the use checking further to handle a case like PR35834: https://bugs.llvm.org/show_bug.cgi?id=35834 ...but we can make that a follow-up if it is needed. llvm-svn: 321882 --- .../InstCombine/InstCombineSelect.cpp | 34 +++++++------------ test/Transforms/InstCombine/max-of-nots.ll | 28 +++++++++++++++ 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombineSelect.cpp b/lib/Transforms/InstCombine/InstCombineSelect.cpp index 6f26f7f5cd1..b02865c1290 100644 --- a/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1551,6 +1551,18 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { Value *NewCast = Builder.CreateCast(CastOp, NewSI, SelType); return replaceInstUsesWith(SI, NewCast); } + + // MAX(~a, ~b) -> ~MIN(a, b) + // MIN(~a, ~b) -> ~MAX(a, b) + Value *A, *B; + if (match(LHS, m_Not(m_Value(A))) && LHS->getNumUses() <= 2 && + match(RHS, m_Not(m_Value(B))) && RHS->getNumUses() <= 2) { + CmpInst::Predicate InvertedPred = + getCmpPredicateForMinMax(getInverseMinMaxSelectPattern(SPF)); + Value *InvertedCmp = Builder.CreateICmp(InvertedPred, A, B); + Value *NewSel = Builder.CreateSelect(InvertedCmp, A, B); + return BinaryOperator::CreateNot(NewSel); + } } if (SPF) { @@ -1570,28 +1582,6 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { return R; } - // MAX(~a, ~b) -> ~MIN(a, b) - if ((SPF == SPF_SMAX || SPF == SPF_UMAX) && - IsFreeToInvert(LHS, LHS->hasNUses(2)) && - IsFreeToInvert(RHS, RHS->hasNUses(2))) { - // For this transform to be profitable, we need to eliminate at least two - // 'not' instructions if we're going to add one 'not' instruction. - int NumberOfNots = - (LHS->hasNUses(2) && match(LHS, m_Not(m_Value()))) + - (RHS->hasNUses(2) && match(RHS, m_Not(m_Value()))) + - (SI.hasOneUse() && match(*SI.user_begin(), m_Not(m_Value()))); - - if (NumberOfNots >= 2) { - Value *NewLHS = Builder.CreateNot(LHS); - Value *NewRHS = Builder.CreateNot(RHS); - Value *NewCmp = SPF == SPF_SMAX ? Builder.CreateICmpSLT(NewLHS, NewRHS) - : Builder.CreateICmpULT(NewLHS, NewRHS); - Value *NewSI = - Builder.CreateNot(Builder.CreateSelect(NewCmp, NewLHS, NewRHS)); - return replaceInstUsesWith(SI, NewSI); - } - } - // TODO. // ABS(-X) -> ABS(X) } diff --git a/test/Transforms/InstCombine/max-of-nots.ll b/test/Transforms/InstCombine/max-of-nots.ll index 0302c9ec6d7..8f9ef9409d5 100644 --- a/test/Transforms/InstCombine/max-of-nots.ll +++ b/test/Transforms/InstCombine/max-of-nots.ll @@ -1,6 +1,34 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -instcombine < %s | FileCheck %s +define <2 x i32> @umin_of_nots(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @umin_of_nots( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt <2 x i32> %x, %y +; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> %x, <2 x i32> %y +; CHECK-NEXT: [[MIN:%.*]] = xor <2 x i32> [[TMP2]], +; CHECK-NEXT: ret <2 x i32> [[MIN]] +; + %notx = xor <2 x i32> %x, + %noty = xor <2 x i32> %y, + %cmp = icmp ult <2 x i32> %notx, %noty + %min = select <2 x i1> %cmp, <2 x i32> %notx, <2 x i32> %noty + ret <2 x i32> %min +} + +define <2 x i32> @smin_of_nots(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @smin_of_nots( +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt <2 x i32> %x, %y +; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> %x, <2 x i32> %y +; CHECK-NEXT: [[MIN:%.*]] = xor <2 x i32> [[TMP2]], +; CHECK-NEXT: ret <2 x i32> [[MIN]] +; + %notx = xor <2 x i32> %x, + %noty = xor <2 x i32> %y, + %cmp = icmp sle <2 x i32> %notx, %noty + %min = select <2 x i1> %cmp, <2 x i32> %notx, <2 x i32> %noty + ret <2 x i32> %min +} + define i32 @compute_min_2(i32 %x, i32 %y) { ; CHECK-LABEL: @compute_min_2( ; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 %x, %y