[InstSimplify] refactor intrinsic simplifications; NFCI

llvm-svn: 338215
This commit is contained in:
Sanjay Patel 2018-07-29 14:42:08 +00:00
parent 38f01067ac
commit 64526ca2e5

View File

@ -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))