Add minnum / maxnum intrinsics

These are named following the IEEE-754 names for these
functions, rather than the libm fmin / fmax to avoid
possible ambiguities. Some languages may implement something
resembling fmin / fmax which return NaN if either operand is
to propagate errors. These implement the IEEE-754 semantics
of returning the other operand if either is a NaN representing
missing data.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@220341 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matt Arsenault
2014-10-21 23:00:20 +00:00
parent cb3866e72e
commit 252134602f
14 changed files with 773 additions and 2 deletions

View File

@@ -519,6 +519,90 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
}
}
break;
case Intrinsic::minnum:
case Intrinsic::maxnum: {
Value *Arg0 = II->getArgOperand(0);
Value *Arg1 = II->getArgOperand(1);
// fmin(x, x) -> x
if (Arg0 == Arg1)
return ReplaceInstUsesWith(CI, Arg0);
const ConstantFP *C0 = dyn_cast<ConstantFP>(Arg0);
const ConstantFP *C1 = dyn_cast<ConstantFP>(Arg1);
// Canonicalize constants into the RHS.
if (C0 && !C1) {
II->setArgOperand(0, Arg1);
II->setArgOperand(1, Arg0);
return II;
}
// fmin(x, nan) -> x
if (C1 && C1->isNaN())
return ReplaceInstUsesWith(CI, Arg0);
// This is the value because if undef were NaN, we would return the other
// value and cannot return a NaN unless both operands are.
//
// fmin(undef, x) -> x
if (isa<UndefValue>(Arg0))
return ReplaceInstUsesWith(CI, Arg1);
// fmin(x, undef) -> x
if (isa<UndefValue>(Arg1))
return ReplaceInstUsesWith(CI, Arg0);
Value *X = nullptr;
Value *Y = nullptr;
if (II->getIntrinsicID() == Intrinsic::minnum) {
// fmin(x, fmin(x, y)) -> fmin(x, y)
// fmin(y, fmin(x, y)) -> fmin(x, y)
if (match(Arg1, m_FMin(m_Value(X), m_Value(Y)))) {
if (Arg0 == X || Arg0 == Y)
return ReplaceInstUsesWith(CI, Arg1);
}
// fmin(fmin(x, y), x) -> fmin(x, y)
// fmin(fmin(x, y), y) -> fmin(x, y)
if (match(Arg0, m_FMin(m_Value(X), m_Value(Y)))) {
if (Arg1 == X || Arg1 == Y)
return ReplaceInstUsesWith(CI, Arg0);
}
// TODO: fmin(nnan x, inf) -> x
// TODO: fmin(nnan ninf x, flt_max) -> x
if (C1 && C1->isInfinity()) {
// fmin(x, -inf) -> -inf
if (C1->isNegative())
return ReplaceInstUsesWith(CI, Arg1);
}
} else {
assert(II->getIntrinsicID() == Intrinsic::maxnum);
// fmax(x, fmax(x, y)) -> fmax(x, y)
// fmax(y, fmax(x, y)) -> fmax(x, y)
if (match(Arg1, m_FMax(m_Value(X), m_Value(Y)))) {
if (Arg0 == X || Arg0 == Y)
return ReplaceInstUsesWith(CI, Arg1);
}
// fmax(fmax(x, y), x) -> fmax(x, y)
// fmax(fmax(x, y), y) -> fmax(x, y)
if (match(Arg0, m_FMax(m_Value(X), m_Value(Y)))) {
if (Arg1 == X || Arg1 == Y)
return ReplaceInstUsesWith(CI, Arg0);
}
// TODO: fmax(nnan x, -inf) -> x
// TODO: fmax(nnan ninf x, -flt_max) -> x
if (C1 && C1->isInfinity()) {
// fmax(x, inf) -> inf
if (!C1->isNegative())
return ReplaceInstUsesWith(CI, Arg1);
}
}
break;
}
case Intrinsic::ppc_altivec_lvx:
case Intrinsic::ppc_altivec_lvxl:
// Turn PPC lvx -> load if the pointer is known aligned.