-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[VPlan] Introduces explicit broadcast for live-in constants. #133213
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1399,6 +1399,17 @@ class LLVM_ABI_FOR_TEST VPWidenRecipe : public VPRecipeWithIRFlags, | |
void print(raw_ostream &O, const Twine &Indent, | ||
VPSlotTracker &SlotTracker) const override; | ||
#endif | ||
|
||
bool onlyFirstLaneUsed(const VPValue *Op) const override { | ||
assert(is_contained(operands(), Op) && | ||
"Op must be an operand of the recipe"); | ||
switch (Opcode) { | ||
default: | ||
return false; | ||
case Instruction::ExtractValue: | ||
return Op == getOperand(1); | ||
Comment on lines
+1404
to
+1410
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simpler to check for the single opcode we are intersted in with an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, update in #145449. Thanks! |
||
} | ||
} | ||
}; | ||
|
||
/// VPWidenCastRecipe is a recipe to create vector cast instructions. | ||
|
@@ -1594,6 +1605,14 @@ class LLVM_ABI_FOR_TEST VPWidenCallRecipe : public VPRecipeWithIRFlags, | |
void print(raw_ostream &O, const Twine &Indent, | ||
VPSlotTracker &SlotTracker) const override; | ||
#endif | ||
|
||
/// Returns true if the recipe only uses the first lane of operand \p Op. | ||
bool onlyFirstLaneUsed(const VPValue *Op) const override { | ||
assert(is_contained(operands(), Op) && | ||
"Op must be an operand of the recipe"); | ||
// Scalar called fuction cannot be vectorized. | ||
return Op == getOperand(getNumOperands() - 1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understand correctly, the last operand is the called scalar function, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it is the function pointer of the scalar function. |
||
} | ||
}; | ||
|
||
/// A recipe representing a sequence of load -> update -> store as part of | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3193,10 +3193,7 @@ void VPlanTransforms::materializeBroadcasts(VPlan &Plan) { | |
|
||
auto *VectorPreheader = Plan.getVectorPreheader(); | ||
for (VPValue *VPV : VPValues) { | ||
if (all_of(VPV->users(), | ||
[VPV](VPUser *U) { return U->usesScalars(VPV); }) || | ||
(VPV->isLiveIn() && VPV->getLiveInIRValue() && | ||
isa<Constant>(VPV->getLiveInIRValue()))) | ||
if (all_of(VPV->users(), [VPV](VPUser *U) { return U->usesScalars(VPV); })) | ||
continue; | ||
|
||
// Add explicit broadcast at the insert point that dominates all users. | ||
|
@@ -3213,8 +3210,25 @@ void VPlanTransforms::materializeBroadcasts(VPlan &Plan) { | |
"All users must be in the vector preheader or dominated by it"); | ||
} | ||
|
||
VPBuilder Builder(cast<VPBasicBlock>(HoistBlock), HoistPoint); | ||
auto *Broadcast = Builder.createNaryOp(VPInstruction::Broadcast, {VPV}); | ||
VPInstruction *Broadcast; | ||
if (VPV->isLiveIn() && isa_and_nonnull<Constant>(VPV->getLiveInIRValue())) { | ||
// We cannot replace the constant live-ins for PHIs by broadcast in the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I understand the relevance of PHIs in this code, since nothing else in this function seems to use or create them? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because the broadcast of the constant live-ins are put in the same VPBB. Replace the live-in from predecessor by a broadcast in the same block will break the definition of the PHI. |
||
// same VPBB because it will break PHI. Also cannot replace the | ||
// VPWidenGEPRecipe since it broadcasts the generated pointer instead of | ||
// operands. | ||
if (auto *R = dyn_cast_if_present<VPRecipeBase>(*(VPV->users().begin())); | ||
R && !isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPWidenGEPRecipe>(R) && | ||
!VPV->hasMoreThanOneUniqueUser()) { | ||
Broadcast = new VPInstruction(VPInstruction::Broadcast, {VPV}); | ||
// Insert just before the user to reduce register pressure. | ||
Broadcast->insertBefore(R); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't there a problem here? It looks like you're assuming that the first user of VPV dominates all users of VPV, but I don't think that is always true. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For register pressure, if hoisting all of constant broadcast to the preheader, the register pressure will be high in the loop body. Probably need to limit all the user of the constant need to in the same BB. |
||
} else { | ||
continue; | ||
} | ||
} else { | ||
VPBuilder Builder(cast<VPBasicBlock>(HoistBlock), HoistPoint); | ||
Broadcast = Builder.createNaryOp(VPInstruction::Broadcast, {VPV}); | ||
} | ||
VPV->replaceUsesWithIf(Broadcast, | ||
[VPV, Broadcast](VPUser &U, unsigned Idx) { | ||
return Broadcast != &U && !U.usesScalars(VPV); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it's worth pulling the VPlan.h and VPlanRecipes.cpp changes out into a separate PR as they make sense on their own? That way we can see what test changes are due to which code changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Split off to #145449, thanks!