[llvm] [VPlan] Add VPExpressionRecipe, replacing extended reduction recipes. (PR #144281)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 1 13:34:01 PDT 2025
================
@@ -2563,30 +2563,182 @@ InstructionCost VPReductionRecipe::computeCost(ElementCount VF,
Ctx.CostKind);
}
-InstructionCost
-VPExtendedReductionRecipe::computeCost(ElementCount VF,
- VPCostContext &Ctx) const {
- unsigned Opcode = RecurrenceDescriptor::getOpcode(getRecurrenceKind());
+VPExpressionRecipe::VPExpressionRecipe(
+ ExpressionTypes ExpressionType,
+ ArrayRef<VPSingleDefRecipe *> ExpressionRecipes)
+ : VPSingleDefRecipe(VPDef::VPExpressionSC, {}, {}),
+ ExpressionRecipes(SetVector<VPSingleDefRecipe *>(
+ ExpressionRecipes.begin(), ExpressionRecipes.end())
+ .takeVector()),
+ ExpressionType(ExpressionType) {
+ assert(!ExpressionRecipes.empty() && "Nothing to combine?");
+ assert(
+ none_of(ExpressionRecipes,
+ [](VPSingleDefRecipe *R) { return R->mayHaveSideEffects(); }) &&
+ "expression cannot contain recipes with side-effects");
+
+ // Maintain a copy of the expression recipes as a set of users.
+ SmallPtrSet<VPUser *, 4> ExpressionRecipesAsSetOfUsers;
+ for (auto *R : ExpressionRecipes)
+ ExpressionRecipesAsSetOfUsers.insert(R);
+
+ // Recipes in the expression, except the last one, must only be used by
+ // (other) recipes inside the expression. If there are other users, external
+ // to the expression, use a clone of the recipe for external users.
+ for (VPSingleDefRecipe *R : ExpressionRecipes) {
+ if (R != ExpressionRecipes.back() &&
+ any_of(R->users(), [&ExpressionRecipesAsSetOfUsers](VPUser *U) {
+ return !ExpressionRecipesAsSetOfUsers.contains(U);
+ })) {
+ // There are users outside of the expression. Clone the recipe and use the
+ // clone those external users.
+ VPSingleDefRecipe *CopyForExtUsers = R->clone();
+ R->replaceUsesWithIf(CopyForExtUsers, [&ExpressionRecipesAsSetOfUsers](
+ VPUser &U, unsigned) {
+ return !ExpressionRecipesAsSetOfUsers.contains(&U);
+ });
+ CopyForExtUsers->insertBefore(R);
+ }
+ if (R->getParent())
+ R->removeFromParent();
+ }
+
+ // Internalize all external operands to the expression recipes. To do so,
+ // create new temporary VPValues for all operands defined by a recipe outside
+ // the expression. The original operands are added as operands of the
+ // VPExpressionRecipe itself.
+ for (auto *R : ExpressionRecipes) {
+ for (const auto &[Idx, Op] : enumerate(R->operands())) {
+ auto *Def = Op->getDefiningRecipe();
+ if (Def && ExpressionRecipesAsSetOfUsers.contains(Def))
+ continue;
+ addOperand(Op);
+ LiveInPlaceholders.push_back(new VPValue());
+ R->setOperand(Idx, LiveInPlaceholders.back());
+ }
+ }
+}
+
+void VPExpressionRecipe::unbundle() {
+ for (auto *R : ExpressionRecipes)
+ R->insertBefore(this);
+
+ for (const auto &[Idx, Op] : enumerate(operands()))
+ LiveInPlaceholders[Idx]->replaceAllUsesWith(Op);
+
+ replaceAllUsesWith(ExpressionRecipes.back());
+ ExpressionRecipes.clear();
+}
+
+InstructionCost VPExpressionRecipe::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));
----------------
ayalz wrote:
Does the first operand of VPExpressionRecipe deserve a concrete get*() method? Complementing `getOperandOfResultType()`.
https://github.com/llvm/llvm-project/pull/144281
More information about the llvm-commits
mailing list