mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-23 14:25:07 +00:00
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:
@@ -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.
|
||||
|
Reference in New Issue
Block a user