Skip to content

[VPlan] Sink retrieving legacy costs to more specific computeCost impls. #109708

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 9, 2024

Conversation

fhahn
Copy link
Contributor

@fhahn fhahn commented Sep 23, 2024

Make legacy cost retrieval independent of getInstructionForCost by sinking it to more specific ::computeCost implementation (specifically VPInterleaveRecipe::computeCost and VPSingleDefRecipe::computeCost).

Inline getInstructionForCost to VPRecipeBase::cost(), as it is now only used to decide which recipes to skip during cost computation and when to apply forced costs.

Update computeCost to return InstructionCost::getMax() for recipes
without underlying instructions. Max is used as a sentinel value to
handle cases where there is no underlying instruction. At the moment we
need to catch those cases when -force-target-instruction-cost is passed
to avoid applying the forced cost to auxiliary recipes (like scalar
steps). This is needed to match the legacy behavior.

Unfortunately we cannot use InstructionCost::getInvalid, as this is used
to indicate that an instruction cannot be legalized (e.g. for scalable
vectors).

Alternatively computeCost could return an optional cost.
@llvmbot
Copy link
Member

llvmbot commented Sep 23, 2024

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

Changes

Update computeCost to return InstructionCost::getMax() for recipes without underlying instructions. Max is used as a sentinel value to handle cases where there is no underlying instruction. At the moment we need to catch those cases when -force-target-instruction-cost is passed to avoid applying the forced cost to auxiliary recipes (like scalar steps). This is needed to match the legacy behavior.

Unfortunately we cannot use InstructionCost::getInvalid, as this is used to indicate that an instruction cannot be legalized (e.g. for scalable vectors).

Alternatively computeCost could return an optional cost.


Full diff: https://github.com/llvm/llvm-project/pull/109708.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Vectorize/VPlan.h (+3-1)
  • (modified) llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp (+9-11)
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 0632495bc511cd..6f8a44e1cd1802 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -844,7 +844,9 @@ class VPRecipeBase : public ilist_node_with_parent<VPRecipeBase, VPBasicBlock>,
 protected:
   /// Compute the cost of this recipe either using a recipe's specialized
   /// implementation or using the legacy cost model and the underlying
-  /// instructions.
+  /// instructions. Returns InstructionCost::max() if the cost of this recipe
+  /// should be ignored. Forced target instruction cost is not applied for such
+  /// recipes.
   virtual InstructionCost computeCost(ElementCount VF,
                                       VPCostContext &Ctx) const;
 };
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 3f7ab416e877bc..ca4622b74275e5 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -276,14 +276,6 @@ static Instruction *getInstructionForCost(const VPRecipeBase *R) {
     return dyn_cast_or_null<Instruction>(S->getUnderlyingValue());
   if (auto *IG = dyn_cast<VPInterleaveRecipe>(R))
     return IG->getInsertPos();
-  // Currently the legacy cost model only calculates the instruction cost with
-  // underlying instruction. Removing the WidenMem here will prevent
-  // force-target-instruction-cost overwriting the cost of recipe with
-  // underlying instruction which is inconsistent with the legacy model.
-  // TODO: Remove WidenMem from this function when we don't need to compare to
-  // the legacy model.
-  if (auto *WidenMem = dyn_cast<VPWidenMemoryRecipe>(R))
-    return &WidenMem->getIngredient();
   return nullptr;
 }
 
@@ -293,9 +285,13 @@ InstructionCost VPRecipeBase::cost(ElementCount VF, VPCostContext &Ctx) {
     return 0;
 
   InstructionCost RecipeCost = computeCost(VF, Ctx);
-  if (UI && ForceTargetInstructionCost.getNumOccurrences() > 0 &&
-      RecipeCost.isValid())
+  if (ForceTargetInstructionCost.getNumOccurrences() > 0 &&
+      (RecipeCost.isValid() && RecipeCost != InstructionCost::getMax()))
     RecipeCost = InstructionCost(ForceTargetInstructionCost);
+  // Max cost is used as a sentinel value to detect recipes without underlying
+  // instructions for which no forced target instruction cost should be applied.
+  if (RecipeCost == InstructionCost::getMax())
+    RecipeCost = 0;
 
   LLVM_DEBUG({
     dbgs() << "Cost of " << RecipeCost << " for VF " << VF << ": ";
@@ -315,7 +311,9 @@ InstructionCost VPRecipeBase::computeCost(ElementCount VF,
     // transform, avoid computing their cost multiple times for now.
     Ctx.SkipCostComputation.insert(UI);
   }
-  return UI ? Ctx.getLegacyCost(UI, VF) : 0;
+  // Max cost is used as a sentinel value to detect recipes without underlying
+  // instructions for which no forced target instruction cost should be applied.
+  return UI ? Ctx.getLegacyCost(UI, VF) : InstructionCost::getMax();
 }
 
 FastMathFlags VPRecipeWithIRFlags::getFastMathFlags() const {

@@ -276,14 +276,6 @@ static Instruction *getInstructionForCost(const VPRecipeBase *R) {
return dyn_cast_or_null<Instruction>(S->getUnderlyingValue());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we're here, this could return S->getUnderlyingInstr(), if the latter does cast_if_present rather than cast?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I think originally the intention was to only use getUnderlyingInstr if it is guaranteed to be available, but perhaps it is time to revisit this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right. May be good to revisit this intention.

// TODO: Remove WidenMem from this function when we don't need to compare to
// the legacy model.
if (auto *WidenMem = dyn_cast<VPWidenMemoryRecipe>(R))
return &WidenMem->getIngredient();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth leaving a note, that even though widen loads and stores have an underlying instruction ("ingredient"), null is returned - in order to match legacy cost model behavior with force-target-instruction-cost?

The instruction a recipe provides for cost affects both

  • skipCostComputation() - widen loads and stores are irrelevant for skipping?
  • force-target-instruction-cost - widen loads and stores should be assigned zero instead of this overriding cost?
  • w/o force-target-instruction-cost - should be assigned zero cost?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified the the comment about the return value for the function.

Nullptr is returned if either the recipe doesn't have an underlying instruction or computeCost is implemented and there is no need for the underlying instruction (i.e. it should not be needed to be skipped)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nullptr is returned if either the recipe doesn't have an underlying instruction or computeCost is implemented and there is no need for the underlying instruction (i.e. it should not be needed to be skipped)

Regarding the "else" part of this "or" - not needing UI because recipe is not to be skipped is fine (if it's absence from SkipCostComputation it won't be skipped), but would UI still be needed in order to apply ForceTargetInstructionCost?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been reworked in the latest version. The function is gone and inline to ::cost(), which clarifies that it is only used to decide to skip and when to apply forced costs.

Comment on lines 291 to 294
// Max cost is used as a sentinel value to detect recipes without underlying
// instructions for which no forced target instruction cost should be applied.
if (RecipeCost == InstructionCost::getMax())
RecipeCost = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So cost is essentially a valid non-overridable/un-forceable value, of zero?

Would adding, say, a "Permanent" state to CostState, along with Valid and InValid, be reasonable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes exactly. Not sure if it would be worth adding a new state for this very specific use case?

@@ -293,9 +285,13 @@ InstructionCost VPRecipeBase::cost(ElementCount VF, VPCostContext &Ctx) {
return 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that skipped costs also skip debug dump.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest version

RecipeCost = InstructionCost(ForceTargetInstructionCost);
// Max cost is used as a sentinel value to detect recipes without underlying
// instructions for which no forced target instruction cost should be applied.
if (RecipeCost == InstructionCost::getMax())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

elseif? (Otherwise a ForceTargetInstructionCost of Max will be replaced by zero.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, thanks!

return UI ? Ctx.getLegacyCost(UI, VF) : 0;
// Max cost is used as a sentinel value to detect recipes without underlying
// instructions for which no forced target instruction cost should be applied.
return UI ? Ctx.getLegacyCost(UI, VF) : InstructionCost::getMax();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment above about returning zero when no underlying instruction is there, should be updated.

Under ForceTargetInstructionCost, all UI's with valid costs are assigned ForceTargetInstructionCost cost. Therefore, under ForceTargetInstructionCost, all recipes w/ UI's and valid costs should also be assigned this cost, and all recipes w/o UI's should be assigned zero cost?

Need to distinguish between (zero, but could be any other valid) cost of a recipe that has no underlying, which should be ignored by ForceTargetInstructionCost because legacy only addresses UI's, and recipes w/ underlying (whose legacy cost is returned, can be zero or any other valid cost) which are subject to ForceTargetInstructionCost.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<Move the comment above to update the existing comment, thanks!

@@ -844,7 +844,9 @@ class VPRecipeBase : public ilist_node_with_parent<VPRecipeBase, VPBasicBlock>,
protected:
/// Compute the cost of this recipe either using a recipe's specialized
/// implementation or using the legacy cost model and the underlying
/// instructions.
/// instructions. Returns InstructionCost::max() if the cost of this recipe
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underlying instruction can be passed as argument, except that this base implementation should be a default for all derived VPlan-based computations, where the latter should be independent on UI, if possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, also there are some computeCost implementation for recipes with underlying instruction, for which the default should not trigger. In particular, all recipes which currently have computeCost implemented in subclasses should be included with force-target-instruction-cost.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively computeCost could return an optional cost.

Perhaps better to return no cost at all, as in optional, when cost should be ignored, rather than a max sentinel. The latter requires additional attention to remain unmodified, preventing (mistaken) updates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change is not needed in latest version.

@@ -844,7 +844,9 @@ class VPRecipeBase : public ilist_node_with_parent<VPRecipeBase, VPBasicBlock>,
protected:
/// Compute the cost of this recipe either using a recipe's specialized
/// implementation or using the legacy cost model and the underlying
/// instructions.
/// instructions. Returns InstructionCost::max() if the cost of this recipe
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively computeCost could return an optional cost.

Perhaps better to return no cost at all, as in optional, when cost should be ignored, rather than a max sentinel. The latter requires additional attention to remain unmodified, preventing (mistaken) updates.

/// the legacy cost model. Return nullptr if there's no suitable instruction or
/// computeCost is already implemented for the recipe and there is no need for
/// the underlying instruction, i.e. it does not need to be skipped for cost
/// computations.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gotten Instruction For Cost is used for (a) computing cost via legacy model - zero or greater, valid or not, (b) skipping cost - valid zero cost is used if skipped, (c) qualifying for Forced cost overwriting - valid zero cost is used if unqualified. All uses agree on UI or null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has completely changed in the latest version.

I've implemented ::computeCost for recipes as needed, so there's no need to use this function with getLegacyCost. This more clearly scopes where the legacy cost is still used and how the instructions are obtained (recipe specific). There's no need to remove recipes from getInstructionForCost as their computeCost moves to not use legacy cost.

@@ -276,14 +276,6 @@ static Instruction *getInstructionForCost(const VPRecipeBase *R) {
return dyn_cast_or_null<Instruction>(S->getUnderlyingValue());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right. May be good to revisit this intention.

RecipeCost = InstructionCost(ForceTargetInstructionCost);
// Max cost is used as a sentinel value to detect recipes without underlying
// instructions for which no forced target instruction cost should be applied.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to indicate why such a sentinel is needed, rather than detecting the absence of an underlying instruction by directly checking UI, as done now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No sentinel is needed in the latest version, it uses UI now, thanks!

// InstructionCost::getMax. It is used as a sentinel value to detect recipes
// without underlying instructions for which no forced target instruction cost
// should be applied.

Instruction *UI = getInstructionForCost(this);
if (UI && isa<VPReplicateRecipe>(this)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(independent) Have VPReplicateRecipe::computeCost() take care of inserting UI into SkipCostComputation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no such implementation yet, but can be added soon! Now moved slightly closer to VPSingleDefRecipe::computeCost.

// 0.
// the underlying instruction. If there is no underlying instruction or the
// cost is computed by the recipe's computeCost, returns
// InstructionCost::getMax. It is used as a sentinel value to detect recipes
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// InstructionCost::getMax. It is used as a sentinel value to detect recipes
// InstructionCost::getMax. It is used as a sentinel value to detect recipes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment gone in the latest version.

Comment on lines 317 to 318
// without underlying instructions for which no forced target instruction cost
// should be applied.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// without underlying instructions for which no forced target instruction cost
// should be applied.
// without underlying instructions for which forced target instruction cost
// should not be applied.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment gone in the latest version.

Instruction *UI = getInstructionForCost(this);
if (UI && isa<VPReplicateRecipe>(this)) {
// VPReplicateRecipe may be cloned as part of an existing VPlan-to-VPlan
// transform, avoid computing their cost multiple times for now.
Ctx.SkipCostComputation.insert(UI);
}
return UI ? Ctx.getLegacyCost(UI, VF) : 0;
return UI ? Ctx.getLegacyCost(UI, VF) : InstructionCost::getMax();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the default base-class implementation of VPRecipeBase::computeCost() should return null, delegating the fallback use of Ctx.getLegacyCost(UI, VF) to its caller VPRecipeBase::cost(), as outlined above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjusted to use getLegacyCost in a few relevant sub-classes (VPSingleDefRecipe/VPInterleaveRecipe). Should hopefully be clearer and simpler now

RecipeCost = InstructionCost(ForceTargetInstructionCost);
// Max cost is used as a sentinel value to detect recipes without underlying
// instructions for which no forced target instruction cost should be applied.
else if (RecipeCost == InstructionCost::getMax())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the logic be as follows:

If UI is to be skipped, zero cost should be (dumped? and) returned.

If VPlan-based cost cannot be computed (yet, i.e., computeCost() returned null), fallback on legacy cost model using UI - asserting UI is available?

If computed cost (VPlan or legacy based) is invalid, it should be (dumped and) returned.

If ForceTargetInstructionCost, the cost should be either ForceTargetInstructionCost or zero, depending on whether UI exists or not.

Sounds right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked to implement the relevant ::comptueCosts to return the legacy cost, and use UI to decide when to skip and apply forced cost.

// TODO: Remove WidenMem from this function when we don't need to compare to
// the legacy model.
if (auto *WidenMem = dyn_cast<VPWidenMemoryRecipe>(R))
return &WidenMem->getIngredient();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nullptr is returned if either the recipe doesn't have an underlying instruction or computeCost is implemented and there is no need for the underlying instruction (i.e. it should not be needed to be skipped)

Regarding the "else" part of this "or" - not needing UI because recipe is not to be skipped is fine (if it's absence from SkipCostComputation it won't be skipped), but would UI still be needed in order to apply ForceTargetInstructionCost?

@fhahn fhahn force-pushed the vplan-max-cost-sentinel branch from b7440b3 to 7fcddd6 Compare October 8, 2024 18:49
Copy link
Contributor Author

@fhahn fhahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latest version changed quite drastically.

Now no sentinel value is used. Instead VPSingleDefRecipe/VPInterleaveRecipe return their cost via legacy, which removes the use of getInstructionForCost to return legacy costs. getInstructionForCost is only used in ::cost to divide what to skip and when to apply forced costs.

Hopefully this should be simpler and clearer. WDYT?

@@ -844,7 +844,9 @@ class VPRecipeBase : public ilist_node_with_parent<VPRecipeBase, VPBasicBlock>,
protected:
/// Compute the cost of this recipe either using a recipe's specialized
/// implementation or using the legacy cost model and the underlying
/// instructions.
/// instructions. Returns InstructionCost::max() if the cost of this recipe
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change is not needed in latest version.

/// the legacy cost model. Return nullptr if there's no suitable instruction or
/// computeCost is already implemented for the recipe and there is no need for
/// the underlying instruction, i.e. it does not need to be skipped for cost
/// computations.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has completely changed in the latest version.

I've implemented ::computeCost for recipes as needed, so there's no need to use this function with getLegacyCost. This more clearly scopes where the legacy cost is still used and how the instructions are obtained (recipe specific). There's no need to remove recipes from getInstructionForCost as their computeCost moves to not use legacy cost.

// TODO: Remove WidenMem from this function when we don't need to compare to
// the legacy model.
if (auto *WidenMem = dyn_cast<VPWidenMemoryRecipe>(R))
return &WidenMem->getIngredient();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been reworked in the latest version. The function is gone and inline to ::cost(), which clarifies that it is only used to decide to skip and when to apply forced costs.

@@ -293,9 +285,13 @@ InstructionCost VPRecipeBase::cost(ElementCount VF, VPCostContext &Ctx) {
return 0;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest version

RecipeCost = InstructionCost(ForceTargetInstructionCost);
// Max cost is used as a sentinel value to detect recipes without underlying
// instructions for which no forced target instruction cost should be applied.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No sentinel is needed in the latest version, it uses UI now, thanks!

Comment on lines 314 to 315
// the underlying instruction. If there is no underlying instruction or the
// cost is computed by the recipe's computeCost, returns
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully clearer in the latest version.

// 0.
// the underlying instruction. If there is no underlying instruction or the
// cost is computed by the recipe's computeCost, returns
// InstructionCost::getMax. It is used as a sentinel value to detect recipes
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment gone in the latest version.

Comment on lines 317 to 318
// without underlying instructions for which no forced target instruction cost
// should be applied.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment gone in the latest version.

// InstructionCost::getMax. It is used as a sentinel value to detect recipes
// without underlying instructions for which no forced target instruction cost
// should be applied.

Instruction *UI = getInstructionForCost(this);
if (UI && isa<VPReplicateRecipe>(this)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no such implementation yet, but can be added soon! Now moved slightly closer to VPSingleDefRecipe::computeCost.

Instruction *UI = getInstructionForCost(this);
if (UI && isa<VPReplicateRecipe>(this)) {
// VPReplicateRecipe may be cloned as part of an existing VPlan-to-VPlan
// transform, avoid computing their cost multiple times for now.
Ctx.SkipCostComputation.insert(UI);
}
return UI ? Ctx.getLegacyCost(UI, VF) : 0;
return UI ? Ctx.getLegacyCost(UI, VF) : InstructionCost::getMax();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjusted to use getLegacyCost in a few relevant sub-classes (VPSingleDefRecipe/VPInterleaveRecipe). Should hopefully be clearer and simpler now

@fhahn fhahn changed the title [VPlan] Return Max from computeCost without underlying instrs. [VPlan] Sink retrieving legacy costs to more specific computeCost impls. Oct 8, 2024
@fhahn fhahn force-pushed the vplan-max-cost-sentinel branch from 7fcddd6 to f632630 Compare October 8, 2024 19:00
Copy link
Collaborator

@ayalz ayalz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for reworking this, LGTM!
Sinking legacy costs into individual usages will hopefully help refactor them into VPlan.
Added some minor comments.

@@ -915,6 +915,9 @@ class VPSingleDefRecipe : public VPRecipeBase, public VPValue {
llvm_unreachable("Unhandled VPDefID");
}

InstructionCost computeCost(ElementCount VF,
VPCostContext &Ctx) const override;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can a better position be found, rather than between two static classof()'s?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to the end. thanks!

@@ -2326,6 +2332,9 @@ class VPInterleaveRecipe : public VPRecipeBase {
/// Generate the wide load or store, and shuffles.
void execute(VPTransformState &State) override;

InstructionCost computeCost(ElementCount VF,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to /// document, here and elsewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added thanks!

if (UI && ForceTargetInstructionCost.getNumOccurrences() > 0 &&
RecipeCost.isValid())
RecipeCost = InstructionCost(ForceTargetInstructionCost);
// Get the underlying instruction for the recipe, if there is one. Is is used
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Get the underlying instruction for the recipe, if there is one. Is is used
// Get the underlying instruction for the recipe, if there is one. It is used

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks!

@@ -864,6 +861,11 @@ void VPIRInstruction::execute(VPTransformState &State) {
State.Builder.SetInsertPoint(I.getParent(), std::next(I.getIterator()));
}

InstructionCost VPIRInstruction::computeCost(ElementCount VF,
VPCostContext &Ctx) const {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comment explaining that this wraps an existing IR instruction on the border of VPlan's scope, hence does not contribute to VPlan's cost modeling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added, thanks!

@@ -2156,6 +2158,11 @@ void VPBranchOnMaskRecipe::execute(VPTransformState &State) {
ReplaceInstWithInst(CurrentTerminator, CondBr);
}

InstructionCost VPBranchOnMaskRecipe::computeCost(ElementCount VF,
VPCostContext &Ctx) const {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some explanation for treating this branch as free.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added thanks!


InstructionCost VPSingleDefRecipe::computeCost(ElementCount VF,
VPCostContext &Ctx) const {
Instruction *UI = dyn_cast_or_null<Instruction>(getUnderlyingValue());
if (UI && isa<VPReplicateRecipe>(this)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that replicate recipes by definition must have a UI, so the latter can be asserted instead of checked.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thanks!

// Get the underlying instruction for the recipe, if there is one. Is is used
// to
// * decide if cost computation should be skipped for this recipe
// * apply forced target instr
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// * apply forced target instr
// * apply forced target instruction cost.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed thanks!

@fhahn fhahn merged commit fa3258e into llvm:main Oct 9, 2024
6 of 9 checks passed
@fhahn fhahn deleted the vplan-max-cost-sentinel branch October 9, 2024 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants