mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-08 12:21:04 +00:00
[InstSimplify] refactor intrinsic simplifications; NFCI
llvm-svn: 338215
This commit is contained in:
parent
38f01067ac
commit
64526ca2e5
@ -4641,149 +4641,131 @@ static bool maskIsAllZeroOrUndef(Value *Mask) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename IterTy>
|
||||
static Value *SimplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd,
|
||||
const SimplifyQuery &Q, unsigned MaxRecurse) {
|
||||
static Value *simplifyUnaryIntrinsic(Function *F, Value *Op0,
|
||||
const SimplifyQuery &Q) {
|
||||
// Idempotent functions return the same result when called repeatedly.
|
||||
Intrinsic::ID IID = F->getIntrinsicID();
|
||||
unsigned NumOperands = std::distance(ArgBegin, ArgEnd);
|
||||
if (IsIdempotent(IID))
|
||||
if (auto *II = dyn_cast<IntrinsicInst>(Op0))
|
||||
if (II->getIntrinsicID() == IID)
|
||||
return II;
|
||||
|
||||
// Unary Ops
|
||||
if (NumOperands == 1) {
|
||||
// Perform idempotent optimizations
|
||||
if (IsIdempotent(IID)) {
|
||||
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(*ArgBegin)) {
|
||||
if (II->getIntrinsicID() == IID)
|
||||
return II;
|
||||
}
|
||||
}
|
||||
|
||||
Value *IIOperand = *ArgBegin;
|
||||
Value *X;
|
||||
switch (IID) {
|
||||
case Intrinsic::fabs: {
|
||||
if (SignBitMustBeZero(IIOperand, Q.TLI))
|
||||
return IIOperand;
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::bswap: {
|
||||
// bswap(bswap(x)) -> x
|
||||
if (match(IIOperand, m_BSwap(m_Value(X))))
|
||||
return X;
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::bitreverse: {
|
||||
// bitreverse(bitreverse(x)) -> x
|
||||
if (match(IIOperand, m_BitReverse(m_Value(X))))
|
||||
return X;
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::exp: {
|
||||
// exp(log(x)) -> x
|
||||
if (Q.CxtI->hasAllowReassoc() &&
|
||||
match(IIOperand, m_Intrinsic<Intrinsic::log>(m_Value(X))))
|
||||
return X;
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::exp2: {
|
||||
// exp2(log2(x)) -> x
|
||||
if (Q.CxtI->hasAllowReassoc() &&
|
||||
match(IIOperand, m_Intrinsic<Intrinsic::log2>(m_Value(X))))
|
||||
return X;
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::log: {
|
||||
// log(exp(x)) -> x
|
||||
if (Q.CxtI->hasAllowReassoc() &&
|
||||
match(IIOperand, m_Intrinsic<Intrinsic::exp>(m_Value(X))))
|
||||
return X;
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::log2: {
|
||||
// log2(exp2(x)) -> x
|
||||
if (Q.CxtI->hasAllowReassoc() &&
|
||||
match(IIOperand, m_Intrinsic<Intrinsic::exp2>(m_Value(X)))) {
|
||||
return X;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
Value *X;
|
||||
switch (IID) {
|
||||
case Intrinsic::fabs:
|
||||
if (SignBitMustBeZero(Op0, Q.TLI)) return Op0;
|
||||
break;
|
||||
case Intrinsic::bswap:
|
||||
// bswap(bswap(x)) -> x
|
||||
if (match(Op0, m_BSwap(m_Value(X)))) return X;
|
||||
break;
|
||||
case Intrinsic::bitreverse:
|
||||
// bitreverse(bitreverse(x)) -> x
|
||||
if (match(Op0, m_BitReverse(m_Value(X)))) return X;
|
||||
break;
|
||||
case Intrinsic::exp:
|
||||
// exp(log(x)) -> x
|
||||
if (Q.CxtI->hasAllowReassoc() &&
|
||||
match(Op0, m_Intrinsic<Intrinsic::log>(m_Value(X)))) return X;
|
||||
break;
|
||||
case Intrinsic::exp2:
|
||||
// exp2(log2(x)) -> x
|
||||
if (Q.CxtI->hasAllowReassoc() &&
|
||||
match(Op0, m_Intrinsic<Intrinsic::log2>(m_Value(X)))) return X;
|
||||
break;
|
||||
case Intrinsic::log:
|
||||
// log(exp(x)) -> x
|
||||
if (Q.CxtI->hasAllowReassoc() &&
|
||||
match(Op0, m_Intrinsic<Intrinsic::exp>(m_Value(X)))) return X;
|
||||
break;
|
||||
case Intrinsic::log2:
|
||||
// log2(exp2(x)) -> x
|
||||
if (Q.CxtI->hasAllowReassoc() &&
|
||||
match(Op0, m_Intrinsic<Intrinsic::exp2>(m_Value(X)))) return X;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Binary Ops
|
||||
if (NumOperands == 2) {
|
||||
Value *LHS = *ArgBegin;
|
||||
Value *RHS = *(ArgBegin + 1);
|
||||
Type *ReturnType = F->getReturnType();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
switch (IID) {
|
||||
case Intrinsic::usub_with_overflow:
|
||||
case Intrinsic::ssub_with_overflow: {
|
||||
// X - X -> { 0, false }
|
||||
if (LHS == RHS)
|
||||
return Constant::getNullValue(ReturnType);
|
||||
|
||||
// X - undef -> undef
|
||||
// undef - X -> undef
|
||||
if (isa<UndefValue>(LHS) || isa<UndefValue>(RHS))
|
||||
return UndefValue::get(ReturnType);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::uadd_with_overflow:
|
||||
case Intrinsic::sadd_with_overflow: {
|
||||
// X + undef -> undef
|
||||
if (isa<UndefValue>(LHS) || isa<UndefValue>(RHS))
|
||||
return UndefValue::get(ReturnType);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::umul_with_overflow:
|
||||
case Intrinsic::smul_with_overflow: {
|
||||
// 0 * X -> { 0, false }
|
||||
// X * 0 -> { 0, false }
|
||||
if (match(LHS, m_Zero()) || match(RHS, m_Zero()))
|
||||
return Constant::getNullValue(ReturnType);
|
||||
|
||||
// undef * X -> { 0, false }
|
||||
// X * undef -> { 0, false }
|
||||
if (match(LHS, m_Undef()) || match(RHS, m_Undef()))
|
||||
return Constant::getNullValue(ReturnType);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::load_relative: {
|
||||
Constant *C0 = dyn_cast<Constant>(LHS);
|
||||
Constant *C1 = dyn_cast<Constant>(RHS);
|
||||
if (C0 && C1)
|
||||
static Value *simplifyBinaryIntrinsic(Function *F, Value *Op0, Value *Op1,
|
||||
const SimplifyQuery &Q) {
|
||||
Intrinsic::ID IID = F->getIntrinsicID();
|
||||
Type *ReturnType = F->getReturnType();
|
||||
switch (IID) {
|
||||
case Intrinsic::usub_with_overflow:
|
||||
case Intrinsic::ssub_with_overflow:
|
||||
// X - X -> { 0, false }
|
||||
if (Op0 == Op1)
|
||||
return Constant::getNullValue(ReturnType);
|
||||
// X - undef -> undef
|
||||
// undef - X -> undef
|
||||
if (isa<UndefValue>(Op0) || isa<UndefValue>(Op1))
|
||||
return UndefValue::get(ReturnType);
|
||||
break;
|
||||
case Intrinsic::uadd_with_overflow:
|
||||
case Intrinsic::sadd_with_overflow:
|
||||
// X + undef -> undef
|
||||
if (isa<UndefValue>(Op0) || isa<UndefValue>(Op1))
|
||||
return UndefValue::get(ReturnType);
|
||||
break;
|
||||
case Intrinsic::umul_with_overflow:
|
||||
case Intrinsic::smul_with_overflow:
|
||||
// 0 * X -> { 0, false }
|
||||
// X * 0 -> { 0, false }
|
||||
if (match(Op0, m_Zero()) || match(Op1, m_Zero()))
|
||||
return Constant::getNullValue(ReturnType);
|
||||
// undef * X -> { 0, false }
|
||||
// X * undef -> { 0, false }
|
||||
if (match(Op0, m_Undef()) || match(Op1, m_Undef()))
|
||||
return Constant::getNullValue(ReturnType);
|
||||
break;
|
||||
case Intrinsic::load_relative:
|
||||
if (auto *C0 = dyn_cast<Constant>(Op0))
|
||||
if (auto *C1 = dyn_cast<Constant>(Op1))
|
||||
return SimplifyRelativeLoad(C0, C1, Q.DL);
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::powi:
|
||||
if (ConstantInt *Power = dyn_cast<ConstantInt>(RHS)) {
|
||||
// powi(x, 0) -> 1.0
|
||||
if (Power->isZero())
|
||||
return ConstantFP::get(LHS->getType(), 1.0);
|
||||
// powi(x, 1) -> x
|
||||
if (Power->isOne())
|
||||
return LHS;
|
||||
}
|
||||
return nullptr;
|
||||
case Intrinsic::maxnum:
|
||||
case Intrinsic::minnum:
|
||||
// If one argument is NaN, return the other argument.
|
||||
if (match(LHS, m_NaN()))
|
||||
return RHS;
|
||||
if (match(RHS, m_NaN()))
|
||||
return LHS;
|
||||
return nullptr;
|
||||
default:
|
||||
return nullptr;
|
||||
break;
|
||||
case Intrinsic::powi:
|
||||
if (auto *Power = dyn_cast<ConstantInt>(Op1)) {
|
||||
// powi(x, 0) -> 1.0
|
||||
if (Power->isZero())
|
||||
return ConstantFP::get(Op0->getType(), 1.0);
|
||||
// powi(x, 1) -> x
|
||||
if (Power->isOne())
|
||||
return Op0;
|
||||
}
|
||||
break;
|
||||
case Intrinsic::maxnum:
|
||||
case Intrinsic::minnum:
|
||||
// If one argument is NaN, return the other argument.
|
||||
if (match(Op0, m_NaN())) return Op1;
|
||||
if (match(Op1, m_NaN())) return Op0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Simplify calls to llvm.masked.load.*
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename IterTy>
|
||||
static Value *simplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd,
|
||||
const SimplifyQuery &Q) {
|
||||
// Intrinsics with no operands have some kind of side effect. Don't simplify.
|
||||
unsigned NumOperands = std::distance(ArgBegin, ArgEnd);
|
||||
if (NumOperands == 0)
|
||||
return nullptr;
|
||||
|
||||
Intrinsic::ID IID = F->getIntrinsicID();
|
||||
if (NumOperands == 1)
|
||||
return simplifyUnaryIntrinsic(F, ArgBegin[0], Q);
|
||||
|
||||
if (NumOperands == 2)
|
||||
return simplifyBinaryIntrinsic(F, ArgBegin[0], ArgBegin[1], Q);
|
||||
|
||||
// Handle intrinsics with 3 or more arguments.
|
||||
switch (IID) {
|
||||
case Intrinsic::masked_load: {
|
||||
Value *MaskArg = ArgBegin[2];
|
||||
@ -4817,7 +4799,7 @@ static Value *SimplifyCall(ImmutableCallSite CS, Value *V, IterTy ArgBegin,
|
||||
return nullptr;
|
||||
|
||||
if (F->isIntrinsic())
|
||||
if (Value *Ret = SimplifyIntrinsic(F, ArgBegin, ArgEnd, Q, MaxRecurse))
|
||||
if (Value *Ret = simplifyIntrinsic(F, ArgBegin, ArgEnd, Q))
|
||||
return Ret;
|
||||
|
||||
if (!canConstantFoldCallTo(CS, F))
|
||||
|
Loading…
Reference in New Issue
Block a user