Skip to content

Commit

Permalink
Pattern matching code for intrinsics.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
milseman committed Dec 13, 2012
1 parent 05fa24c commit 8ad435f
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 15 deletions.
98 changes: 98 additions & 0 deletions include/llvm/Support/PatternMatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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

Expand Down
32 changes: 17 additions & 15 deletions lib/Transforms/InstCombine/InstCombineCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");

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

0 comments on commit 8ad435f

Please sign in to comment.