From 8ad435fa4809b5a4ad1043435cbafd5c9ddf2d93 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Thu, 13 Dec 2012 03:13:36 +0000 Subject: [PATCH] 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 --- include/llvm/Support/PatternMatch.h | 98 +++++++++++++++++++ .../InstCombine/InstCombineCalls.cpp | 32 +++--- 2 files changed, 115 insertions(+), 15 deletions(-) diff --git a/include/llvm/Support/PatternMatch.h b/include/llvm/Support/PatternMatch.h index edf997de59d..7420fab1a74 100644 --- a/include/llvm/Support/PatternMatch.h +++ b/include/llvm/Support/PatternMatch.h @@ -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(L, R); } +template +struct Argument_match { + unsigned OpI; + Opnd_t Val; + Argument_match(unsigned OpIdx, const Opnd_t &V) : OpI(OpIdx), Val(V) { } + + template + bool match(OpTy *V) { + CallSite CS(V); + return CS.isCall() && Val.match(CS.getArgument(OpI)); + } +}; + +/// Match an argument +template +inline Argument_match m_Argument(const Opnd_t &Op) { + return Argument_match(OpI, Op); +} + +/// Intrinsic matchers. +struct IntrinsicID_match { + unsigned ID; + IntrinsicID_match(unsigned IntrID) : ID(IntrID) { } + + template + bool match(OpTy *V) { + IntrinsicInst *II = dyn_cast(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 struct m_Intrinsic_Ty; +template +struct m_Intrinsic_Ty { + typedef match_combine_and > Ty; +}; +template +struct m_Intrinsic_Ty { + typedef match_combine_and::Ty, + Argument_match > Ty; +}; +template +struct m_Intrinsic_Ty { + typedef match_combine_and::Ty, + Argument_match > Ty; +}; +template +struct m_Intrinsic_Ty { + typedef match_combine_and::Ty, + Argument_match > Ty; +}; + +/// Match intrinsic calls like this: +/// m_Intrinsic(m_Value(X)) +template +inline IntrinsicID_match +m_Intrinsic() { return IntrinsicID_match(IntrID); } + +template +inline typename m_Intrinsic_Ty::Ty +m_Intrinsic(const T0 &Op0) { + return m_CombineAnd(m_Intrinsic(), m_Argument<0>(Op0)); +} + +template +inline typename m_Intrinsic_Ty::Ty +m_Intrinsic(const T0 &Op0, const T1 &Op1) { + return m_CombineAnd(m_Intrinsic(Op0), m_Argument<1>(Op1)); +} + +template +inline typename m_Intrinsic_Ty::Ty +m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2) { + return m_CombineAnd(m_Intrinsic(Op0, Op1), m_Argument<2>(Op2)); +} + +template +inline typename m_Intrinsic_Ty::Ty +m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3) { + return m_CombineAnd(m_Intrinsic(Op0, Op1, Op2), m_Argument<3>(Op3)); +} + +// Helper intrinsic matching specializations +template +inline typename m_Intrinsic_Ty::Ty +m_BSwap(const Opnd0 &Op0) { + return m_Intrinsic(Op0); +} + } // end namespace PatternMatch } // end namespace llvm diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 8cd9409f5e0..ba4a57329d5 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -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(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(II->getArgOperand(0))) { - if (IntrinsicInst *Operand = dyn_cast(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(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()); } }