Skip to content

Commit 2435dcd

Browse files
authored
[VPlan] Add initial pattern match implementation for VPInstruction. (#80563)
Add an initial version of a pattern match for VPValues and recipes, starting with VPInstruction. PR: #80563
1 parent 5105f15 commit 2435dcd

File tree

3 files changed

+148
-20
lines changed

3 files changed

+148
-20
lines changed

llvm/lib/Transforms/Vectorize/VPlan.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "VPlan.h"
2020
#include "VPlanCFG.h"
2121
#include "VPlanDominatorTree.h"
22+
#include "VPlanPatternMatch.h"
2223
#include "llvm/ADT/PostOrderIterator.h"
2324
#include "llvm/ADT/STLExtras.h"
2425
#include "llvm/ADT/SmallVector.h"
@@ -46,6 +47,7 @@
4647
#include <vector>
4748

4849
using namespace llvm;
50+
using namespace llvm::VPlanPatternMatch;
4951

5052
namespace llvm {
5153
extern cl::opt<bool> EnableVPlanNativePath;
@@ -569,11 +571,9 @@ static bool hasConditionalTerminator(const VPBasicBlock *VPBB) {
569571
}
570572

571573
const VPRecipeBase *R = &VPBB->back();
572-
auto *VPI = dyn_cast<VPInstruction>(R);
573-
bool IsCondBranch =
574-
isa<VPBranchOnMaskRecipe>(R) ||
575-
(VPI && (VPI->getOpcode() == VPInstruction::BranchOnCond ||
576-
VPI->getOpcode() == VPInstruction::BranchOnCount));
574+
bool IsCondBranch = isa<VPBranchOnMaskRecipe>(R) ||
575+
match(R, m_BranchOnCond(m_VPValue())) ||
576+
match(R, m_BranchOnCount(m_VPValue(), m_VPValue()));
577577
(void)IsCondBranch;
578578

579579
if (VPBB->getNumSuccessors() >= 2 ||
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
//===- VPlanPatternMatch.h - Match on VPValues and recipes ------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file provides a simple and efficient mechanism for performing general
10+
// tree-based pattern matches on the VPlan values and recipes, based on
11+
// LLVM's IR pattern matchers.
12+
//
13+
// Currently it provides generic matchers for unary and binary VPInstructions,
14+
// and specialized matchers like m_Not, m_ActiveLaneMask, m_BranchOnCond,
15+
// m_BranchOnCount to match specific VPInstructions.
16+
// TODO: Add missing matchers for additional opcodes and recipes as needed.
17+
//
18+
//===----------------------------------------------------------------------===//
19+
20+
#ifndef LLVM_TRANSFORM_VECTORIZE_VPLANPATTERNMATCH_H
21+
#define LLVM_TRANSFORM_VECTORIZE_VPLANPATTERNMATCH_H
22+
23+
#include "VPlan.h"
24+
25+
namespace llvm {
26+
namespace VPlanPatternMatch {
27+
28+
template <typename Val, typename Pattern> bool match(Val *V, const Pattern &P) {
29+
return const_cast<Pattern &>(P).match(V);
30+
}
31+
32+
template <typename Class> struct class_match {
33+
template <typename ITy> bool match(ITy *V) { return isa<Class>(V); }
34+
};
35+
36+
/// Match an arbitrary VPValue and ignore it.
37+
inline class_match<VPValue> m_VPValue() { return class_match<VPValue>(); }
38+
39+
template <typename Class> struct bind_ty {
40+
Class *&VR;
41+
42+
bind_ty(Class *&V) : VR(V) {}
43+
44+
template <typename ITy> bool match(ITy *V) {
45+
if (auto *CV = dyn_cast<Class>(V)) {
46+
VR = CV;
47+
return true;
48+
}
49+
return false;
50+
}
51+
};
52+
53+
/// Match a VPValue, capturing it if we match.
54+
inline bind_ty<VPValue> m_VPValue(VPValue *&V) { return V; }
55+
56+
template <typename Op0_t, unsigned Opcode> struct UnaryVPInstruction_match {
57+
Op0_t Op0;
58+
59+
UnaryVPInstruction_match(Op0_t Op0) : Op0(Op0) {}
60+
61+
bool match(const VPValue *V) {
62+
auto *DefR = V->getDefiningRecipe();
63+
return DefR && match(DefR);
64+
}
65+
66+
bool match(const VPRecipeBase *R) {
67+
auto *DefR = dyn_cast<VPInstruction>(R);
68+
if (!DefR || DefR->getOpcode() != Opcode)
69+
return false;
70+
assert(DefR->getNumOperands() == 1 &&
71+
"recipe with matched opcode does not have 1 operands");
72+
return Op0.match(DefR->getOperand(0));
73+
}
74+
};
75+
76+
template <typename Op0_t, typename Op1_t, unsigned Opcode>
77+
struct BinaryVPInstruction_match {
78+
Op0_t Op0;
79+
Op1_t Op1;
80+
81+
BinaryVPInstruction_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {}
82+
83+
bool match(const VPValue *V) {
84+
auto *DefR = V->getDefiningRecipe();
85+
return DefR && match(DefR);
86+
}
87+
88+
bool match(const VPRecipeBase *R) {
89+
auto *DefR = dyn_cast<VPInstruction>(R);
90+
if (!DefR || DefR->getOpcode() != Opcode)
91+
return false;
92+
assert(DefR->getNumOperands() == 2 &&
93+
"recipe with matched opcode does not have 2 operands");
94+
return Op0.match(DefR->getOperand(0)) && Op1.match(DefR->getOperand(1));
95+
}
96+
};
97+
98+
template <unsigned Opcode, typename Op0_t>
99+
inline UnaryVPInstruction_match<Op0_t, Opcode>
100+
m_VPInstruction(const Op0_t &Op0) {
101+
return UnaryVPInstruction_match<Op0_t, Opcode>(Op0);
102+
}
103+
104+
template <unsigned Opcode, typename Op0_t, typename Op1_t>
105+
inline BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>
106+
m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1) {
107+
return BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>(Op0, Op1);
108+
}
109+
110+
template <typename Op0_t>
111+
inline UnaryVPInstruction_match<Op0_t, VPInstruction::Not>
112+
m_Not(const Op0_t &Op0) {
113+
return m_VPInstruction<VPInstruction::Not>(Op0);
114+
}
115+
116+
template <typename Op0_t>
117+
inline UnaryVPInstruction_match<Op0_t, VPInstruction::BranchOnCond>
118+
m_BranchOnCond(const Op0_t &Op0) {
119+
return m_VPInstruction<VPInstruction::BranchOnCond>(Op0);
120+
}
121+
122+
template <typename Op0_t, typename Op1_t>
123+
inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::ActiveLaneMask>
124+
m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1) {
125+
return m_VPInstruction<VPInstruction::ActiveLaneMask>(Op0, Op1);
126+
}
127+
128+
template <typename Op0_t, typename Op1_t>
129+
inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::BranchOnCount>
130+
m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1) {
131+
return m_VPInstruction<VPInstruction::BranchOnCount>(Op0, Op1);
132+
}
133+
} // namespace VPlanPatternMatch
134+
} // namespace llvm
135+
136+
#endif

llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "VPlanAnalysis.h"
1717
#include "VPlanCFG.h"
1818
#include "VPlanDominatorTree.h"
19+
#include "VPlanPatternMatch.h"
1920
#include "llvm/ADT/PostOrderIterator.h"
2021
#include "llvm/ADT/STLExtras.h"
2122
#include "llvm/ADT/SetVector.h"
@@ -26,8 +27,6 @@
2627

2728
using namespace llvm;
2829

29-
using namespace llvm::PatternMatch;
30-
3130
void VPlanTransforms::VPInstructionsToVPRecipes(
3231
VPlanPtr &Plan,
3332
function_ref<const InductionDescriptor *(PHINode *)>
@@ -486,6 +485,7 @@ static void removeDeadRecipes(VPlan &Plan) {
486485
[](VPValue *V) { return V->getNumUsers(); }))
487486
continue;
488487

488+
using namespace llvm::PatternMatch;
489489
// Having side effects keeps R alive, but do remove conditional assume
490490
// instructions as their conditions may be flattened.
491491
auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
@@ -595,31 +595,23 @@ static void removeRedundantExpandSCEVRecipes(VPlan &Plan) {
595595
}
596596
}
597597

598-
static bool canSimplifyBranchOnCond(VPInstruction *Term) {
599-
VPInstruction *Not = dyn_cast<VPInstruction>(Term->getOperand(0));
600-
if (!Not || Not->getOpcode() != VPInstruction::Not)
601-
return false;
602-
603-
VPInstruction *ALM = dyn_cast<VPInstruction>(Not->getOperand(0));
604-
return ALM && ALM->getOpcode() == VPInstruction::ActiveLaneMask;
605-
}
606-
607598
void VPlanTransforms::optimizeForVFAndUF(VPlan &Plan, ElementCount BestVF,
608599
unsigned BestUF,
609600
PredicatedScalarEvolution &PSE) {
610601
assert(Plan.hasVF(BestVF) && "BestVF is not available in Plan");
611602
assert(Plan.hasUF(BestUF) && "BestUF is not available in Plan");
612603
VPBasicBlock *ExitingVPBB =
613604
Plan.getVectorLoopRegion()->getExitingBasicBlock();
614-
auto *Term = dyn_cast<VPInstruction>(&ExitingVPBB->back());
605+
auto *Term = &ExitingVPBB->back();
615606
// Try to simplify the branch condition if TC <= VF * UF when preparing to
616607
// execute the plan for the main vector loop. We only do this if the
617608
// terminator is:
618609
// 1. BranchOnCount, or
619610
// 2. BranchOnCond where the input is Not(ActiveLaneMask).
620-
if (!Term || (Term->getOpcode() != VPInstruction::BranchOnCount &&
621-
(Term->getOpcode() != VPInstruction::BranchOnCond ||
622-
!canSimplifyBranchOnCond(Term))))
611+
using namespace llvm::VPlanPatternMatch;
612+
if (!match(Term, m_BranchOnCount(m_VPValue(), m_VPValue())) &&
613+
!match(Term,
614+
m_BranchOnCond(m_Not(m_ActiveLaneMask(m_VPValue(), m_VPValue())))))
623615
return;
624616

625617
Type *IdxTy =

0 commit comments

Comments
 (0)