[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; return true;
} }
template <typename IterTy> static Value *simplifyUnaryIntrinsic(Function *F, Value *Op0,
static Value *SimplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd, const SimplifyQuery &Q) {
const SimplifyQuery &Q, unsigned MaxRecurse) { // Idempotent functions return the same result when called repeatedly.
Intrinsic::ID IID = F->getIntrinsicID(); 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 Value *X;
if (NumOperands == 1) { switch (IID) {
// Perform idempotent optimizations case Intrinsic::fabs:
if (IsIdempotent(IID)) { if (SignBitMustBeZero(Op0, Q.TLI)) return Op0;
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(*ArgBegin)) { break;
if (II->getIntrinsicID() == IID) case Intrinsic::bswap:
return II; // bswap(bswap(x)) -> x
} if (match(Op0, m_BSwap(m_Value(X)))) return X;
} break;
case Intrinsic::bitreverse:
Value *IIOperand = *ArgBegin; // bitreverse(bitreverse(x)) -> x
Value *X; if (match(Op0, m_BitReverse(m_Value(X)))) return X;
switch (IID) { break;
case Intrinsic::fabs: { case Intrinsic::exp:
if (SignBitMustBeZero(IIOperand, Q.TLI)) // exp(log(x)) -> x
return IIOperand; if (Q.CxtI->hasAllowReassoc() &&
return nullptr; match(Op0, m_Intrinsic<Intrinsic::log>(m_Value(X)))) return X;
} break;
case Intrinsic::bswap: { case Intrinsic::exp2:
// bswap(bswap(x)) -> x // exp2(log2(x)) -> x
if (match(IIOperand, m_BSwap(m_Value(X)))) if (Q.CxtI->hasAllowReassoc() &&
return X; match(Op0, m_Intrinsic<Intrinsic::log2>(m_Value(X)))) return X;
return nullptr; break;
} case Intrinsic::log:
case Intrinsic::bitreverse: { // log(exp(x)) -> x
// bitreverse(bitreverse(x)) -> x if (Q.CxtI->hasAllowReassoc() &&
if (match(IIOperand, m_BitReverse(m_Value(X)))) match(Op0, m_Intrinsic<Intrinsic::exp>(m_Value(X)))) return X;
return X; break;
return nullptr; case Intrinsic::log2:
} // log2(exp2(x)) -> x
case Intrinsic::exp: { if (Q.CxtI->hasAllowReassoc() &&
// exp(log(x)) -> x match(Op0, m_Intrinsic<Intrinsic::exp2>(m_Value(X)))) return X;
if (Q.CxtI->hasAllowReassoc() && break;
match(IIOperand, m_Intrinsic<Intrinsic::log>(m_Value(X)))) default:
return X; break;
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;
}
} }
// Binary Ops return nullptr;
if (NumOperands == 2) { }
Value *LHS = *ArgBegin;
Value *RHS = *(ArgBegin + 1);
Type *ReturnType = F->getReturnType();
switch (IID) { static Value *simplifyBinaryIntrinsic(Function *F, Value *Op0, Value *Op1,
case Intrinsic::usub_with_overflow: const SimplifyQuery &Q) {
case Intrinsic::ssub_with_overflow: { Intrinsic::ID IID = F->getIntrinsicID();
// X - X -> { 0, false } Type *ReturnType = F->getReturnType();
if (LHS == RHS) switch (IID) {
return Constant::getNullValue(ReturnType); case Intrinsic::usub_with_overflow:
case Intrinsic::ssub_with_overflow:
// X - undef -> undef // X - X -> { 0, false }
// undef - X -> undef if (Op0 == Op1)
if (isa<UndefValue>(LHS) || isa<UndefValue>(RHS)) return Constant::getNullValue(ReturnType);
return UndefValue::get(ReturnType); // X - undef -> undef
// undef - X -> undef
return nullptr; if (isa<UndefValue>(Op0) || isa<UndefValue>(Op1))
} return UndefValue::get(ReturnType);
case Intrinsic::uadd_with_overflow: break;
case Intrinsic::sadd_with_overflow: { case Intrinsic::uadd_with_overflow:
// X + undef -> undef case Intrinsic::sadd_with_overflow:
if (isa<UndefValue>(LHS) || isa<UndefValue>(RHS)) // X + undef -> undef
return UndefValue::get(ReturnType); if (isa<UndefValue>(Op0) || isa<UndefValue>(Op1))
return UndefValue::get(ReturnType);
return nullptr; break;
} case Intrinsic::umul_with_overflow:
case Intrinsic::umul_with_overflow: case Intrinsic::smul_with_overflow:
case Intrinsic::smul_with_overflow: { // 0 * X -> { 0, false }
// 0 * X -> { 0, false } // X * 0 -> { 0, false }
// X * 0 -> { 0, false } if (match(Op0, m_Zero()) || match(Op1, m_Zero()))
if (match(LHS, m_Zero()) || match(RHS, m_Zero())) return Constant::getNullValue(ReturnType);
return Constant::getNullValue(ReturnType); // undef * X -> { 0, false }
// X * undef -> { 0, false }
// undef * X -> { 0, false } if (match(Op0, m_Undef()) || match(Op1, m_Undef()))
// X * undef -> { 0, false } return Constant::getNullValue(ReturnType);
if (match(LHS, m_Undef()) || match(RHS, m_Undef())) break;
return Constant::getNullValue(ReturnType); case Intrinsic::load_relative:
if (auto *C0 = dyn_cast<Constant>(Op0))
return nullptr; if (auto *C1 = dyn_cast<Constant>(Op1))
}
case Intrinsic::load_relative: {
Constant *C0 = dyn_cast<Constant>(LHS);
Constant *C1 = dyn_cast<Constant>(RHS);
if (C0 && C1)
return SimplifyRelativeLoad(C0, C1, Q.DL); return SimplifyRelativeLoad(C0, C1, Q.DL);
return nullptr; break;
} case Intrinsic::powi:
case Intrinsic::powi: if (auto *Power = dyn_cast<ConstantInt>(Op1)) {
if (ConstantInt *Power = dyn_cast<ConstantInt>(RHS)) { // powi(x, 0) -> 1.0
// powi(x, 0) -> 1.0 if (Power->isZero())
if (Power->isZero()) return ConstantFP::get(Op0->getType(), 1.0);
return ConstantFP::get(LHS->getType(), 1.0); // powi(x, 1) -> x
// powi(x, 1) -> x if (Power->isOne())
if (Power->isOne()) return Op0;
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::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) { switch (IID) {
case Intrinsic::masked_load: { case Intrinsic::masked_load: {
Value *MaskArg = ArgBegin[2]; Value *MaskArg = ArgBegin[2];
@ -4817,7 +4799,7 @@ static Value *SimplifyCall(ImmutableCallSite CS, Value *V, IterTy ArgBegin,
return nullptr; return nullptr;
if (F->isIntrinsic()) if (F->isIntrinsic())
if (Value *Ret = SimplifyIntrinsic(F, ArgBegin, ArgEnd, Q, MaxRecurse)) if (Value *Ret = simplifyIntrinsic(F, ArgBegin, ArgEnd, Q))
return Ret; return Ret;
if (!canConstantFoldCallTo(CS, F)) if (!canConstantFoldCallTo(CS, F))