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.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@170091 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michael Ilseman 2012-12-13 03:13:36 +00:00
parent 05fa24c574
commit 8ad435fa48
2 changed files with 115 additions and 15 deletions

View File

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

View File

@ -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());
}
}