This allows cast/dyn_cast'ing from VPUser to recipes. This is needed
because there are VPUsers that are not recipes.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
llvm/lib/Transforms/Vectorize/VPlan.h | ||
---|---|---|
720 | Can we make getVPUserID() protected instead of friendship above? | |
llvm/lib/Transforms/Vectorize/VPlanValue.h | ||
279 |
|
Add comment about the Other ID type, making clear that currently there are VPUsers in VPBlockBase, but in the future Other should only be used for live-outs.
llvm/lib/Transforms/Vectorize/VPlan.h | ||
---|---|---|
720 | Unfortunately I don't think so. If it's protected, we can access it from inside a VPRecipeBase object, but here we need to access it from a VPUser pointer directly. | |
llvm/lib/Transforms/Vectorize/VPlanValue.h | ||
279 |
It's just to prevent accidental growth, but it is not strictly necessary (and we don't have static asserts for other sizes yet), but it is a common pattern, e.g. in various key classes in Clang to prevent unnoticed size growth.
I think 48 should be the upper bound on 64 bit platforms (unless there are differences caused by different 64 bit operating systems) and on 32-bit platforms it should be less than or equal. |
LGTM.
llvm/lib/Transforms/Vectorize/VPlan.h | ||
---|---|---|
720 | I'd rather make the enum/method public then, but it's very subjective. |
Non-recipe "other" VPUsers are quite exceptional ... would it suffice to have (native) VPlan hold all 'dangling' non-recipe VPUsers of its VPBasicBlocks, as an alternative, until these are cleaned up?
The blocks need to use the VPUsers to access the current value they hold I think, so I am not sure how the VPlan holding the VPUsers would look like unfortunately. It would be great if you could elaborate in a bit more detail, in case I am missing something.
The blocks will still have their VPUsers (in native; until this gets cleaned up). The thought is that whoever needs to distinguish between a block'd VPUser and a recipe'd one, would do so by consulting VPlan, rather than isa-ing the VPUser.
Oh I see what you mean now, thanks! That sounds like a viable alternative.
IIUC we will have non-recipe users in the future (e.g. live-outs) so I think we need to be able to make this distinction in the future as well, once the current VPUsers in the native path get cleaned up. If that's true, I think having to consult a VPlan to check what type of user we are dealing with seems a bit clunky in the long term (and breaks with the common pattern used for other VP* classes and other places in LLVM). Unless we anticipate a more fine-grained distinction between VPUsers in the future, we could also just use a boolean flag instead of the enum, to make it less appealing to add new VPUser types.
If we don't anticipate having to distinguish between recipe and non-recipe VPUsers in the future, then I think using a map in the plan directly makes a lot of sense (and in that case we might want to get rid of the separate VPUser class completely?)
IIUC we will have non-recipe users in the future (e.g. live-outs)
Not making a request or committing to implement myself in near future, but can we model live-outs as a recipe as well? I'm thinking about something like vplan-ret %val0, %val1, %val2 that would have VPValues as operands and corresponding llvm::Uses inside itself (like shufflevector contains mask argument or `PHINode' contains incoming blocks.
The anticipated long-term need for non-recipe VPUsers is indeed to represent live-outs, along with their underlying IR Value, or rather Instruction; analogous to VPValue::getLiveInIRValue(). This would call for a derived VPLiveOut non-recipe subclass of VPUser.
VPUser class itself should probably be pure virtual, similar to User, to avoid having a potential kitchen sink of dangling opaque instances. Instead of representing arbitrary "other"/"non-recipe" instances, the current VPUsers of VPBasicBlock predicates and conditions could be represented as specific, concrete subclasses of VPUser, potentially until they are cleaned up. WDYT?
llvm/lib/Transforms/Vectorize/VPlanValue.h | ||
---|---|---|
214 | Do we have to have a default constructor? If so, shouldn't the default ID be Other? |
Rebased and addressed comments:
- Turn VPUser into a pure virtual class.
- Add VPBlockUser, move update logic to that class
- Remove default values for ID in constructors.
- Remove default constructor.
Thanks, I updated the code to turn VPUser in a virtual base class and added s subclass for the uses in VPBlockBase. WDYT?
(For now I used a dummy function VPUser::makeVPUserVirtual to turn VPUser into a pure virtual class. Not sure if there's a different way?)
Thanks, I updated the code to turn VPUser in a virtual base class and added s subclass for the uses in VPBlockBase. WDYT?
Looks good!
(For now I used a dummy function VPUser::makeVPUserVirtual to turn VPUser into a pure virtual class. Not sure if there's a different way?)
Wouldn't making the constructors protected suffice?
llvm/lib/Transforms/Vectorize/VPlan.h | ||
---|---|---|
720 |
+1 |
llvm/lib/Transforms/Vectorize/VPlanValue.h | ||
---|---|---|
279 | This seems a bit premature. Perhaps better to have this discussion separate of this patch. |
Update to make getVPUserID() and the ID enum public, make constructors protected and remove static assert.
Yeah, I guess we do not need it to be pure virtual, updated!
llvm/lib/Transforms/Vectorize/VPlan.h | ||
---|---|---|
720 | I don't mind either way, I made it public. But this has the dis-advantage that the IDs themselves are exposed to users, which should never use them. Probably not a very big deal though. | |
llvm/lib/Transforms/Vectorize/VPlanValue.h | ||
279 | It is just an extra guard which make unintended size changes visible (similar to other places in LLVM/Clang), but it can be a separate patch. I removed it for now. |
@gilr I think your comments should be addressed and I am planning land this in the next few days, unless there are any additional comments :)
Can we make getVPUserID() protected instead of friendship above?