[InstCombine] Add new rule for MIN(MAX(~A, ~B), ~C) et. al.

Summary:
Optimizing these well are especially interesting for IRCE since it
"clamps" values by generating this sort of pattern through SCEV
expressions.

Depends on D9352.

Reviewers: majnemer

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D9353

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236203 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sanjoy Das 2015-04-30 04:56:04 +00:00
parent c0730628a4
commit a34038226e
2 changed files with 103 additions and 0 deletions

View File

@ -20,6 +20,46 @@ using namespace PatternMatch;
#define DEBUG_TYPE "instcombine"
static SelectPatternFlavor
getInverseMinMaxSelectPattern(SelectPatternFlavor SPF) {
switch (SPF) {
default:
llvm_unreachable("unhandled!");
case SPF_SMIN:
return SPF_SMAX;
case SPF_UMIN:
return SPF_UMAX;
case SPF_SMAX:
return SPF_SMIN;
case SPF_UMAX:
return SPF_UMIN;
}
}
static CmpInst::Predicate getICmpPredicateForMinMax(SelectPatternFlavor SPF) {
switch (SPF) {
default:
llvm_unreachable("unhandled!");
case SPF_SMIN:
return ICmpInst::ICMP_SLT;
case SPF_UMIN:
return ICmpInst::ICMP_ULT;
case SPF_SMAX:
return ICmpInst::ICMP_SGT;
case SPF_UMAX:
return ICmpInst::ICMP_UGT;
}
}
static Value *generateMinMaxSelectPattern(InstCombiner::BuilderTy *Builder,
SelectPatternFlavor SPF, Value *A,
Value *B) {
CmpInst::Predicate Pred = getICmpPredicateForMinMax(SPF);
return Builder->CreateSelect(Builder->CreateICmp(Pred, A, B), A, B);
}
/// MatchSelectPattern - Pattern match integer [SU]MIN, [SU]MAX, and ABS idioms,
/// returning the kind and providing the out parameter results if we
/// successfully match.
@ -840,6 +880,52 @@ Instruction *InstCombiner::FoldSPFofSPF(Instruction *Inner,
SI->getCondition(), SI->getFalseValue(), SI->getTrueValue());
return ReplaceInstUsesWith(Outer, NewSI);
}
auto IsFreeOrProfitableToInvert =
[&](Value *V, Value *&NotV, bool &ElidesXor) {
if (match(V, m_Not(m_Value(NotV)))) {
// If V has at most 2 uses then we can get rid of the xor operation
// entirely.
ElidesXor |= !V->hasNUsesOrMore(3);
return true;
}
if (IsFreeToInvert(V, !V->hasNUsesOrMore(3))) {
NotV = nullptr;
return true;
}
return false;
};
Value *NotA, *NotB, *NotC;
bool ElidesXor = false;
// MIN(MIN(~A, ~B), ~C) == ~MAX(MAX(A, B), C)
// MIN(MAX(~A, ~B), ~C) == ~MAX(MIN(A, B), C)
// MAX(MIN(~A, ~B), ~C) == ~MIN(MAX(A, B), C)
// MAX(MAX(~A, ~B), ~C) == ~MIN(MIN(A, B), C)
//
// This transform is performance neutral if we can elide at least one xor from
// the set of three operands, since we'll be tacking on an xor at the very
// end.
if (IsFreeOrProfitableToInvert(A, NotA, ElidesXor) &&
IsFreeOrProfitableToInvert(B, NotB, ElidesXor) &&
IsFreeOrProfitableToInvert(C, NotC, ElidesXor) && ElidesXor) {
if (!NotA)
NotA = Builder->CreateNot(A);
if (!NotB)
NotB = Builder->CreateNot(B);
if (!NotC)
NotC = Builder->CreateNot(C);
Value *NewInner = generateMinMaxSelectPattern(
Builder, getInverseMinMaxSelectPattern(SPF1), NotA, NotB);
Value *NewOuter = Builder->CreateNot(generateMinMaxSelectPattern(
Builder, getInverseMinMaxSelectPattern(SPF2), NewInner, NotC));
return ReplaceInstUsesWith(Outer, NewOuter);
}
return nullptr;
}

View File

@ -66,3 +66,20 @@ define i32 @compute_min_pessimization(i32 %x, i32 %y) {
%min = sub i32 -1, %not_min
ret i32 %min
}
define i32 @max_of_nots(i32 %x, i32 %y) {
; CHECK-LABEL: @max_of_nots(
; CHECK-NEXT: icmp
; CHECK-NEXT: select
; CHECK-NEXT: icmp
; CHECK-NEXT: select
; CHECK-NEXT: xor
; CHECK-NEXT: ret
%c0 = icmp sgt i32 %y, 0
%xor_y = xor i32 %y, -1
%s0 = select i1 %c0, i32 %xor_y, i32 -1
%xor_x = xor i32 %x, -1
%c1 = icmp slt i32 %s0, %xor_x
%smax96 = select i1 %c1, i32 %xor_x, i32 %s0
ret i32 %smax96
}