[llvm] [VPlan] Add VPSingleDefBundleRecipe, replacing extended reduction recipes. (PR #144281)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 1 05:55:54 PDT 2025


================
@@ -2580,30 +2580,174 @@ InstructionCost VPReductionRecipe::computeCost(ElementCount VF,
                                             Ctx.CostKind);
 }
 
-InstructionCost
-VPExtendedReductionRecipe::computeCost(ElementCount VF,
-                                       VPCostContext &Ctx) const {
-  unsigned Opcode = RecurrenceDescriptor::getOpcode(getRecurrenceKind());
+VPSingleDefBundleRecipe::VPSingleDefBundleRecipe(
+    BundleTypes BundleType, ArrayRef<VPSingleDefRecipe *> ToBundle)
+    : VPSingleDefRecipe(VPDef::VPBundleSC, {}, {}),
+      BundledRecipes(
+          SetVector<VPSingleDefRecipe *>(ToBundle.begin(), ToBundle.end())
+              .takeVector()),
+      BundleType(BundleType) {
+  assert(!BundledRecipes.empty() && "Nothing to bundle?");
+
+  // Maintain a copy of the bundled recipes as a set of users.
+  SmallPtrSet<VPUser *, 4> BundledRecipesAsSetOfUsers;
+  for (auto *R : BundledRecipes)
+    BundledRecipesAsSetOfUsers.insert(R);
+
+  // Recipes in the bundle, except the last one, must only be used by (other)
+  // recipes inside the bundle. If there are other users, external to the
+  // bundle, use a clone of the recipe for external users.
+  for (VPSingleDefRecipe *R : BundledRecipes) {
+    if (R != BundledRecipes.back() &&
+        any_of(R->users(), [&BundledRecipesAsSetOfUsers](VPUser *U) {
+          return !BundledRecipesAsSetOfUsers.contains(U);
+        })) {
+      // There are users outside of the bundle. Clone the recipe and use the
+      // clone those external users.
+      VPSingleDefRecipe *CopyForExtUsers = R->clone();
+      R->replaceUsesWithIf(CopyForExtUsers,
+                           [&BundledRecipesAsSetOfUsers](VPUser &U, unsigned) {
+                             return !BundledRecipesAsSetOfUsers.contains(&U);
+                           });
+      CopyForExtUsers->insertBefore(R);
+    }
+    if (R->getParent())
+      R->removeFromParent();
+  }
+
+  // Internalize all external operands to the bundled recipes. To do so,
+  // create new temporary VPValues for all operands defined by a recipe outside
+  // the bundle. The original operands are added as operands of the
+  // VPSingleDefBundleRecipe itself.
+  for (auto *R : BundledRecipes) {
+    for (const auto &[Idx, Op] : enumerate(R->operands())) {
+      auto *Def = Op->getDefiningRecipe();
+      if (Def && BundledRecipesAsSetOfUsers.contains(Def))
+        continue;
+      addOperand(Op);
+      BundleLiveInPlaceholders.push_back(new VPValue());
+      R->setOperand(Idx, BundleLiveInPlaceholders.back());
+    }
+  }
+}
+
+void VPSingleDefBundleRecipe::unbundle() {
+  for (auto *R : BundledRecipes)
+    R->insertBefore(this);
+
+  for (const auto &[Idx, Op] : enumerate(operands()))
+    BundleLiveInPlaceholders[Idx]->replaceAllUsesWith(Op);
+
+  replaceAllUsesWith(BundledRecipes.back());
+  BundledRecipes.clear();
+}
+
+InstructionCost VPSingleDefBundleRecipe::computeCost(ElementCount VF,
+                                                     VPCostContext &Ctx) const {
   Type *RedTy = Ctx.Types.inferScalarType(this);
-  auto *SrcVecTy =
-      cast<VectorType>(toVectorTy(Ctx.Types.inferScalarType(getVecOp()), VF));
+  auto *SrcVecTy = cast<VectorType>(
+      toVectorTy(Ctx.Types.inferScalarType(getOperand(0)), VF));
   assert(RedTy->isIntegerTy() &&
-         "ExtendedReduction only support integer type currently.");
-  return Ctx.TTI.getExtendedReductionCost(Opcode, isZExt(), RedTy, SrcVecTy,
-                                          std::nullopt, Ctx.CostKind);
+         "VPSingleDefBundleRecipe only supports integer types currently.");
+  switch (BundleType) {
+  case BundleTypes::ExtendedReduction: {
+    unsigned Opcode = RecurrenceDescriptor::getOpcode(
+        cast<VPReductionRecipe>(BundledRecipes[1])->getRecurrenceKind());
+    return Ctx.TTI.getExtendedReductionCost(
+        Opcode,
+        cast<VPWidenCastRecipe>(BundledRecipes.front())->getOpcode() ==
+            Instruction::ZExt,
+        RedTy, SrcVecTy, std::nullopt, Ctx.CostKind);
+  }
+  case BundleTypes::MulAccumulateReduction:
+    return Ctx.TTI.getMulAccReductionCost(false, RedTy, SrcVecTy, Ctx.CostKind);
+
+  case BundleTypes::ExtMulAccumulateReduction:
+    return Ctx.TTI.getMulAccReductionCost(
+        cast<VPWidenCastRecipe>(BundledRecipes.front())->getOpcode() ==
+            Instruction::ZExt,
+        RedTy, SrcVecTy, Ctx.CostKind);
+  }
+}
+
+bool VPSingleDefBundleRecipe::mayReadOrWriteMemory() const {
+  return any_of(BundledRecipes, [](VPSingleDefRecipe *R) {
+    return R->mayReadFromMemory() || R->mayWriteToMemory();
+  });
 }
 
-InstructionCost
-VPMulAccumulateReductionRecipe::computeCost(ElementCount VF,
-                                            VPCostContext &Ctx) const {
-  Type *RedTy = Ctx.Types.inferScalarType(this);
-  auto *SrcVecTy =
-      cast<VectorType>(toVectorTy(Ctx.Types.inferScalarType(getVecOp0()), VF));
-  return Ctx.TTI.getMulAccReductionCost(isZExt(), RedTy, SrcVecTy,
-                                        Ctx.CostKind);
+bool VPSingleDefBundleRecipe::mayHaveSideEffects() const {
+  return any_of(BundledRecipes,
+                [](VPSingleDefRecipe *R) { return R->mayHaveSideEffects(); });
----------------
fhahn wrote:

For now, I added an assert here and. the constructor to disallow recieps with side-effects, thanks

https://github.com/llvm/llvm-project/pull/144281


More information about the llvm-commits mailing list