@@ -49,6 +49,8 @@ using VectorParts = SmallVector<Value *, 2>;
49
49
50
50
bool VPRecipeBase::mayWriteToMemory () const {
51
51
switch (getVPDefID ()) {
52
+ case VPBundleSC:
53
+ return cast<VPBundleRecipe>(this )->mayReadOrWriteMemory ();
52
54
case VPInstructionSC:
53
55
return cast<VPInstruction>(this )->opcodeMayReadOrWriteFromMemory ();
54
56
case VPInterleaveSC:
@@ -97,6 +99,8 @@ bool VPRecipeBase::mayWriteToMemory() const {
97
99
98
100
bool VPRecipeBase::mayReadFromMemory () const {
99
101
switch (getVPDefID ()) {
102
+ case VPBundleSC:
103
+ return cast<VPBundleRecipe>(this )->mayReadOrWriteMemory ();
100
104
case VPInstructionSC:
101
105
return cast<VPInstruction>(this )->opcodeMayReadOrWriteFromMemory ();
102
106
case VPWidenLoadEVLSC:
@@ -143,6 +147,8 @@ bool VPRecipeBase::mayReadFromMemory() const {
143
147
144
148
bool VPRecipeBase::mayHaveSideEffects () const {
145
149
switch (getVPDefID ()) {
150
+ case VPBundleSC:
151
+ return cast<VPBundleRecipe>(this )->mayHaveSideEffects ();
146
152
case VPDerivedIVSC:
147
153
case VPFirstOrderRecurrencePHISC:
148
154
case VPPredInstPHISC:
@@ -2500,95 +2506,65 @@ InstructionCost VPReductionRecipe::computeCost(ElementCount VF,
2500
2506
Ctx.CostKind );
2501
2507
}
2502
2508
2503
- void VPBundleRecipe::bundle (ArrayRef<VPValue *> Operands) {
2509
+ VPBundleRecipe::VPBundleRecipe (BundleTypes BundleType,
2510
+ ArrayRef<VPSingleDefRecipe *> ToBundle)
2511
+ : VPSingleDefRecipe(VPDef::VPBundleSC, {}, {}),
2512
+ BundledRecipes(
2513
+ SetVector<VPSingleDefRecipe *>(ToBundle.begin(), ToBundle.end())
2514
+ .takeVector()),
2515
+ BundleType(BundleType) {
2504
2516
assert (!BundledRecipes.empty () && " Nothing to bundle?" );
2505
2517
2506
- // Bundle up the operand recipes.
2507
- SmallPtrSet<VPUser *, 4 > BundledUsers ;
2518
+ // Maintain a copy of the bundled recipes as a set of users .
2519
+ SmallPtrSet<VPUser *, 4 > BundledRecipesAsSetOfUsers ;
2508
2520
for (auto *R : BundledRecipes)
2509
- BundledUsers.insert (R);
2510
-
2511
- // Recipes in the bundle, except the last one, must only be used inside the
2512
- // bundle. If there other external users, clone the recipes for the bundle.
2513
- for (unsigned Idx = 0 ; Idx != BundledRecipes.size () - 1 ; ++Idx) {
2514
- VPSingleDefRecipe *R = BundledRecipes[Idx];
2515
- if (all_of (R->users (), [&BundledUsers](VPUser *U) {
2516
- return BundledUsers.contains (U);
2521
+ BundledRecipesAsSetOfUsers.insert (R);
2522
+
2523
+ // Recipes in the bundle, except the last one, must only be used by (other)
2524
+ // recipes inside the bundle. If there are other users, external to the
2525
+ // bundle, use a clone of the recipe for external users.
2526
+ for (VPSingleDefRecipe *R : BundledRecipes) {
2527
+ if (R != BundledRecipes.back () &&
2528
+ any_of (R->users (), [&BundledRecipesAsSetOfUsers](VPUser *U) {
2529
+ return !BundledRecipesAsSetOfUsers.contains (U);
2517
2530
})) {
2518
- if (R->getParent ())
2519
- R->removeFromParent ();
2520
- continue ;
2531
+ // There are users outside of the bundle. Clone the recipe and use the
2532
+ // clone those external users.
2533
+ VPSingleDefRecipe *CopyForExtUsers = R->clone ();
2534
+ R->replaceUsesWithIf (CopyForExtUsers,
2535
+ [&BundledRecipesAsSetOfUsers](VPUser &U, unsigned ) {
2536
+ return !BundledRecipesAsSetOfUsers.contains (&U);
2537
+ });
2538
+ CopyForExtUsers->insertBefore (R);
2521
2539
}
2522
- // The users external to the bundle. Clone the recipe for use in the
2523
- // bundle and update all its in-bundle users.
2524
- VPSingleDefRecipe *Copy = R->clone ();
2525
- BundledRecipes[Idx] = Copy;
2526
- BundledUsers.insert (Copy);
2527
- R->replaceUsesWithIf (Copy, [&BundledUsers](VPUser &U, unsigned ) {
2528
- return BundledUsers.contains (&U);
2529
- });
2530
- }
2531
- if (BundledRecipes.back ()->getParent ())
2532
- BundledRecipes.back ()->removeFromParent ();
2533
-
2534
- // Internalize all external operands to the bundled operations. To do so,
2535
- // create new temporary VPValues for all operands not defined by recipe in
2540
+ if (R->getParent ())
2541
+ R->removeFromParent ();
2542
+ }
2543
+
2544
+ // Internalize all external operands to the bundled recipes. To do so,
2545
+ // create new temporary VPValues for all operands defined by a recipe outside
2536
2546
// the bundle. The original operands are added as operands of the
2537
- // VPBundleRecipe.
2547
+ // VPBundleRecipe itself .
2538
2548
for (auto *R : BundledRecipes) {
2539
2549
for (const auto &[Idx, Op] : enumerate(R->operands ())) {
2540
2550
auto *Def = Op->getDefiningRecipe ();
2541
- if (Def && BundledUsers .contains (Def))
2551
+ if (Def && BundledRecipesAsSetOfUsers .contains (Def))
2542
2552
continue ;
2543
- if (Operands.empty ())
2544
- addOperand (Op);
2545
- else
2546
- addOperand (Operands[TmpValues.size ()]);
2547
- TmpValues.push_back (new VPValue ());
2548
- R->setOperand (Idx, TmpValues.back ());
2553
+ addOperand (Op);
2554
+ BundleLiveInPlaceholders.push_back (new VPValue ());
2555
+ R->setOperand (Idx, BundleLiveInPlaceholders.back ());
2549
2556
}
2550
2557
}
2551
2558
}
2552
2559
2553
2560
void VPBundleRecipe::unbundle () {
2554
2561
for (auto *R : BundledRecipes)
2555
- if (!R->getParent ())
2556
2562
R->insertBefore (this );
2557
2563
2558
2564
for (const auto &[Idx, Op] : enumerate(operands ()))
2559
- TmpValues [Idx]->replaceAllUsesWith (Op);
2565
+ BundleLiveInPlaceholders [Idx]->replaceAllUsesWith (Op);
2560
2566
2561
2567
replaceAllUsesWith (getResultRecipe ());
2562
-
2563
- if (BundleType == BundleTypes::MulAccumulateReduction &&
2564
- BundledRecipes.size () == 5 ) {
2565
- // Note that we will drop the extend after mul which transforms
2566
- // reduce.add(ext(mul(ext, ext))) to reduce.add(mul(ext, ext)).
2567
- // TODO: This transform should be done separately from bundling/unbundling.
2568
- auto *Ext0 = cast<VPWidenCastRecipe>(BundledRecipes[0 ]);
2569
- auto *Ext1 = cast<VPWidenCastRecipe>(BundledRecipes[1 ]);
2570
- auto *Ext2 = cast<VPWidenCastRecipe>(BundledRecipes[3 ]);
2571
- auto *Op0 =
2572
- new VPWidenCastRecipe (Ext0->getOpcode (), Ext0->getOperand (0 ),
2573
- Ext2->getResultType (), *Ext0, getDebugLoc ());
2574
- Op0->insertBefore (Ext0);
2575
-
2576
- VPSingleDefRecipe *Op1 = Op0;
2577
- if (Ext0 != Ext1) {
2578
- Op1 = new VPWidenCastRecipe (Ext1->getOpcode (), Ext1->getOperand (0 ),
2579
- Ext2->getResultType (), *Ext1, getDebugLoc ());
2580
- Op1->insertBefore (Ext1);
2581
- }
2582
- auto *Mul = cast<VPWidenRecipe>(BundledRecipes[2 ]);
2583
- auto *Red = cast<VPReductionRecipe>(BundledRecipes[4 ]);
2584
- Mul->setOperand (0 , Op0);
2585
- Mul->setOperand (1 , Op1);
2586
- Red->setOperand (1 , Mul);
2587
- Ext0->eraseFromParent ();
2588
- Ext2->eraseFromParent ();
2589
- if (Ext0 != Ext1)
2590
- Ext1->eraseFromParent ();
2591
- }
2592
2568
BundledRecipes.clear ();
2593
2569
}
2594
2570
@@ -2610,15 +2586,27 @@ InstructionCost VPBundleRecipe::computeCost(ElementCount VF,
2610
2586
RedTy, SrcVecTy, std::nullopt, Ctx.CostKind );
2611
2587
}
2612
2588
case BundleTypes::MulAccumulateReduction:
2589
+ return Ctx.TTI .getMulAccReductionCost (false , RedTy, SrcVecTy, Ctx.CostKind );
2590
+
2591
+ case BundleTypes::ExtMulAccumulateReduction:
2613
2592
return Ctx.TTI .getMulAccReductionCost (
2614
- BundledRecipes.size () > 2
2615
- ? cast<VPWidenCastRecipe>(BundledRecipes.front ())->getOpcode () ==
2616
- Instruction::ZExt
2617
- : false ,
2593
+ cast<VPWidenCastRecipe>(BundledRecipes.front ())->getOpcode () ==
2594
+ Instruction::ZExt,
2618
2595
RedTy, SrcVecTy, Ctx.CostKind );
2619
2596
}
2620
2597
}
2621
2598
2599
+ bool VPBundleRecipe::mayReadOrWriteMemory () const {
2600
+ return any_of (BundledRecipes, [](VPSingleDefRecipe *R) {
2601
+ return R->mayReadFromMemory () || R->mayWriteToMemory ();
2602
+ });
2603
+ }
2604
+
2605
+ bool VPBundleRecipe::mayHaveSideEffects () const {
2606
+ return any_of (BundledRecipes,
2607
+ [](VPSingleDefRecipe *R) { return R->mayHaveSideEffects (); });
2608
+ }
2609
+
2622
2610
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2623
2611
2624
2612
void VPBundleRecipe::print (raw_ostream &O, const Twine &Indent,
@@ -2647,33 +2635,32 @@ void VPBundleRecipe::print(raw_ostream &O, const Twine &Indent,
2647
2635
O << " )" ;
2648
2636
break ;
2649
2637
}
2650
- case BundleTypes::MulAccumulateReduction: {
2638
+ case BundleTypes::MulAccumulateReduction:
2639
+ case BundleTypes::ExtMulAccumulateReduction: {
2651
2640
getOperand (getNumOperands () - 1 )->printAsOperand (O, SlotTracker);
2652
2641
O << " + " ;
2653
2642
O << " reduce."
2654
2643
<< Instruction::getOpcodeName (
2655
2644
RecurrenceDescriptor::getOpcode (Red->getRecurrenceKind ()))
2656
2645
<< " (" ;
2657
2646
O << " mul" ;
2658
- auto *Mul = cast<VPWidenRecipe>(
2659
- BundledRecipes.size () == 2 ? BundledRecipes[0 ] : BundledRecipes[2 ]);
2647
+ bool IsExtended = BundleType == BundleTypes::ExtMulAccumulateReduction;
2648
+ auto *Mul =
2649
+ cast<VPWidenRecipe>(IsExtended ? BundledRecipes[2 ] : BundledRecipes[0 ]);
2660
2650
Mul->printFlags (O);
2661
- bool IsExtended = BundledRecipes.size () > 2 ;
2662
2651
if (IsExtended)
2663
2652
O << " (" ;
2664
2653
getOperand (0 )->printAsOperand (O, SlotTracker);
2665
2654
if (IsExtended) {
2666
- auto *Ext0 = cast<VPWidenCastRecipe>(
2667
- BundledRecipes.size () == 5 ? BundledRecipes[3 ] : BundledRecipes[0 ]);
2655
+ auto *Ext0 = cast<VPWidenCastRecipe>(BundledRecipes[0 ]);
2668
2656
O << " " << Instruction::getOpcodeName (Ext0->getOpcode ()) << " to "
2669
2657
<< *Ext0->getResultType () << " ), (" ;
2670
2658
} else {
2671
2659
O << " , " ;
2672
2660
}
2673
2661
getOperand (1 )->printAsOperand (O, SlotTracker);
2674
2662
if (IsExtended) {
2675
- auto *Ext1 = cast<VPWidenCastRecipe>(
2676
- BundledRecipes.size () == 5 ? BundledRecipes[3 ] : BundledRecipes[1 ]);
2663
+ auto *Ext1 = cast<VPWidenCastRecipe>(BundledRecipes[1 ]);
2677
2664
O << " " << Instruction::getOpcodeName (Ext1->getOpcode ()) << " to "
2678
2665
<< *Ext1->getResultType () << " )" ;
2679
2666
}
0 commit comments