Implement some basic simplifications involving min/max, for example

max(a,b) >= a -> true.  According to my super-optimizer, these are
by far the most common simplifications (of the -instsimplify kind)
that occur in the testsuite and aren't caught by -std-compile-opts.

llvm-svn: 130780
This commit is contained in:
Duncan Sands 2011-05-03 19:53:10 +00:00
parent e6ce2053e7
commit 0a9c1246d7
3 changed files with 356 additions and 0 deletions

View File

@ -694,6 +694,99 @@ inline brc_match<Cond_t> m_Br(const Cond_t &C, BasicBlock *&T, BasicBlock *&F) {
return brc_match<Cond_t>(C, T, F);
}
//===----------------------------------------------------------------------===//
// Matchers for max/min idioms, eg: "select (sgt x, y), x, y" -> smax(x,y).
//
template<typename LHS_t, typename RHS_t, typename Pred_t>
struct MaxMin_match {
LHS_t L;
RHS_t R;
MaxMin_match(const LHS_t &LHS, const RHS_t &RHS)
: L(LHS), R(RHS) {}
template<typename OpTy>
bool match(OpTy *V) {
// Look for "(x pred y) ? x : y" or "(x pred y) ? y : x".
SelectInst *SI = dyn_cast<SelectInst>(V);
if (!SI)
return false;
ICmpInst *Cmp = dyn_cast<ICmpInst>(SI->getCondition());
if (!Cmp)
return false;
// At this point we have a select conditioned on a comparison. Check that
// it is the values returned by the select that are being compared.
Value *TrueVal = SI->getTrueValue();
Value *FalseVal = SI->getFalseValue();
Value *LHS = Cmp->getOperand(0);
Value *RHS = Cmp->getOperand(1);
if ((TrueVal != LHS || FalseVal != RHS) &&
(TrueVal != RHS || FalseVal != LHS))
return false;
ICmpInst::Predicate Pred = LHS == TrueVal ?
Cmp->getPredicate() : Cmp->getSwappedPredicate();
// Does "(x pred y) ? x : y" represent the desired max/min operation?
if (!Pred_t::match(Pred))
return false;
// It does! Bind the operands.
return L.match(LHS) && R.match(RHS);
}
};
/// smax_pred_ty - Helper class for identifying signed max predicates.
struct smax_pred_ty {
static bool match(ICmpInst::Predicate Pred) {
return Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SGE;
}
};
/// smin_pred_ty - Helper class for identifying signed min predicates.
struct smin_pred_ty {
static bool match(ICmpInst::Predicate Pred) {
return Pred == CmpInst::ICMP_SLT || Pred == CmpInst::ICMP_SLE;
}
};
/// umax_pred_ty - Helper class for identifying unsigned max predicates.
struct umax_pred_ty {
static bool match(ICmpInst::Predicate Pred) {
return Pred == CmpInst::ICMP_UGT || Pred == CmpInst::ICMP_UGE;
}
};
/// umin_pred_ty - Helper class for identifying unsigned min predicates.
struct umin_pred_ty {
static bool match(ICmpInst::Predicate Pred) {
return Pred == CmpInst::ICMP_ULT || Pred == CmpInst::ICMP_ULE;
}
};
template<typename LHS, typename RHS>
inline MaxMin_match<LHS, RHS, smax_pred_ty>
m_SMax(const LHS &L, const RHS &R) {
return MaxMin_match<LHS, RHS, smax_pred_ty>(L, R);
}
template<typename LHS, typename RHS>
inline MaxMin_match<LHS, RHS, smin_pred_ty>
m_SMin(const LHS &L, const RHS &R) {
return MaxMin_match<LHS, RHS, smin_pred_ty>(L, R);
}
template<typename LHS, typename RHS>
inline MaxMin_match<LHS, RHS, umax_pred_ty>
m_UMax(const LHS &L, const RHS &R) {
return MaxMin_match<LHS, RHS, umax_pred_ty>(L, R);
}
template<typename LHS, typename RHS>
inline MaxMin_match<LHS, RHS, umin_pred_ty>
m_UMin(const LHS &L, const RHS &R) {
return MaxMin_match<LHS, RHS, umin_pred_ty>(L, R);
}
} // end namespace PatternMatch
} // end namespace llvm

View File

@ -1868,6 +1868,124 @@ static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
}
}
// Simplify comparisons involving max/min.
Value *A, *B;
CmpInst::Predicate P = CmpInst::BAD_ICMP_PREDICATE;
CmpInst::Predicate EqP; // Chosen so that "A == max/min(A,B)" iff "A EqP B".
// Signed max/min.
if (match(LHS, m_SMax(m_Value(A), m_Value(B))) && (A == RHS || B == RHS)) {
if (A != RHS) std::swap(A, B); // smax(A, B) pred A.
EqP = CmpInst::ICMP_SGE; // "A == smax(A, B)" iff "A sge B".
// We analyze this as smax(A, B) pred A.
P = Pred;
} else if (match(RHS, m_SMax(m_Value(A), m_Value(B))) &&
(A == LHS || B == LHS)) {
if (A != LHS) std::swap(A, B); // A pred smax(A, B).
EqP = CmpInst::ICMP_SGE; // "A == smax(A, B)" iff "A sge B".
// We analyze this as smax(A, B) swapped-pred A.
P = CmpInst::getSwappedPredicate(Pred);
} else if (match(LHS, m_SMin(m_Value(A), m_Value(B))) &&
(A == RHS || B == RHS)) {
if (A != RHS) std::swap(A, B); // smin(A, B) pred A.
EqP = CmpInst::ICMP_SLE; // "A == smin(A, B)" iff "A sle B".
// We analyze this as smax(-A, -B) swapped-pred -A.
// Note that we do not need to actually form -A or -B thanks to EqP.
P = CmpInst::getSwappedPredicate(Pred);
} else if (match(RHS, m_SMin(m_Value(A), m_Value(B))) &&
(A == LHS || B == LHS)) {
if (A != LHS) std::swap(A, B); // A pred smin(A, B).
EqP = CmpInst::ICMP_SLE; // "A == smin(A, B)" iff "A sle B".
// We analyze this as smax(-A, -B) pred -A.
// Note that we do not need to actually form -A or -B thanks to EqP.
P = Pred;
}
if (P != CmpInst::BAD_ICMP_PREDICATE) {
// Cases correspond to "max(A, B) p A".
switch (P) {
default:
break;
case CmpInst::ICMP_EQ:
case CmpInst::ICMP_SLE:
// Equivalent to "A EqP B".
if (MaxRecurse)
if (Value *V = SimplifyICmpInst(EqP, A, B, TD, DT, MaxRecurse-1))
return V;
break;
case CmpInst::ICMP_NE:
case CmpInst::ICMP_SGT:
// Equivalent to "A inverse-EqP B".
if (MaxRecurse)
if (Value *V = SimplifyICmpInst(CmpInst::getInversePredicate(EqP), A, B,
TD, DT, MaxRecurse-1))
return V;
break;
case CmpInst::ICMP_SGE:
// Always true.
return Constant::getAllOnesValue(ITy);
case CmpInst::ICMP_SLT:
// Always false.
return Constant::getNullValue(ITy);
}
}
// Unsigned max/min.
P = CmpInst::BAD_ICMP_PREDICATE;
if (match(LHS, m_UMax(m_Value(A), m_Value(B))) && (A == RHS || B == RHS)) {
if (A != RHS) std::swap(A, B); // umax(A, B) pred A.
EqP = CmpInst::ICMP_UGE; // "A == umax(A, B)" iff "A uge B".
// We analyze this as umax(A, B) pred A.
P = Pred;
} else if (match(RHS, m_UMax(m_Value(A), m_Value(B))) &&
(A == LHS || B == LHS)) {
if (A != LHS) std::swap(A, B); // A pred umax(A, B).
EqP = CmpInst::ICMP_UGE; // "A == umax(A, B)" iff "A uge B".
// We analyze this as umax(A, B) swapped-pred A.
P = CmpInst::getSwappedPredicate(Pred);
} else if (match(LHS, m_UMin(m_Value(A), m_Value(B))) &&
(A == RHS || B == RHS)) {
if (A != RHS) std::swap(A, B); // umin(A, B) pred A.
EqP = CmpInst::ICMP_ULE; // "A == umin(A, B)" iff "A ule B".
// We analyze this as umax(-A, -B) swapped-pred -A.
// Note that we do not need to actually form -A or -B thanks to EqP.
P = CmpInst::getSwappedPredicate(Pred);
} else if (match(RHS, m_UMin(m_Value(A), m_Value(B))) &&
(A == LHS || B == LHS)) {
if (A != LHS) std::swap(A, B); // A pred umin(A, B).
EqP = CmpInst::ICMP_ULE; // "A == umin(A, B)" iff "A ule B".
// We analyze this as umax(-A, -B) pred -A.
// Note that we do not need to actually form -A or -B thanks to EqP.
P = Pred;
}
if (P != CmpInst::BAD_ICMP_PREDICATE) {
// Cases correspond to "max(A, B) p A".
switch (P) {
default:
break;
case CmpInst::ICMP_EQ:
case CmpInst::ICMP_ULE:
// Equivalent to "A EqP B".
if (MaxRecurse)
if (Value *V = SimplifyICmpInst(EqP, A, B, TD, DT, MaxRecurse-1))
return V;
break;
case CmpInst::ICMP_NE:
case CmpInst::ICMP_UGT:
// Equivalent to "A inverse-EqP B".
if (MaxRecurse)
if (Value *V = SimplifyICmpInst(CmpInst::getInversePredicate(EqP), A, B,
TD, DT, MaxRecurse-1))
return V;
break;
case CmpInst::ICMP_UGE:
// Always true.
return Constant::getAllOnesValue(ITy);
case CmpInst::ICMP_ULT:
// Always false.
return Constant::getNullValue(ITy);
}
}
// If the comparison is with the result of a select instruction, check whether
// comparing with either branch of the select always yields the same value.
if (isa<SelectInst>(LHS) || isa<SelectInst>(RHS))

View File

@ -0,0 +1,145 @@
; RUN: opt < %s -instsimplify -S | FileCheck %s
define i1 @max1(i32 %x, i32 %y) {
; CHECK: @max1
%c = icmp sgt i32 %x, %y
%m = select i1 %c, i32 %x, i32 %y
%r = icmp slt i32 %m, %x
ret i1 %r
; CHECK: ret i1 false
}
define i1 @max2(i32 %x, i32 %y) {
; CHECK: @max2
%c = icmp sge i32 %x, %y
%m = select i1 %c, i32 %x, i32 %y
%r = icmp sge i32 %m, %x
ret i1 %r
; CHECK: ret i1 true
}
define i1 @max3(i32 %x, i32 %y) {
; CHECK: @max3
%c = icmp ugt i32 %x, %y
%m = select i1 %c, i32 %x, i32 %y
%r = icmp ult i32 %m, %x
ret i1 %r
; CHECK: ret i1 false
}
define i1 @max4(i32 %x, i32 %y) {
; CHECK: @max4
%c = icmp uge i32 %x, %y
%m = select i1 %c, i32 %x, i32 %y
%r = icmp uge i32 %m, %x
ret i1 %r
; CHECK: ret i1 true
}
define i1 @max5(i32 %x, i32 %y) {
; CHECK: @max5
%c = icmp sgt i32 %x, %y
%m = select i1 %c, i32 %x, i32 %y
%r = icmp sgt i32 %x, %m
ret i1 %r
; CHECK: ret i1 false
}
define i1 @max6(i32 %x, i32 %y) {
; CHECK: @max6
%c = icmp sge i32 %x, %y
%m = select i1 %c, i32 %x, i32 %y
%r = icmp sle i32 %x, %m
ret i1 %r
; CHECK: ret i1 true
}
define i1 @max7(i32 %x, i32 %y) {
; CHECK: @max7
%c = icmp ugt i32 %x, %y
%m = select i1 %c, i32 %x, i32 %y
%r = icmp ugt i32 %x, %m
ret i1 %r
; CHECK: ret i1 false
}
define i1 @max8(i32 %x, i32 %y) {
; CHECK: @max8
%c = icmp uge i32 %x, %y
%m = select i1 %c, i32 %x, i32 %y
%r = icmp ule i32 %x, %m
ret i1 %r
; CHECK: ret i1 true
}
define i1 @min1(i32 %x, i32 %y) {
; CHECK: @min1
%c = icmp sgt i32 %x, %y
%m = select i1 %c, i32 %y, i32 %x
%r = icmp sgt i32 %m, %x
ret i1 %r
; CHECK: ret i1 false
}
define i1 @min2(i32 %x, i32 %y) {
; CHECK: @min2
%c = icmp sge i32 %x, %y
%m = select i1 %c, i32 %y, i32 %x
%r = icmp sle i32 %m, %x
ret i1 %r
; CHECK: ret i1 true
}
define i1 @min3(i32 %x, i32 %y) {
; CHECK: @min3
%c = icmp ugt i32 %x, %y
%m = select i1 %c, i32 %y, i32 %x
%r = icmp ugt i32 %m, %x
ret i1 %r
; CHECK: ret i1 false
}
define i1 @min4(i32 %x, i32 %y) {
; CHECK: @min4
%c = icmp uge i32 %x, %y
%m = select i1 %c, i32 %y, i32 %x
%r = icmp ule i32 %m, %x
ret i1 %r
; CHECK: ret i1 true
}
define i1 @min5(i32 %x, i32 %y) {
; CHECK: @min5
%c = icmp sgt i32 %x, %y
%m = select i1 %c, i32 %y, i32 %x
%r = icmp slt i32 %x, %m
ret i1 %r
; CHECK: ret i1 false
}
define i1 @min6(i32 %x, i32 %y) {
; CHECK: @min6
%c = icmp sge i32 %x, %y
%m = select i1 %c, i32 %y, i32 %x
%r = icmp sge i32 %x, %m
ret i1 %r
; CHECK: ret i1 true
}
define i1 @min7(i32 %x, i32 %y) {
; CHECK: @min7
%c = icmp ugt i32 %x, %y
%m = select i1 %c, i32 %y, i32 %x
%r = icmp ult i32 %x, %m
ret i1 %r
; CHECK: ret i1 false
}
define i1 @min8(i32 %x, i32 %y) {
; CHECK: @min8
%c = icmp uge i32 %x, %y
%m = select i1 %c, i32 %y, i32 %x
%r = icmp uge i32 %x, %m
ret i1 %r
; CHECK: ret i1 true
}