@@ -120,7 +120,12 @@ template <unsigned Opcode, typename RecipeTy>
120120struct 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+
160199template <typename Op0_t, unsigned Opcode>
161200using UnaryVPInstruction_match =
162201 UnaryRecipe_match<Op0_t, Opcode, VPInstruction>;
@@ -168,32 +207,8 @@ using AllUnaryRecipe_match =
168207
169208template <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
198213template <typename Op0_t, typename Op1_t, unsigned Opcode>
199214using 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
327334inline 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
351342template <typename Op0_t, typename Op1_t>
352343inline VPScalarIVSteps_match<Op0_t, Op1_t> m_ScalarIVSteps (const Op0_t &Op0,
0 commit comments