Skip to content

Commit af06835

Browse files
authored
[VPlan] Use parameter packs to avoid unary/binary/ternary matchers. NFC (#152272)
Instead of defining unary/binary/ternary/4ary overloads of each matcher, we can use parameter packs to support arbitrary numbers of operands. This allows us to remove the explicit N-ary definitions for each matcher. We need to rewrite Recipe_match's constructor to use a parameter pack too, otherwise we end up with ambiguous overloads.
1 parent a73403b commit af06835

File tree

1 file changed

+64
-143
lines changed

1 file changed

+64
-143
lines changed

llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h

Lines changed: 64 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -200,15 +200,11 @@ template <typename Ops_t, unsigned Opcode, bool Commutative,
200200
struct Recipe_match {
201201
Ops_t Ops;
202202

203-
Recipe_match() : Ops() {
204-
static_assert(std::tuple_size<Ops_t>::value == 0 &&
205-
"constructor can only be used with zero operands");
206-
}
207-
Recipe_match(Ops_t Ops) : Ops(Ops) {}
208-
template <typename A_t, typename B_t>
209-
Recipe_match(A_t A, B_t B) : Ops({A, B}) {
210-
static_assert(std::tuple_size<Ops_t>::value == 2 &&
211-
"constructor can only be used for binary matcher");
203+
template <typename... OpTy> Recipe_match(OpTy... Ops) : Ops(Ops...) {
204+
static_assert(std::tuple_size<Ops_t>::value == sizeof...(Ops) &&
205+
"number of operands in constructor doesn't match Ops_t");
206+
static_assert((!Commutative || std::tuple_size<Ops_t>::value == 2) &&
207+
"only binary ops can be commutative");
212208
}
213209

214210
bool match(const VPValue *V) const {
@@ -254,7 +250,6 @@ struct Recipe_match {
254250
// Check for recipes that do not have opcodes.
255251
if constexpr (std::is_same<RecipeTy, VPScalarIVStepsRecipe>::value ||
256252
std::is_same<RecipeTy, VPCanonicalIVPHIRecipe>::value ||
257-
std::is_same<RecipeTy, VPWidenSelectRecipe>::value ||
258253
std::is_same<RecipeTy, VPDerivedIVRecipe>::value ||
259254
std::is_same<RecipeTy, VPWidenGEPRecipe>::value)
260255
return DefR;
@@ -270,195 +265,128 @@ struct Recipe_match {
270265
}
271266
};
272267

273-
template <unsigned Opcode, typename... RecipeTys>
274-
using ZeroOpRecipe_match =
275-
Recipe_match<std::tuple<>, Opcode, false, RecipeTys...>;
276-
277-
template <typename Op0_t, unsigned Opcode, typename... RecipeTys>
278-
using UnaryRecipe_match =
279-
Recipe_match<std::tuple<Op0_t>, Opcode, false, RecipeTys...>;
280-
281-
template <typename Op0_t, unsigned Opcode>
282-
using UnaryVPInstruction_match =
283-
UnaryRecipe_match<Op0_t, Opcode, VPInstruction>;
268+
template <unsigned Opcode, typename... OpTys>
269+
using AllRecipe_match =
270+
Recipe_match<std::tuple<OpTys...>, Opcode, /*Commutative*/ false,
271+
VPWidenRecipe, VPReplicateRecipe, VPWidenCastRecipe,
272+
VPInstruction, VPWidenSelectRecipe>;
284273

285-
template <unsigned Opcode>
286-
using ZeroOpVPInstruction_match = ZeroOpRecipe_match<Opcode, VPInstruction>;
274+
template <unsigned Opcode, typename... OpTys>
275+
using AllRecipe_commutative_match =
276+
Recipe_match<std::tuple<OpTys...>, Opcode, /*Commutative*/ true,
277+
VPWidenRecipe, VPReplicateRecipe, VPInstruction>;
287278

288-
template <typename Op0_t, unsigned Opcode>
289-
using AllUnaryRecipe_match =
290-
UnaryRecipe_match<Op0_t, Opcode, VPWidenRecipe, VPReplicateRecipe,
291-
VPWidenCastRecipe, VPInstruction>;
279+
template <unsigned Opcode, typename... OpTys>
280+
using VPInstruction_match = Recipe_match<std::tuple<OpTys...>, Opcode,
281+
/*Commutative*/ false, VPInstruction>;
292282

293-
template <typename Op0_t, typename Op1_t, unsigned Opcode, bool Commutative,
294-
typename... RecipeTys>
295-
using BinaryRecipe_match =
296-
Recipe_match<std::tuple<Op0_t, Op1_t>, Opcode, Commutative, RecipeTys...>;
297-
298-
template <typename Op0_t, typename Op1_t, unsigned Opcode>
299-
using BinaryVPInstruction_match =
300-
BinaryRecipe_match<Op0_t, Op1_t, Opcode, /*Commutative*/ false,
301-
VPInstruction>;
302-
303-
template <typename Op0_t, typename Op1_t, typename Op2_t, unsigned Opcode,
304-
bool Commutative, typename... RecipeTys>
305-
using TernaryRecipe_match = Recipe_match<std::tuple<Op0_t, Op1_t, Op2_t>,
306-
Opcode, Commutative, RecipeTys...>;
307-
308-
template <typename Op0_t, typename Op1_t, typename Op2_t, unsigned Opcode>
309-
using TernaryVPInstruction_match =
310-
TernaryRecipe_match<Op0_t, Op1_t, Op2_t, Opcode, /*Commutative*/ false,
311-
VPInstruction>;
312-
313-
template <typename Op0_t, typename Op1_t, unsigned Opcode,
314-
bool Commutative = false>
315-
using AllBinaryRecipe_match =
316-
BinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative, VPWidenRecipe,
317-
VPReplicateRecipe, VPWidenCastRecipe, VPInstruction>;
283+
template <unsigned Opcode, typename... OpTys>
284+
inline VPInstruction_match<Opcode, OpTys...>
285+
m_VPInstruction(const OpTys &...Ops) {
286+
return VPInstruction_match<Opcode, OpTys...>(Ops...);
287+
}
318288

319289
/// BuildVector is matches only its opcode, w/o matching its operands as the
320290
/// number of operands is not fixed.
321-
inline ZeroOpVPInstruction_match<VPInstruction::BuildVector> m_BuildVector() {
322-
return ZeroOpVPInstruction_match<VPInstruction::BuildVector>();
323-
}
324-
325-
template <unsigned Opcode, typename Op0_t>
326-
inline UnaryVPInstruction_match<Op0_t, Opcode>
327-
m_VPInstruction(const Op0_t &Op0) {
328-
return UnaryVPInstruction_match<Op0_t, Opcode>(Op0);
329-
}
330-
331-
template <unsigned Opcode, typename Op0_t, typename Op1_t>
332-
inline BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>
333-
m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1) {
334-
return BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>(Op0, Op1);
291+
inline VPInstruction_match<VPInstruction::BuildVector> m_BuildVector() {
292+
return m_VPInstruction<VPInstruction::BuildVector>();
335293
}
336294

337-
template <unsigned Opcode, typename Op0_t, typename Op1_t, typename Op2_t>
338-
inline TernaryVPInstruction_match<Op0_t, Op1_t, Op2_t, Opcode>
339-
m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2) {
340-
return TernaryVPInstruction_match<Op0_t, Op1_t, Op2_t, Opcode>(
341-
{Op0, Op1, Op2});
342-
}
343-
344-
template <typename Op0_t, typename Op1_t, typename Op2_t, typename Op3_t,
345-
unsigned Opcode, bool Commutative, typename... RecipeTys>
346-
using Recipe4Op_match = Recipe_match<std::tuple<Op0_t, Op1_t, Op2_t, Op3_t>,
347-
Opcode, Commutative, RecipeTys...>;
348-
349-
template <typename Op0_t, typename Op1_t, typename Op2_t, typename Op3_t,
350-
unsigned Opcode>
351-
using VPInstruction4Op_match =
352-
Recipe4Op_match<Op0_t, Op1_t, Op2_t, Op3_t, Opcode, /*Commutative*/ false,
353-
VPInstruction>;
354-
355-
template <unsigned Opcode, typename Op0_t, typename Op1_t, typename Op2_t,
356-
typename Op3_t>
357-
inline VPInstruction4Op_match<Op0_t, Op1_t, Op2_t, Op3_t, Opcode>
358-
m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2,
359-
const Op3_t &Op3) {
360-
return VPInstruction4Op_match<Op0_t, Op1_t, Op2_t, Op3_t, Opcode>(
361-
{Op0, Op1, Op2, Op3});
362-
}
363295
template <typename Op0_t>
364-
inline UnaryVPInstruction_match<Op0_t, Instruction::Freeze>
296+
inline VPInstruction_match<Instruction::Freeze, Op0_t>
365297
m_Freeze(const Op0_t &Op0) {
366298
return m_VPInstruction<Instruction::Freeze>(Op0);
367299
}
368300

369301
template <typename Op0_t>
370-
inline UnaryVPInstruction_match<Op0_t, VPInstruction::BranchOnCond>
302+
inline VPInstruction_match<VPInstruction::BranchOnCond, Op0_t>
371303
m_BranchOnCond(const Op0_t &Op0) {
372304
return m_VPInstruction<VPInstruction::BranchOnCond>(Op0);
373305
}
374306

375307
template <typename Op0_t>
376-
inline UnaryVPInstruction_match<Op0_t, VPInstruction::Broadcast>
308+
inline VPInstruction_match<VPInstruction::Broadcast, Op0_t>
377309
m_Broadcast(const Op0_t &Op0) {
378310
return m_VPInstruction<VPInstruction::Broadcast>(Op0);
379311
}
380312

381313
template <typename Op0_t, typename Op1_t>
382-
inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::ActiveLaneMask>
314+
inline VPInstruction_match<VPInstruction::ActiveLaneMask, Op0_t, Op1_t>
383315
m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1) {
384316
return m_VPInstruction<VPInstruction::ActiveLaneMask>(Op0, Op1);
385317
}
386318

387319
template <typename Op0_t, typename Op1_t>
388-
inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::BranchOnCount>
320+
inline VPInstruction_match<VPInstruction::BranchOnCount, Op0_t, Op1_t>
389321
m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1) {
390322
return m_VPInstruction<VPInstruction::BranchOnCount>(Op0, Op1);
391323
}
392324

393325
template <unsigned Opcode, typename Op0_t>
394-
inline AllUnaryRecipe_match<Op0_t, Opcode> m_Unary(const Op0_t &Op0) {
395-
return AllUnaryRecipe_match<Op0_t, Opcode>(Op0);
326+
inline AllRecipe_match<Opcode, Op0_t> m_Unary(const Op0_t &Op0) {
327+
return AllRecipe_match<Opcode, Op0_t>(Op0);
396328
}
397329

398330
template <typename Op0_t>
399-
inline AllUnaryRecipe_match<Op0_t, Instruction::Trunc>
400-
m_Trunc(const Op0_t &Op0) {
331+
inline AllRecipe_match<Instruction::Trunc, Op0_t> m_Trunc(const Op0_t &Op0) {
401332
return m_Unary<Instruction::Trunc, Op0_t>(Op0);
402333
}
403334

404335
template <typename Op0_t>
405-
inline AllUnaryRecipe_match<Op0_t, Instruction::ZExt> m_ZExt(const Op0_t &Op0) {
336+
inline AllRecipe_match<Instruction::ZExt, Op0_t> m_ZExt(const Op0_t &Op0) {
406337
return m_Unary<Instruction::ZExt, Op0_t>(Op0);
407338
}
408339

409340
template <typename Op0_t>
410-
inline AllUnaryRecipe_match<Op0_t, Instruction::SExt> m_SExt(const Op0_t &Op0) {
341+
inline AllRecipe_match<Instruction::SExt, Op0_t> m_SExt(const Op0_t &Op0) {
411342
return m_Unary<Instruction::SExt, Op0_t>(Op0);
412343
}
413344

414345
template <typename Op0_t>
415-
inline match_combine_or<AllUnaryRecipe_match<Op0_t, Instruction::ZExt>,
416-
AllUnaryRecipe_match<Op0_t, Instruction::SExt>>
346+
inline match_combine_or<AllRecipe_match<Instruction::ZExt, Op0_t>,
347+
AllRecipe_match<Instruction::SExt, Op0_t>>
417348
m_ZExtOrSExt(const Op0_t &Op0) {
418349
return m_CombineOr(m_ZExt(Op0), m_SExt(Op0));
419350
}
420351

421-
template <unsigned Opcode, typename Op0_t, typename Op1_t,
422-
bool Commutative = false>
423-
inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>
424-
m_Binary(const Op0_t &Op0, const Op1_t &Op1) {
425-
return AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>(Op0, Op1);
352+
template <unsigned Opcode, typename Op0_t, typename Op1_t>
353+
inline AllRecipe_match<Opcode, Op0_t, Op1_t> m_Binary(const Op0_t &Op0,
354+
const Op1_t &Op1) {
355+
return AllRecipe_match<Opcode, Op0_t, Op1_t>(Op0, Op1);
426356
}
427357

428358
template <unsigned Opcode, typename Op0_t, typename Op1_t>
429-
inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, true>
359+
inline AllRecipe_commutative_match<Opcode, Op0_t, Op1_t>
430360
m_c_Binary(const Op0_t &Op0, const Op1_t &Op1) {
431-
return AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, true>(Op0, Op1);
361+
return AllRecipe_commutative_match<Opcode, Op0_t, Op1_t>(Op0, Op1);
432362
}
433363

434364
template <typename Op0_t, typename Op1_t>
435-
inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul>
436-
m_Mul(const Op0_t &Op0, const Op1_t &Op1) {
365+
inline AllRecipe_match<Instruction::Mul, Op0_t, Op1_t> m_Mul(const Op0_t &Op0,
366+
const Op1_t &Op1) {
437367
return m_Binary<Instruction::Mul, Op0_t, Op1_t>(Op0, Op1);
438368
}
439369

440370
template <typename Op0_t, typename Op1_t>
441-
inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul,
442-
/* Commutative =*/true>
371+
inline AllRecipe_commutative_match<Instruction::Mul, Op0_t, Op1_t>
443372
m_c_Mul(const Op0_t &Op0, const Op1_t &Op1) {
444-
return m_Binary<Instruction::Mul, Op0_t, Op1_t, true>(Op0, Op1);
373+
return m_c_Binary<Instruction::Mul, Op0_t, Op1_t>(Op0, Op1);
445374
}
446375

447376
/// Match a binary OR operation. Note that while conceptually the operands can
448377
/// be matched commutatively, \p Commutative defaults to false in line with the
449378
/// IR-based pattern matching infrastructure. Use m_c_BinaryOr for a commutative
450379
/// version of the matcher.
451-
template <typename Op0_t, typename Op1_t, bool Commutative = false>
452-
inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or, Commutative>
380+
template <typename Op0_t, typename Op1_t>
381+
inline AllRecipe_match<Instruction::Or, Op0_t, Op1_t>
453382
m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
454-
return m_Binary<Instruction::Or, Op0_t, Op1_t, Commutative>(Op0, Op1);
383+
return m_Binary<Instruction::Or, Op0_t, Op1_t>(Op0, Op1);
455384
}
456385

457386
template <typename Op0_t, typename Op1_t>
458-
inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or,
459-
/*Commutative*/ true>
387+
inline AllRecipe_commutative_match<Instruction::Or, Op0_t, Op1_t>
460388
m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
461-
return m_BinaryOr<Op0_t, Op1_t, /*Commutative*/ true>(Op0, Op1);
389+
return m_c_Binary<Instruction::Or, Op0_t, Op1_t>(Op0, Op1);
462390
}
463391

464392
/// ICmp_match is a variant of BinaryRecipe_match that also binds the comparison
@@ -523,58 +451,51 @@ m_SpecificICmp(CmpPredicate MatchPred, const Op0_t &Op0, const Op1_t &Op1) {
523451

524452
template <typename Op0_t, typename Op1_t>
525453
using GEPLikeRecipe_match =
526-
BinaryRecipe_match<Op0_t, Op1_t, Instruction::GetElementPtr, false,
527-
VPWidenRecipe, VPReplicateRecipe, VPWidenGEPRecipe,
528-
VPInstruction>;
454+
Recipe_match<std::tuple<Op0_t, Op1_t>, Instruction::GetElementPtr,
455+
/*Commutative*/ false, VPWidenRecipe, VPReplicateRecipe,
456+
VPWidenGEPRecipe, VPInstruction>;
529457

530458
template <typename Op0_t, typename Op1_t>
531459
inline GEPLikeRecipe_match<Op0_t, Op1_t> m_GetElementPtr(const Op0_t &Op0,
532460
const Op1_t &Op1) {
533461
return GEPLikeRecipe_match<Op0_t, Op1_t>(Op0, Op1);
534462
}
535463

536-
template <typename Op0_t, typename Op1_t, typename Op2_t, unsigned Opcode>
537-
using AllTernaryRecipe_match =
538-
Recipe_match<std::tuple<Op0_t, Op1_t, Op2_t>, Opcode, false,
539-
VPReplicateRecipe, VPInstruction, VPWidenSelectRecipe>;
540-
541464
template <typename Op0_t, typename Op1_t, typename Op2_t>
542-
inline AllTernaryRecipe_match<Op0_t, Op1_t, Op2_t, Instruction::Select>
465+
inline AllRecipe_match<Instruction::Select, Op0_t, Op1_t, Op2_t>
543466
m_Select(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2) {
544-
return AllTernaryRecipe_match<Op0_t, Op1_t, Op2_t, Instruction::Select>(
467+
return AllRecipe_match<Instruction::Select, Op0_t, Op1_t, Op2_t>(
545468
{Op0, Op1, Op2});
546469
}
547470

548471
template <typename Op0_t>
549-
inline match_combine_or<UnaryVPInstruction_match<Op0_t, VPInstruction::Not>,
550-
AllBinaryRecipe_match<int_pred_ty<is_all_ones>, Op0_t,
551-
Instruction::Xor, true>>
472+
inline match_combine_or<VPInstruction_match<VPInstruction::Not, Op0_t>,
473+
AllRecipe_commutative_match<
474+
Instruction::Xor, int_pred_ty<is_all_ones>, Op0_t>>
552475
m_Not(const Op0_t &Op0) {
553476
return m_CombineOr(m_VPInstruction<VPInstruction::Not>(Op0),
554477
m_c_Binary<Instruction::Xor>(m_AllOnes(), Op0));
555478
}
556479

557480
template <typename Op0_t, typename Op1_t>
558481
inline match_combine_or<
559-
BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::LogicalAnd>,
560-
AllTernaryRecipe_match<Op0_t, Op1_t, specific_intval<1>,
561-
Instruction::Select>>
482+
VPInstruction_match<VPInstruction::LogicalAnd, Op0_t, Op1_t>,
483+
AllRecipe_match<Instruction::Select, Op0_t, Op1_t, specific_intval<1>>>
562484
m_LogicalAnd(const Op0_t &Op0, const Op1_t &Op1) {
563485
return m_CombineOr(
564486
m_VPInstruction<VPInstruction::LogicalAnd, Op0_t, Op1_t>(Op0, Op1),
565487
m_Select(Op0, Op1, m_False()));
566488
}
567489

568490
template <typename Op0_t, typename Op1_t>
569-
inline AllTernaryRecipe_match<Op0_t, specific_intval<1>, Op1_t,
570-
Instruction::Select>
491+
inline AllRecipe_match<Instruction::Select, Op0_t, specific_intval<1>, Op1_t>
571492
m_LogicalOr(const Op0_t &Op0, const Op1_t &Op1) {
572493
return m_Select(Op0, m_True(), Op1);
573494
}
574495

575496
template <typename Op0_t, typename Op1_t, typename Op2_t>
576-
using VPScalarIVSteps_match =
577-
TernaryRecipe_match<Op0_t, Op1_t, Op2_t, 0, false, VPScalarIVStepsRecipe>;
497+
using VPScalarIVSteps_match = Recipe_match<std::tuple<Op0_t, Op1_t, Op2_t>, 0,
498+
false, VPScalarIVStepsRecipe>;
578499

579500
template <typename Op0_t, typename Op1_t, typename Op2_t>
580501
inline VPScalarIVSteps_match<Op0_t, Op1_t, Op2_t>

0 commit comments

Comments
 (0)