Skip to content

Commit 285ac34

Browse files
committed
!fixup address latest comments, thanks
1 parent 86b1216 commit 285ac34

File tree

4 files changed

+148
-138
lines changed

4 files changed

+148
-138
lines changed

llvm/lib/Transforms/Vectorize/VPlan.h

Lines changed: 61 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2707,93 +2707,95 @@ class VPBranchOnMaskRecipe : public VPRecipeBase {
27072707
};
27082708

27092709
/// A recipe to combine multiple recipes into a 'bundle' recipe, which should be
2710-
/// considered as single entity for cost-modeling and transforms. The recipe
2711-
/// needs to be 'unbundled', i.e. replaced by its individual recipes before
2712-
/// execute. The bundled recipes are completely connected from the def-use graph
2713-
/// outside the bundled recipes. Operands not defined by recipes in the bundle
2714-
/// are added as operands of the VPBundleRecipe and the users of the result
2715-
/// recipe must be updated to use the VPBundleRecipe.
2716-
class VPBundleRecipe : public VPSingleDefRecipe {
2717-
enum class BundleTypes {
2718-
ExtendedReduction,
2719-
MulAccumulateReduction,
2720-
};
2721-
2722-
/// Recipes bundled together in this VPBundleRecipe.
2710+
/// considered a single entity for cost-modeling and transforms. The recipe
2711+
/// needs to be 'unbundled', i.e. replaced by its bundled recipes before
2712+
/// execute. The bundled recipes are completely disconnected from the def-use
2713+
/// graph of other, non-bundled recipes. Def-use edges between pairs of bundled
2714+
/// recipes remain intact, whereas every edge between a bundled and a
2715+
/// non-bundled recipe is elevated to connect the non-bundled recipe with the
2716+
/// VPExpression itself.
2717+
class VPExpression : public VPSingleDefRecipe {
2718+
/// Recipes bundled together in this VPExpression.
27232719
SmallVector<VPSingleDefRecipe *> BundledRecipes;
27242720

27252721
/// Temporary VPValues used for external operands of the bundle, i.e. operands
27262722
/// not defined by recipes in the bundle.
2727-
SmallVector<VPValue *> TmpValues;
2723+
SmallVector<VPValue *> BundleLiveInPlaceholders;
2724+
2725+
enum class BundleTypes {
2726+
/// Represents an inloop extended reduction operation, performing a
2727+
/// reduction on a extended vector operand into a scalar value, and adding
2728+
/// the result to a chain.
2729+
ExtendedReduction,
2730+
/// Represent an inloop multiply-accumulate reduction, multiplying the
2731+
/// extended vector operands, performing a reduction.add on the result, and
2732+
/// adding the scalar result to a chain.
2733+
ExtMulAccumulateReduction,
2734+
/// Represent an inloop multiply-accumulate reduction, multiplying the
2735+
/// vector operands, performing a reduction.add on the result, and adding
2736+
/// the scalar result to a chain.
2737+
MulAccumulateReduction,
2738+
};
27282739

27292740
/// Type of the bundle.
27302741
BundleTypes BundleType;
27312742

2732-
VPBundleRecipe(BundleTypes BundleType, ArrayRef<VPSingleDefRecipe *> ToBundle,
2733-
ArrayRef<VPValue *> Operands)
2734-
: VPSingleDefRecipe(VPDef::VPBundleSC, {}, {}), BundledRecipes(ToBundle),
2735-
BundleType(BundleType) {
2736-
bundle(Operands);
2737-
}
2738-
2739-
/// Internalize recipes in BundledRecipes External operands (i.e. not defined
2740-
/// by another recipe in the bundle) are replaced by temporary VPValues and
2741-
/// the original operands are transferred to the VPBundleRecipe itself. Clone
2742-
/// recipes as needed to ensure they are only used by other recipes in the
2743-
/// bundle. If \p Operands is not empty, use it as operands for the new
2744-
/// VPBundleRecipe (used when cloning the recipe).
2745-
void bundle(ArrayRef<VPValue *> Operands);
2743+
/// Construct a new VPExpression by internalizing recipes in \p
2744+
/// BundledRecipes. External operands (i.e. not defined by another recipe in
2745+
/// the bundle) are replaced by temporary VPValues and the original operands
2746+
/// are transferred to the VPExpression itself. Clone recipes as needed
2747+
/// (excluding last) to ensure they are only used by other recipes in the
2748+
/// bundle.
2749+
VPExpression(BundleTypes BundleType, ArrayRef<VPSingleDefRecipe *> ToBundle);
27462750

27472751
public:
2748-
VPBundleRecipe(VPWidenCastRecipe *Ext, VPReductionRecipe *Red)
2749-
: VPBundleRecipe(BundleTypes::ExtendedReduction, {Ext, Red}, {}) {}
2750-
VPBundleRecipe(VPWidenRecipe *Mul, VPReductionRecipe *Red)
2751-
: VPBundleRecipe(BundleTypes::MulAccumulateReduction, {Mul, Red}, {}) {}
2752-
VPBundleRecipe(VPWidenCastRecipe *Ext0, VPWidenCastRecipe *Ext1,
2753-
VPWidenRecipe *Mul, VPReductionRecipe *Red)
2754-
: VPBundleRecipe(BundleTypes::MulAccumulateReduction,
2755-
{Ext0, Ext1, Mul, Red}, {}) {}
2756-
VPBundleRecipe(VPWidenCastRecipe *Ext0, VPWidenCastRecipe *Ext1,
2757-
VPWidenRecipe *Mul, VPWidenCastRecipe *Ext2,
2758-
VPReductionRecipe *Red)
2759-
: VPBundleRecipe(BundleTypes::MulAccumulateReduction,
2760-
{Ext0, Ext1, Mul, Ext2, Red}, {}) {}
2761-
2762-
~VPBundleRecipe() override {
2752+
VPExpression(VPWidenCastRecipe *Ext, VPReductionRecipe *Red)
2753+
: VPExpression(BundleTypes::ExtendedReduction, {Ext, Red}) {}
2754+
VPExpression(VPWidenRecipe *Mul, VPReductionRecipe *Red)
2755+
: VPExpression(BundleTypes::MulAccumulateReduction, {Mul, Red}) {}
2756+
VPExpression(VPWidenCastRecipe *Ext0, VPWidenCastRecipe *Ext1,
2757+
VPWidenRecipe *Mul, VPReductionRecipe *Red)
2758+
: VPExpression(BundleTypes::ExtMulAccumulateReduction,
2759+
{Ext0, Ext1, Mul, Red}) {}
2760+
2761+
~VPExpression() override {
27632762
SmallPtrSet<VPRecipeBase *, 4> Seen;
27642763
for (auto *R : reverse(BundledRecipes))
27652764
if (Seen.insert(R).second)
27662765
delete R;
2767-
for (VPValue *T : TmpValues)
2766+
for (VPValue *T : BundleLiveInPlaceholders)
27682767
delete T;
27692768
}
27702769

27712770
VP_CLASSOF_IMPL(VPDef::VPBundleSC)
27722771

2773-
VPBundleRecipe *clone() override {
2772+
VPExpression *clone() override {
27742773
assert(!BundledRecipes.empty() && "empty bundles should be removed");
27752774
SmallVector<VPSingleDefRecipe *> NewBundledRecipes;
27762775
for (auto *R : BundledRecipes)
27772776
NewBundledRecipes.push_back(R->clone());
27782777
for (auto *New : NewBundledRecipes) {
2779-
for (const auto &[Idx, Old] : enumerate(BundledRecipes)) {
2778+
for (const auto &[Idx, Old] : enumerate(BundledRecipes))
27802779
New->replaceUsesOfWith(Old, NewBundledRecipes[Idx]);
2781-
}
2780+
// Update placeholder operands in the cloned recipe to use the external
2781+
// operands, to be internalized when the cloned bundle is constructed.
2782+
for (const auto &[Placeholder, OutsideOp] :
2783+
zip(BundleLiveInPlaceholders, operands()))
2784+
New->replaceUsesOfWith(Placeholder, OutsideOp);
27822785
}
2783-
return new VPBundleRecipe(BundleType, NewBundledRecipes, operands());
2786+
return new VPExpression(BundleType, NewBundledRecipes);
27842787
}
27852788

27862789
/// Return the VPSingleDefRecipe producing the final result of the bundled
27872790
/// recipe.
27882791
VPSingleDefRecipe *getResultRecipe() const { return BundledRecipes.back(); }
27892792

27902793
/// Insert the bundled recipes back into the VPlan, directly before the
2791-
/// current recipe. Leaves the bundle recipe empty and the recipe must be
2792-
/// removed before codegen.
2794+
/// current recipe. Leaves the bundle recipe empty, which must be removed
2795+
/// before codegen.
27932796
void unbundle();
27942797

2795-
/// Generate the extraction of the appropriate bit from the block mask and the
2796-
/// conditional branch.
2798+
/// Method for generating code, must not be called as this recipe is abstract.
27972799
void execute(VPTransformState &State) override {
27982800
llvm_unreachable("recipe must be removed before execute");
27992801
}
@@ -2806,6 +2808,13 @@ class VPBundleRecipe : public VPSingleDefRecipe {
28062808
void print(raw_ostream &O, const Twine &Indent,
28072809
VPSlotTracker &SlotTracker) const override;
28082810
#endif
2811+
2812+
/// Returns true if this bundle contains recipes that may read from or write
2813+
/// to memory.
2814+
bool mayReadOrWriteMemory() const;
2815+
2816+
/// Returns true if this bundle contains recipes that may have side effects.
2817+
bool mayHaveSideEffects() const;
28092818
};
28102819

28112820
/// VPPredInstPHIRecipe is a recipe for generating the phi nodes needed when

llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp

Lines changed: 67 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ using VectorParts = SmallVector<Value *, 2>;
4949

5050
bool VPRecipeBase::mayWriteToMemory() const {
5151
switch (getVPDefID()) {
52+
case VPBundleSC:
53+
return cast<VPBundleRecipe>(this)->mayReadOrWriteMemory();
5254
case VPInstructionSC:
5355
return cast<VPInstruction>(this)->opcodeMayReadOrWriteFromMemory();
5456
case VPInterleaveSC:
@@ -97,6 +99,8 @@ bool VPRecipeBase::mayWriteToMemory() const {
9799

98100
bool VPRecipeBase::mayReadFromMemory() const {
99101
switch (getVPDefID()) {
102+
case VPBundleSC:
103+
return cast<VPBundleRecipe>(this)->mayReadOrWriteMemory();
100104
case VPInstructionSC:
101105
return cast<VPInstruction>(this)->opcodeMayReadOrWriteFromMemory();
102106
case VPWidenLoadEVLSC:
@@ -143,6 +147,8 @@ bool VPRecipeBase::mayReadFromMemory() const {
143147

144148
bool VPRecipeBase::mayHaveSideEffects() const {
145149
switch (getVPDefID()) {
150+
case VPBundleSC:
151+
return cast<VPBundleRecipe>(this)->mayHaveSideEffects();
146152
case VPDerivedIVSC:
147153
case VPFirstOrderRecurrencePHISC:
148154
case VPPredInstPHISC:
@@ -2500,95 +2506,65 @@ InstructionCost VPReductionRecipe::computeCost(ElementCount VF,
25002506
Ctx.CostKind);
25012507
}
25022508

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) {
25042516
assert(!BundledRecipes.empty() && "Nothing to bundle?");
25052517

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;
25082520
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);
25172530
})) {
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);
25212539
}
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
25362546
// the bundle. The original operands are added as operands of the
2537-
// VPBundleRecipe.
2547+
// VPBundleRecipe itself.
25382548
for (auto *R : BundledRecipes) {
25392549
for (const auto &[Idx, Op] : enumerate(R->operands())) {
25402550
auto *Def = Op->getDefiningRecipe();
2541-
if (Def && BundledUsers.contains(Def))
2551+
if (Def && BundledRecipesAsSetOfUsers.contains(Def))
25422552
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());
25492556
}
25502557
}
25512558
}
25522559

25532560
void VPBundleRecipe::unbundle() {
25542561
for (auto *R : BundledRecipes)
2555-
if (!R->getParent())
25562562
R->insertBefore(this);
25572563

25582564
for (const auto &[Idx, Op] : enumerate(operands()))
2559-
TmpValues[Idx]->replaceAllUsesWith(Op);
2565+
BundleLiveInPlaceholders[Idx]->replaceAllUsesWith(Op);
25602566

25612567
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-
}
25922568
BundledRecipes.clear();
25932569
}
25942570

@@ -2610,15 +2586,27 @@ InstructionCost VPBundleRecipe::computeCost(ElementCount VF,
26102586
RedTy, SrcVecTy, std::nullopt, Ctx.CostKind);
26112587
}
26122588
case BundleTypes::MulAccumulateReduction:
2589+
return Ctx.TTI.getMulAccReductionCost(false, RedTy, SrcVecTy, Ctx.CostKind);
2590+
2591+
case BundleTypes::ExtMulAccumulateReduction:
26132592
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,
26182595
RedTy, SrcVecTy, Ctx.CostKind);
26192596
}
26202597
}
26212598

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+
26222610
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
26232611

26242612
void VPBundleRecipe::print(raw_ostream &O, const Twine &Indent,
@@ -2647,33 +2635,32 @@ void VPBundleRecipe::print(raw_ostream &O, const Twine &Indent,
26472635
O << ")";
26482636
break;
26492637
}
2650-
case BundleTypes::MulAccumulateReduction: {
2638+
case BundleTypes::MulAccumulateReduction:
2639+
case BundleTypes::ExtMulAccumulateReduction: {
26512640
getOperand(getNumOperands() - 1)->printAsOperand(O, SlotTracker);
26522641
O << " + ";
26532642
O << "reduce."
26542643
<< Instruction::getOpcodeName(
26552644
RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind()))
26562645
<< " (";
26572646
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]);
26602650
Mul->printFlags(O);
2661-
bool IsExtended = BundledRecipes.size() > 2;
26622651
if (IsExtended)
26632652
O << "(";
26642653
getOperand(0)->printAsOperand(O, SlotTracker);
26652654
if (IsExtended) {
2666-
auto *Ext0 = cast<VPWidenCastRecipe>(
2667-
BundledRecipes.size() == 5 ? BundledRecipes[3] : BundledRecipes[0]);
2655+
auto *Ext0 = cast<VPWidenCastRecipe>(BundledRecipes[0]);
26682656
O << " " << Instruction::getOpcodeName(Ext0->getOpcode()) << " to "
26692657
<< *Ext0->getResultType() << "), (";
26702658
} else {
26712659
O << ", ";
26722660
}
26732661
getOperand(1)->printAsOperand(O, SlotTracker);
26742662
if (IsExtended) {
2675-
auto *Ext1 = cast<VPWidenCastRecipe>(
2676-
BundledRecipes.size() == 5 ? BundledRecipes[3] : BundledRecipes[1]);
2663+
auto *Ext1 = cast<VPWidenCastRecipe>(BundledRecipes[1]);
26772664
O << " " << Instruction::getOpcodeName(Ext1->getOpcode()) << " to "
26782665
<< *Ext1->getResultType() << ")";
26792666
}

0 commit comments

Comments
 (0)