forked from OSchip/llvm-project
Pattern matching code for intrinsics.
Provides m_Argument that allows matching against a CallSite's specified argument. Provides m_Intrinsic pattern that can be templatized over the intrinsic id and bind/match arguments similarly to other pattern matchers. Implementations provided for 0 to 4 arguments, though it's very simple to extend for more. Also provides example template specialization for bswap (m_BSwap) and example of code cleanup for its use. llvm-svn: 170091
This commit is contained in:
parent
cf6d6317cc
commit
536cc32ba0
|
@ -31,7 +31,9 @@
|
|||
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/IntrinsicInst.h"
|
||||
#include "llvm/Operator.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace PatternMatch {
|
||||
|
@ -897,6 +899,102 @@ m_UMin(const LHS &L, const RHS &R) {
|
|||
return MaxMin_match<LHS, RHS, umin_pred_ty>(L, R);
|
||||
}
|
||||
|
||||
template<typename Opnd_t>
|
||||
struct Argument_match {
|
||||
unsigned OpI;
|
||||
Opnd_t Val;
|
||||
Argument_match(unsigned OpIdx, const Opnd_t &V) : OpI(OpIdx), Val(V) { }
|
||||
|
||||
template<typename OpTy>
|
||||
bool match(OpTy *V) {
|
||||
CallSite CS(V);
|
||||
return CS.isCall() && Val.match(CS.getArgument(OpI));
|
||||
}
|
||||
};
|
||||
|
||||
/// Match an argument
|
||||
template<unsigned OpI, typename Opnd_t>
|
||||
inline Argument_match<Opnd_t> m_Argument(const Opnd_t &Op) {
|
||||
return Argument_match<Opnd_t>(OpI, Op);
|
||||
}
|
||||
|
||||
/// Intrinsic matchers.
|
||||
struct IntrinsicID_match {
|
||||
unsigned ID;
|
||||
IntrinsicID_match(unsigned IntrID) : ID(IntrID) { }
|
||||
|
||||
template<typename OpTy>
|
||||
bool match(OpTy *V) {
|
||||
IntrinsicInst *II = dyn_cast<IntrinsicInst>(V);
|
||||
return II && II->getIntrinsicID() == ID;
|
||||
}
|
||||
};
|
||||
|
||||
/// Intrinsic matches are combinations of ID matchers, and argument
|
||||
/// matchers. Higher arity matcher are defined recursively in terms of and-ing
|
||||
/// them with lower arity matchers. Here's some convenient typedefs for up to
|
||||
/// several arguments, and more can be added as needed
|
||||
template <typename T0 = void, typename T1 = void, typename T2 = void,
|
||||
typename T3 = void, typename T4 = void, typename T5 = void,
|
||||
typename T6 = void, typename T7 = void, typename T8 = void,
|
||||
typename T9 = void, typename T10 = void> struct m_Intrinsic_Ty;
|
||||
template <typename T0>
|
||||
struct m_Intrinsic_Ty<T0> {
|
||||
typedef match_combine_and<IntrinsicID_match, Argument_match<T0> > Ty;
|
||||
};
|
||||
template <typename T0, typename T1>
|
||||
struct m_Intrinsic_Ty<T0, T1> {
|
||||
typedef match_combine_and<typename m_Intrinsic_Ty<T0>::Ty,
|
||||
Argument_match<T1> > Ty;
|
||||
};
|
||||
template <typename T0, typename T1, typename T2>
|
||||
struct m_Intrinsic_Ty<T0, T1, T2> {
|
||||
typedef match_combine_and<typename m_Intrinsic_Ty<T0, T1>::Ty,
|
||||
Argument_match<T2> > Ty;
|
||||
};
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
struct m_Intrinsic_Ty<T0, T1, T2, T3> {
|
||||
typedef match_combine_and<typename m_Intrinsic_Ty<T0, T1, T2>::Ty,
|
||||
Argument_match<T3> > Ty;
|
||||
};
|
||||
|
||||
/// Match intrinsic calls like this:
|
||||
/// m_Intrinsic<Intrinsic::fabs>(m_Value(X))
|
||||
template <unsigned IntrID>
|
||||
inline IntrinsicID_match
|
||||
m_Intrinsic() { return IntrinsicID_match(IntrID); }
|
||||
|
||||
template<unsigned IntrID, typename T0>
|
||||
inline typename m_Intrinsic_Ty<T0>::Ty
|
||||
m_Intrinsic(const T0 &Op0) {
|
||||
return m_CombineAnd(m_Intrinsic<IntrID>(), m_Argument<0>(Op0));
|
||||
}
|
||||
|
||||
template<unsigned IntrID, typename T0, typename T1>
|
||||
inline typename m_Intrinsic_Ty<T0, T1>::Ty
|
||||
m_Intrinsic(const T0 &Op0, const T1 &Op1) {
|
||||
return m_CombineAnd(m_Intrinsic<IntrID>(Op0), m_Argument<1>(Op1));
|
||||
}
|
||||
|
||||
template<unsigned IntrID, typename T0, typename T1, typename T2>
|
||||
inline typename m_Intrinsic_Ty<T0, T1, T2>::Ty
|
||||
m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2) {
|
||||
return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1), m_Argument<2>(Op2));
|
||||
}
|
||||
|
||||
template<unsigned IntrID, typename T0, typename T1, typename T2, typename T3>
|
||||
inline typename m_Intrinsic_Ty<T0, T1, T2, T3>::Ty
|
||||
m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3) {
|
||||
return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1, Op2), m_Argument<3>(Op3));
|
||||
}
|
||||
|
||||
// Helper intrinsic matching specializations
|
||||
template<typename Opnd0>
|
||||
inline typename m_Intrinsic_Ty<Opnd0>::Ty
|
||||
m_BSwap(const Opnd0 &Op0) {
|
||||
return m_Intrinsic<Intrinsic::bswap>(Op0);
|
||||
}
|
||||
|
||||
} // end namespace PatternMatch
|
||||
} // end namespace llvm
|
||||
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
#include "llvm/Analysis/MemoryBuiltins.h"
|
||||
#include "llvm/DataLayout.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#include "llvm/Support/PatternMatch.h"
|
||||
#include "llvm/Transforms/Utils/BuildLibCalls.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
using namespace llvm;
|
||||
using namespace PatternMatch;
|
||||
|
||||
STATISTIC(NumSimplified, "Number of library calls simplified");
|
||||
|
||||
|
@ -276,25 +278,25 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
|
|||
return ReplaceInstUsesWith(CI, ConstantInt::get(CI.getType(), Size));
|
||||
return 0;
|
||||
}
|
||||
case Intrinsic::bswap:
|
||||
case Intrinsic::bswap: {
|
||||
Value *IIOperand = II->getArgOperand(0);
|
||||
Value *X = 0;
|
||||
|
||||
// bswap(bswap(x)) -> x
|
||||
if (IntrinsicInst *Operand = dyn_cast<IntrinsicInst>(II->getArgOperand(0)))
|
||||
if (Operand->getIntrinsicID() == Intrinsic::bswap)
|
||||
return ReplaceInstUsesWith(CI, Operand->getArgOperand(0));
|
||||
if (match(IIOperand, m_BSwap(m_Value(X))))
|
||||
return ReplaceInstUsesWith(CI, X);
|
||||
|
||||
// bswap(trunc(bswap(x))) -> trunc(lshr(x, c))
|
||||
if (TruncInst *TI = dyn_cast<TruncInst>(II->getArgOperand(0))) {
|
||||
if (IntrinsicInst *Operand = dyn_cast<IntrinsicInst>(TI->getOperand(0)))
|
||||
if (Operand->getIntrinsicID() == Intrinsic::bswap) {
|
||||
unsigned C = Operand->getType()->getPrimitiveSizeInBits() -
|
||||
TI->getType()->getPrimitiveSizeInBits();
|
||||
Value *CV = ConstantInt::get(Operand->getType(), C);
|
||||
Value *V = Builder->CreateLShr(Operand->getArgOperand(0), CV);
|
||||
return new TruncInst(V, TI->getType());
|
||||
}
|
||||
if (match(IIOperand, m_Trunc(m_BSwap(m_Value(X))))) {
|
||||
unsigned C = X->getType()->getPrimitiveSizeInBits() -
|
||||
IIOperand->getType()->getPrimitiveSizeInBits();
|
||||
Value *CV = ConstantInt::get(X->getType(), C);
|
||||
Value *V = Builder->CreateLShr(X, CV);
|
||||
return new TruncInst(V, IIOperand->getType());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Intrinsic::powi:
|
||||
if (ConstantInt *Power = dyn_cast<ConstantInt>(II->getArgOperand(1))) {
|
||||
// powi(x, 0) -> 1.0
|
||||
|
@ -693,7 +695,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
|
|||
if (Splat->isOne()) {
|
||||
if (Zext)
|
||||
return CastInst::CreateZExtOrBitCast(Arg0, II->getType());
|
||||
// else
|
||||
// else
|
||||
return CastInst::CreateSExtOrBitCast(Arg0, II->getType());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue