This is an archive of the discontinued LLVM Phabricator instance.

[NaryReassociate] Use new access type aware getGEPCost
Needs ReviewPublic

Authored by luke on Jul 21 2023, 8:00 AM.

Details

Summary

This was originally split out from D149889: Now that getGEPCost can more
accurately determine when an GEP will be folded, this patch updates
NaryReassociate to take advantage of it.
Unfortunately I wasn't able to create a test case for this where the GEP was
both foldable and reassociatable. Actually I couldn't find any instances of
this branch being taken since most targets can't fold more than a reg+reg add.
But posting this patch anyway for completeness sake.

Diff Detail

Event Timeline

luke created this revision.Jul 21 2023, 8:00 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 21 2023, 8:00 AM
luke requested review of this revision.Jul 21 2023, 8:00 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 21 2023, 8:00 AM

This seems fine, but I don't know the code well enough to approve it

ebrevnov added inline comments.Aug 3 2023, 2:39 AM
llvm/include/llvm/Analysis/TargetTransformInfo.h
302

"for using getGEPCost" sounds a bit odd... maybe better say "// Helper function to get cost of already materialized GEP instruction"?

llvm/lib/Analysis/TargetTransformInfo.cpp
243

I don't think it's a good idea to have one more place where we define default value for AccessType. Especially taking into account it's incompatible with existing ones. The problem I see is that AccessType will be defaulted to different values depending on particular API used. It's unexpected to get different results depending if getInstructionCost or getGEPCost is used.

I believe we should leave a single place (inside TargetTransformInfoImplCRTPBase::getGEPCost) where default is selected.

llvm/lib/Transforms/Scalar/NaryReassociate.cpp
331

It seems to be possible to simplify all other existing calls to getGEPCost the same way. Are you going to fix them as well?

luke added inline comments.Aug 3 2023, 7:01 AM
llvm/lib/Analysis/TargetTransformInfo.cpp
243

Unfortunately we lose access to the GEP's users in TargetTransformInfoImplCRTPBase::getGEPCost, since it works on operands and not the GEP itself, so I'm not sure if we can calculate the default there.

It's unexpected to get different results depending if getInstructionCost or getGEPCost is used.

getInstructionCost actually duplicates this "check first user" logic, but I agree, it's annoying to have this code duplication. IIRC I ended up duplicating it because there was no easy way to call TargetTransformInfo::getGEPCost from inside TargetTransformInfoImplCRTPBase.

Maybe we could rejig this helper function to something like getGEPUserAccessType, which would then be used like getGEPCost(GEP->getSourceElementType(), GEP->getPointerOperand(), Ops, getGEPUserAccessType(GEP), CostKind);

llvm/lib/Transforms/Scalar/NaryReassociate.cpp
331

Ideally yes, there's at least one other place in NaryReassociate that I'm aware of. I was planning on leaving that to a separate patch

ebrevnov added inline comments.Aug 4 2023, 1:01 AM
llvm/lib/Analysis/TargetTransformInfo.cpp
243

Unfortunately we lose access to the GEP's users in TargetTransformInfoImplCRTPBase::getGEPCost, since it works on operands and not the GEP itself, so I'm not sure if we can calculate the default there.

Ok, I see.

getInstructionCost actually duplicates this "check first user" logic, but I agree, it's annoying to have this code duplication.

It's not quite true. getInstructionCost will use default if there is a single user while getGEPCost if there is at least one user.

Maybe we could rejig this helper function to something like getGEPUserAccessType, which would then be used like getGEPCost(GEP->getSourceElementType(), GEP->getPointerOperand(), Ops, getGEPUserAccessType(GEP), CostKind);

Thinking out it a bit more I find the idea of choosing AccessType implicitly inside TTI problematic. Even if the GEP itself is materialized it's really implementation specific if its users have been already updated or not. For that reason I think the best would be to take AccessType into account only if it is given and don't guess.

I understand having getGEPCost which takes GEP is convenient but extending TTI's API with new interfaces with complex interdependencies is error prune (due to type erased nature of TTI) . Probably the easiest solution would be to simply pass all args each time (as it's done now) or introduce say getFullyMaterializedGEPCost utility somewhere else (not inside TTI).