Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
35266 views
//===- VPlanPatternMatch.h - Match on VPValues and recipes ------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file provides a simple and efficient mechanism for performing general9// tree-based pattern matches on the VPlan values and recipes, based on10// LLVM's IR pattern matchers.11//12// Currently it provides generic matchers for unary and binary VPInstructions,13// and specialized matchers like m_Not, m_ActiveLaneMask, m_BranchOnCond,14// m_BranchOnCount to match specific VPInstructions.15// TODO: Add missing matchers for additional opcodes and recipes as needed.16//17//===----------------------------------------------------------------------===//1819#ifndef LLVM_TRANSFORM_VECTORIZE_VPLANPATTERNMATCH_H20#define LLVM_TRANSFORM_VECTORIZE_VPLANPATTERNMATCH_H2122#include "VPlan.h"2324namespace llvm {25namespace VPlanPatternMatch {2627template <typename Val, typename Pattern> bool match(Val *V, const Pattern &P) {28return const_cast<Pattern &>(P).match(V);29}3031template <typename Class> struct class_match {32template <typename ITy> bool match(ITy *V) { return isa<Class>(V); }33};3435/// Match an arbitrary VPValue and ignore it.36inline class_match<VPValue> m_VPValue() { return class_match<VPValue>(); }3738template <typename Class> struct bind_ty {39Class *&VR;4041bind_ty(Class *&V) : VR(V) {}4243template <typename ITy> bool match(ITy *V) {44if (auto *CV = dyn_cast<Class>(V)) {45VR = CV;46return true;47}48return false;49}50};5152/// Match a specified integer value or vector of all elements of that53/// value. \p BitWidth optionally specifies the bitwidth the matched constant54/// must have. If it is 0, the matched constant can have any bitwidth.55template <unsigned BitWidth = 0> struct specific_intval {56APInt Val;5758specific_intval(APInt V) : Val(std::move(V)) {}5960bool match(VPValue *VPV) {61if (!VPV->isLiveIn())62return false;63Value *V = VPV->getLiveInIRValue();64const auto *CI = dyn_cast<ConstantInt>(V);65if (!CI && V->getType()->isVectorTy())66if (const auto *C = dyn_cast<Constant>(V))67CI = dyn_cast_or_null<ConstantInt>(68C->getSplatValue(/*AllowPoison=*/false));69if (!CI)70return false;7172assert((BitWidth == 0 || CI->getBitWidth() == BitWidth) &&73"Trying the match constant with unexpected bitwidth.");74return APInt::isSameValue(CI->getValue(), Val);75}76};7778inline specific_intval<0> m_SpecificInt(uint64_t V) {79return specific_intval<0>(APInt(64, V));80}8182inline specific_intval<1> m_False() { return specific_intval<1>(APInt(64, 0)); }8384/// Matching combinators85template <typename LTy, typename RTy> struct match_combine_or {86LTy L;87RTy R;8889match_combine_or(const LTy &Left, const RTy &Right) : L(Left), R(Right) {}9091template <typename ITy> bool match(ITy *V) {92if (L.match(V))93return true;94if (R.match(V))95return true;96return false;97}98};99100template <typename LTy, typename RTy>101inline match_combine_or<LTy, RTy> m_CombineOr(const LTy &L, const RTy &R) {102return match_combine_or<LTy, RTy>(L, R);103}104105/// Match a VPValue, capturing it if we match.106inline bind_ty<VPValue> m_VPValue(VPValue *&V) { return V; }107108namespace detail {109110/// A helper to match an opcode against multiple recipe types.111template <unsigned Opcode, typename...> struct MatchRecipeAndOpcode {};112113template <unsigned Opcode, typename RecipeTy>114struct MatchRecipeAndOpcode<Opcode, RecipeTy> {115static bool match(const VPRecipeBase *R) {116auto *DefR = dyn_cast<RecipeTy>(R);117return DefR && DefR->getOpcode() == Opcode;118}119};120121template <unsigned Opcode, typename RecipeTy, typename... RecipeTys>122struct MatchRecipeAndOpcode<Opcode, RecipeTy, RecipeTys...> {123static bool match(const VPRecipeBase *R) {124return MatchRecipeAndOpcode<Opcode, RecipeTy>::match(R) ||125MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R);126}127};128} // namespace detail129130template <typename Op0_t, unsigned Opcode, typename... RecipeTys>131struct UnaryRecipe_match {132Op0_t Op0;133134UnaryRecipe_match(Op0_t Op0) : Op0(Op0) {}135136bool match(const VPValue *V) {137auto *DefR = V->getDefiningRecipe();138return DefR && match(DefR);139}140141bool match(const VPRecipeBase *R) {142if (!detail::MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R))143return false;144assert(R->getNumOperands() == 1 &&145"recipe with matched opcode does not have 1 operands");146return Op0.match(R->getOperand(0));147}148};149150template <typename Op0_t, unsigned Opcode>151using UnaryVPInstruction_match =152UnaryRecipe_match<Op0_t, Opcode, VPInstruction>;153154template <typename Op0_t, unsigned Opcode>155using AllUnaryRecipe_match =156UnaryRecipe_match<Op0_t, Opcode, VPWidenRecipe, VPReplicateRecipe,157VPWidenCastRecipe, VPInstruction>;158159template <typename Op0_t, typename Op1_t, unsigned Opcode, bool Commutative,160typename... RecipeTys>161struct BinaryRecipe_match {162Op0_t Op0;163Op1_t Op1;164165BinaryRecipe_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {}166167bool match(const VPValue *V) {168auto *DefR = V->getDefiningRecipe();169return DefR && match(DefR);170}171172bool match(const VPSingleDefRecipe *R) {173return match(static_cast<const VPRecipeBase *>(R));174}175176bool match(const VPRecipeBase *R) {177if (!detail::MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R))178return false;179assert(R->getNumOperands() == 2 &&180"recipe with matched opcode does not have 2 operands");181if (Op0.match(R->getOperand(0)) && Op1.match(R->getOperand(1)))182return true;183return Commutative && Op0.match(R->getOperand(1)) &&184Op1.match(R->getOperand(0));185}186};187188template <typename Op0_t, typename Op1_t, unsigned Opcode>189using BinaryVPInstruction_match =190BinaryRecipe_match<Op0_t, Op1_t, Opcode, /*Commutative*/ false,191VPInstruction>;192193template <typename Op0_t, typename Op1_t, unsigned Opcode,194bool Commutative = false>195using AllBinaryRecipe_match =196BinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative, VPWidenRecipe,197VPReplicateRecipe, VPWidenCastRecipe, VPInstruction>;198199template <unsigned Opcode, typename Op0_t>200inline UnaryVPInstruction_match<Op0_t, Opcode>201m_VPInstruction(const Op0_t &Op0) {202return UnaryVPInstruction_match<Op0_t, Opcode>(Op0);203}204205template <unsigned Opcode, typename Op0_t, typename Op1_t>206inline BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>207m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1) {208return BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>(Op0, Op1);209}210211template <typename Op0_t>212inline UnaryVPInstruction_match<Op0_t, VPInstruction::Not>213m_Not(const Op0_t &Op0) {214return m_VPInstruction<VPInstruction::Not>(Op0);215}216217template <typename Op0_t>218inline UnaryVPInstruction_match<Op0_t, VPInstruction::BranchOnCond>219m_BranchOnCond(const Op0_t &Op0) {220return m_VPInstruction<VPInstruction::BranchOnCond>(Op0);221}222223template <typename Op0_t, typename Op1_t>224inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::ActiveLaneMask>225m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1) {226return m_VPInstruction<VPInstruction::ActiveLaneMask>(Op0, Op1);227}228229template <typename Op0_t, typename Op1_t>230inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::BranchOnCount>231m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1) {232return m_VPInstruction<VPInstruction::BranchOnCount>(Op0, Op1);233}234235template <unsigned Opcode, typename Op0_t>236inline AllUnaryRecipe_match<Op0_t, Opcode> m_Unary(const Op0_t &Op0) {237return AllUnaryRecipe_match<Op0_t, Opcode>(Op0);238}239240template <typename Op0_t>241inline AllUnaryRecipe_match<Op0_t, Instruction::Trunc>242m_Trunc(const Op0_t &Op0) {243return m_Unary<Instruction::Trunc, Op0_t>(Op0);244}245246template <typename Op0_t>247inline AllUnaryRecipe_match<Op0_t, Instruction::ZExt> m_ZExt(const Op0_t &Op0) {248return m_Unary<Instruction::ZExt, Op0_t>(Op0);249}250251template <typename Op0_t>252inline AllUnaryRecipe_match<Op0_t, Instruction::SExt> m_SExt(const Op0_t &Op0) {253return m_Unary<Instruction::SExt, Op0_t>(Op0);254}255256template <typename Op0_t>257inline match_combine_or<AllUnaryRecipe_match<Op0_t, Instruction::ZExt>,258AllUnaryRecipe_match<Op0_t, Instruction::SExt>>259m_ZExtOrSExt(const Op0_t &Op0) {260return m_CombineOr(m_ZExt(Op0), m_SExt(Op0));261}262263template <unsigned Opcode, typename Op0_t, typename Op1_t,264bool Commutative = false>265inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>266m_Binary(const Op0_t &Op0, const Op1_t &Op1) {267return AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>(Op0, Op1);268}269270template <typename Op0_t, typename Op1_t>271inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul>272m_Mul(const Op0_t &Op0, const Op1_t &Op1) {273return m_Binary<Instruction::Mul, Op0_t, Op1_t>(Op0, Op1);274}275276template <typename Op0_t, typename Op1_t>277inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul,278/* Commutative =*/true>279m_c_Mul(const Op0_t &Op0, const Op1_t &Op1) {280return m_Binary<Instruction::Mul, Op0_t, Op1_t, true>(Op0, Op1);281}282283/// Match a binary OR operation. Note that while conceptually the operands can284/// be matched commutatively, \p Commutative defaults to false in line with the285/// IR-based pattern matching infrastructure. Use m_c_BinaryOr for a commutative286/// version of the matcher.287template <typename Op0_t, typename Op1_t, bool Commutative = false>288inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or, Commutative>289m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {290return m_Binary<Instruction::Or, Op0_t, Op1_t, Commutative>(Op0, Op1);291}292293template <typename Op0_t, typename Op1_t>294inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or,295/*Commutative*/ true>296m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {297return m_BinaryOr<Op0_t, Op1_t, /*Commutative*/ true>(Op0, Op1);298}299300template <typename Op0_t, typename Op1_t>301inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::LogicalAnd>302m_LogicalAnd(const Op0_t &Op0, const Op1_t &Op1) {303return m_VPInstruction<VPInstruction::LogicalAnd, Op0_t, Op1_t>(Op0, Op1);304}305306struct VPCanonicalIVPHI_match {307bool match(const VPValue *V) {308auto *DefR = V->getDefiningRecipe();309return DefR && match(DefR);310}311312bool match(const VPRecipeBase *R) { return isa<VPCanonicalIVPHIRecipe>(R); }313};314315inline VPCanonicalIVPHI_match m_CanonicalIV() {316return VPCanonicalIVPHI_match();317}318319template <typename Op0_t, typename Op1_t> struct VPScalarIVSteps_match {320Op0_t Op0;321Op1_t Op1;322323VPScalarIVSteps_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {}324325bool match(const VPValue *V) {326auto *DefR = V->getDefiningRecipe();327return DefR && match(DefR);328}329330bool match(const VPRecipeBase *R) {331if (!isa<VPScalarIVStepsRecipe>(R))332return false;333assert(R->getNumOperands() == 2 &&334"VPScalarIVSteps must have exactly 2 operands");335return Op0.match(R->getOperand(0)) && Op1.match(R->getOperand(1));336}337};338339template <typename Op0_t, typename Op1_t>340inline VPScalarIVSteps_match<Op0_t, Op1_t> m_ScalarIVSteps(const Op0_t &Op0,341const Op1_t &Op1) {342return VPScalarIVSteps_match<Op0_t, Op1_t>(Op0, Op1);343}344345} // namespace VPlanPatternMatch346} // namespace llvm347348#endif349350351