mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-17 03:24:34 +00:00
[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:
@@ -20,6 +20,46 @@ using namespace PatternMatch;
|
|||||||
|
|
||||||
#define DEBUG_TYPE "instcombine"
|
#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,
|
/// MatchSelectPattern - Pattern match integer [SU]MIN, [SU]MAX, and ABS idioms,
|
||||||
/// returning the kind and providing the out parameter results if we
|
/// returning the kind and providing the out parameter results if we
|
||||||
/// successfully match.
|
/// successfully match.
|
||||||
@@ -840,6 +880,52 @@ Instruction *InstCombiner::FoldSPFofSPF(Instruction *Inner,
|
|||||||
SI->getCondition(), SI->getFalseValue(), SI->getTrueValue());
|
SI->getCondition(), SI->getFalseValue(), SI->getTrueValue());
|
||||||
return ReplaceInstUsesWith(Outer, NewSI);
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -66,3 +66,20 @@ define i32 @compute_min_pessimization(i32 %x, i32 %y) {
|
|||||||
%min = sub i32 -1, %not_min
|
%min = sub i32 -1, %not_min
|
||||||
ret i32 %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
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user