Skip to content

Commit dac0f7e

Browse files
committed
[VPlan] Add general recipe matcher, replace handwritten ones (NFC)
The new matcher is more flexible and can be used to build matchers for additional recipe types without unnecessary duplication.
1 parent 31dd03c commit dac0f7e

File tree

1 file changed

+54
-63
lines changed

1 file changed

+54
-63
lines changed

llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h

Lines changed: 54 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,12 @@ template <unsigned Opcode, typename RecipeTy>
120120
struct MatchRecipeAndOpcode<Opcode, RecipeTy> {
121121
static bool match(const VPRecipeBase *R) {
122122
auto *DefR = dyn_cast<RecipeTy>(R);
123-
return DefR && DefR->getOpcode() == Opcode;
123+
// Check for recipes that do not have opcodes.
124+
if constexpr (std::is_same<RecipeTy, VPScalarIVStepsRecipe>::value ||
125+
std::is_same<RecipeTy, VPCanonicalIVPHIRecipe>::value)
126+
return DefR;
127+
else
128+
return DefR && DefR->getOpcode() == Opcode;
124129
}
125130
};
126131

@@ -131,13 +136,34 @@ struct MatchRecipeAndOpcode<Opcode, RecipeTy, RecipeTys...> {
131136
MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R);
132137
}
133138
};
139+
template <typename TupleTy, typename Fn, std::size_t... Is>
140+
bool CheckTupleElements(const TupleTy &Ops, Fn P, std::index_sequence<Is...>) {
141+
return (P(std::get<Is>(Ops), Is) && ...);
142+
}
143+
144+
/// Helper to check if predicate \p P holds on all tuple elements in \p Ops
145+
template <typename TupleTy, typename Fn>
146+
bool all_of_tuple_elements(const TupleTy &Ops, Fn P) {
147+
return CheckTupleElements(
148+
Ops, P, std::make_index_sequence<std::tuple_size<TupleTy>::value>{});
149+
}
134150
} // namespace detail
135151

136-
template <typename Op0_t, unsigned Opcode, typename... RecipeTys>
137-
struct UnaryRecipe_match {
138-
Op0_t Op0;
152+
template <typename Ops_t, unsigned Opcode, bool Commutative,
153+
typename... RecipeTys>
154+
struct Recipe_match {
155+
Ops_t Ops;
139156

140-
UnaryRecipe_match(Op0_t Op0) : Op0(Op0) {}
157+
Recipe_match() : Ops() {
158+
static_assert(std::tuple_size<Ops_t>::value == 0 &&
159+
"constructor can only be used with zero operands");
160+
}
161+
Recipe_match(Ops_t Ops) : Ops(Ops) {}
162+
template <typename A_t, typename B_t>
163+
Recipe_match(A_t A, B_t B) : Ops({A, B}) {
164+
static_assert(std::tuple_size<Ops_t>::value == 2 &&
165+
"constructor can only be used for binary matcher");
166+
}
141167

142168
bool match(const VPValue *V) const {
143169
auto *DefR = V->getDefiningRecipe();
@@ -151,12 +177,25 @@ struct UnaryRecipe_match {
151177
bool match(const VPRecipeBase *R) const {
152178
if (!detail::MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R))
153179
return false;
154-
assert(R->getNumOperands() == 1 &&
155-
"recipe with matched opcode does not have 1 operands");
156-
return Op0.match(R->getOperand(0));
180+
assert(R->getNumOperands() == std::tuple_size<Ops_t>::value &&
181+
"recipe with matched opcode the expected number of operands");
182+
183+
if (detail::all_of_tuple_elements(Ops, [R](auto Op, unsigned Idx) {
184+
return Op.match(R->getOperand(Idx));
185+
}))
186+
return true;
187+
188+
return Commutative &&
189+
detail::all_of_tuple_elements(Ops, [R](auto Op, unsigned Idx) {
190+
return Op.match(R->getOperand(R->getNumOperands() - Idx - 1));
191+
});
157192
}
158193
};
159194

195+
template <typename Op0_t, unsigned Opcode, typename... RecipeTys>
196+
using UnaryRecipe_match =
197+
Recipe_match<std::tuple<Op0_t>, Opcode, false, RecipeTys...>;
198+
160199
template <typename Op0_t, unsigned Opcode>
161200
using UnaryVPInstruction_match =
162201
UnaryRecipe_match<Op0_t, Opcode, VPInstruction>;
@@ -168,32 +207,8 @@ using AllUnaryRecipe_match =
168207

169208
template <typename Op0_t, typename Op1_t, unsigned Opcode, bool Commutative,
170209
typename... RecipeTys>
171-
struct BinaryRecipe_match {
172-
Op0_t Op0;
173-
Op1_t Op1;
174-
175-
BinaryRecipe_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {}
176-
177-
bool match(const VPValue *V) const {
178-
auto *DefR = V->getDefiningRecipe();
179-
return DefR && match(DefR);
180-
}
181-
182-
bool match(const VPSingleDefRecipe *R) const {
183-
return match(static_cast<const VPRecipeBase *>(R));
184-
}
185-
186-
bool match(const VPRecipeBase *R) const {
187-
if (!detail::MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R))
188-
return false;
189-
assert(R->getNumOperands() == 2 &&
190-
"recipe with matched opcode does not have 2 operands");
191-
if (Op0.match(R->getOperand(0)) && Op1.match(R->getOperand(1)))
192-
return true;
193-
return Commutative && Op0.match(R->getOperand(1)) &&
194-
Op1.match(R->getOperand(0));
195-
}
196-
};
210+
using BinaryRecipe_match =
211+
Recipe_match<std::tuple<Op0_t, Op1_t>, Opcode, Commutative, RecipeTys...>;
197212

198213
template <typename Op0_t, typename Op1_t, unsigned Opcode>
199214
using BinaryVPInstruction_match =
@@ -313,40 +328,16 @@ m_LogicalAnd(const Op0_t &Op0, const Op1_t &Op1) {
313328
return m_VPInstruction<VPInstruction::LogicalAnd, Op0_t, Op1_t>(Op0, Op1);
314329
}
315330

316-
struct VPCanonicalIVPHI_match {
317-
bool match(const VPValue *V) const {
318-
auto *DefR = V->getDefiningRecipe();
319-
return DefR && match(DefR);
320-
}
321-
322-
bool match(const VPRecipeBase *R) const {
323-
return isa<VPCanonicalIVPHIRecipe>(R);
324-
}
325-
};
331+
using VPCanonicalIVPHI_match =
332+
Recipe_match<std::tuple<>, 0, false, VPCanonicalIVPHIRecipe>;
326333

327334
inline VPCanonicalIVPHI_match m_CanonicalIV() {
328335
return VPCanonicalIVPHI_match();
329336
}
330337

331-
template <typename Op0_t, typename Op1_t> struct VPScalarIVSteps_match {
332-
Op0_t Op0;
333-
Op1_t Op1;
334-
335-
VPScalarIVSteps_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {}
336-
337-
bool match(const VPValue *V) const {
338-
auto *DefR = V->getDefiningRecipe();
339-
return DefR && match(DefR);
340-
}
341-
342-
bool match(const VPRecipeBase *R) const {
343-
if (!isa<VPScalarIVStepsRecipe>(R))
344-
return false;
345-
assert(R->getNumOperands() == 2 &&
346-
"VPScalarIVSteps must have exactly 2 operands");
347-
return Op0.match(R->getOperand(0)) && Op1.match(R->getOperand(1));
348-
}
349-
};
338+
template <typename Op0_t, typename Op1_t>
339+
using VPScalarIVSteps_match =
340+
Recipe_match<std::tuple<Op0_t, Op1_t>, 0, false, VPScalarIVStepsRecipe>;
350341

351342
template <typename Op0_t, typename Op1_t>
352343
inline VPScalarIVSteps_match<Op0_t, Op1_t> m_ScalarIVSteps(const Op0_t &Op0,

0 commit comments

Comments
 (0)