-
Notifications
You must be signed in to change notification settings - Fork 11.8k
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
[LICM][TBAA] LICM needlessly drops TBAA #53794
Comments
LICM drops some metadata after hoisting which may not be valid anymore in new location. |
This pattern appears quite common (as this originally arises in the context of a std::vector). In this context, I think preserving TBAA should always be correct, even after hoisting |
It is not legal to preserve TBAA on a speculatively executed load. LICM will preserve the metadata if the load is guaranteed to execute. In your particular example, the load may not be executed if |
@nikic This particular behavior presents a performance decay because of the stripped AA (hindering subsequent LICM, as an example). Consider the case here: https://godbolt.org/z/8v3bnhzY6 #include <vector>
void compute(std::vector<int> &data, unsigned long long numElems) {
for (unsigned long long i=0; i<100; i++) {
for (unsigned long long j=0; j<numElems; j++) {
data[j]++;
}
}
} LICM is first run before loop rotation and thus the inner load is speculative. Speculatively hoisting the load outside of the inner loop drops TBAA. This means the data pointer load can't be speculatively hoisted outside of the outer loop (and moreover the store into the data itself now appears to alias with the load of the data pointer due to the dropped TBAA). Allowing the load of the data pointer, and of the actual data to alias can make a significant performance impact. In contrast, first performing the rotation (making it non-speculative), succeeds at hoisting the data pointer out (though at this point it would still drop the TBAA): https://godbolt.org/z/a44crzPGx #include <vector>
void compute(std::vector<int> &data, unsigned long long numElems) {
for (unsigned long long i=0; i<100; i++) {
if (numElems > 0) {
for (unsigned long long j=0; ; j++) {
data[j]++;
if (j == numElems) break;
}
}
}
} At minimum this feels like we should always ensure LICM follows loop rotation, though I'd also be happy if we don't speculate loads with alias information. |
@wsmoses As a matter of general policy, we prefer doing optimizations that require dropping metadata or attributes over not doing them. This is obviously better on average, and avoids awkward situations where inferring more information in one place inhibits later optimizations. We're certainly not going to inhibit load hoisting to preserve TBAA. We can reconsider doing LICM before LoopRotate though. This is a recent change made in https://reviews.llvm.org/D99249, that is a win in some cases and a loss in others. You could probably present an argument that this is not the right tradeoff. |
Would it be reasonable to make the speculative instruction conditionally executed above the loop in a limited set of circumstances (and thus preserve metadata). The original code is complex because the condition is not loop-invariant, but suppose the speculation was due to a single loop-invariant condition, we could reproduce that outside the loop. The loop-dependent condition is a bit more tricky and would require the outside loop condition to be a "any of the inner conditions are true". |
Another less-intrusive option: Since we now run LICM both before and after Loop rotate, could we add an option to LICM to not speculatively hoist data that would drop information. Thus we could still run LICM prior to LoopRotate and see those benefits (while preserving information), and the "full" LICM run would still perform all of the speculative information. |
I don't think that would be a profitable transform. In fact, if you do that, SimplifyCFG is just going to speculate the load out the branch lateron and drop the metadata anyway. Keeping around control flow to preserve TBAA metadata will be non-profitable outside a few very special circumstances. |
I think this is principally viable. I would phrase this more generally in terms of only hoisting guaranteed-to-execute instructions, because any instructions that can be hoisted through speculation can also be speculated post-rotation. Though I think we'd be better off dropping the first LICM run than complicating things in this direction. I believe the specific problem it was intended to solve was later addressed by emitting necessary alignment attributes in clang. |
I'm okay with either approach, what do you recommend and how do we proceed? |
Drop LICM run before LoopRotate in pass manager? |
Added the speculative option in the PR here: https://reviews.llvm.org/D119965. |
…otate LICM will speculatively hoist code outside of loops. This requires removing information, like alias analysis (#53794), range information (https://bugs.llvm.org/show_bug.cgi?id=50550), among others. Prior to https://reviews.llvm.org/D99249 , LICM would only be run after LoopRotate. Running Loop Rotate prior to LICM prevents a instruction hoist from being speculative, if it was conditionally executed by the iteration (as is commonly emitted by clang and other frontends). Adding the additional LICM pass first, however, forces all of these instructions to be considered speculative, even if they are not speculative after LoopRotate. This destroys information, resulting in performance losses for discarding this additional information. This PR modifies LICM to accept a ``speculative'' parameter which allows LICM to be set to perform information-loss speculative hoists or not. Phase ordering is then modified to not perform the information-losing speculative hoists until after loop rotate is performed, preserving this additional information. Reviewed By: lebedev.ri Differential Revision: https://reviews.llvm.org/D119965
…otate LICM will speculatively hoist code outside of loops. This requires removing information, like alias analysis (llvm#53794), range information (https://bugs.llvm.org/show_bug.cgi?id=50550), among others. Prior to https://reviews.llvm.org/D99249 , LICM would only be run after LoopRotate. Running Loop Rotate prior to LICM prevents a instruction hoist from being speculative, if it was conditionally executed by the iteration (as is commonly emitted by clang and other frontends). Adding the additional LICM pass first, however, forces all of these instructions to be considered speculative, even if they are not speculative after LoopRotate. This destroys information, resulting in performance losses for discarding this additional information. This PR modifies LICM to accept a ``speculative'' parameter which allows LICM to be set to perform information-loss speculative hoists or not. Phase ordering is then modified to not perform the information-losing speculative hoists until after loop rotate is performed, preserving this additional information. Reviewed By: lebedev.ri Differential Revision: https://reviews.llvm.org/D119965 (cherry picked from commit d9da6a5)
…otate LICM will speculatively hoist code outside of loops. This requires removing information, like alias analysis (#53794), range information (https://bugs.llvm.org/show_bug.cgi?id=50550), among others. Prior to https://reviews.llvm.org/D99249 , LICM would only be run after LoopRotate. Running Loop Rotate prior to LICM prevents a instruction hoist from being speculative, if it was conditionally executed by the iteration (as is commonly emitted by clang and other frontends). Adding the additional LICM pass first, however, forces all of these instructions to be considered speculative, even if they are not speculative after LoopRotate. This destroys information, resulting in performance losses for discarding this additional information. This PR modifies LICM to accept a ``speculative'' parameter which allows LICM to be set to perform information-loss speculative hoists or not. Phase ordering is then modified to not perform the information-losing speculative hoists until after loop rotate is performed, preserving this additional information. Reviewed By: lebedev.ri Differential Revision: https://reviews.llvm.org/D119965 (cherry picked from commit d9da6a5)
…otate LICM will speculatively hoist code outside of loops. This requires removing information, like alias analysis (llvm/llvm-project#53794), range information (https://bugs.llvm.org/show_bug.cgi?id=50550), among others. Prior to https://reviews.llvm.org/D99249 , LICM would only be run after LoopRotate. Running Loop Rotate prior to LICM prevents a instruction hoist from being speculative, if it was conditionally executed by the iteration (as is commonly emitted by clang and other frontends). Adding the additional LICM pass first, however, forces all of these instructions to be considered speculative, even if they are not speculative after LoopRotate. This destroys information, resulting in performance losses for discarding this additional information. This PR modifies LICM to accept a ``speculative'' parameter which allows LICM to be set to perform information-loss speculative hoists or not. Phase ordering is then modified to not perform the information-losing speculative hoists until after loop rotate is performed, preserving this additional information. Reviewed By: lebedev.ri Differential Revision: https://reviews.llvm.org/D119965
See: https://godbolt.org/z/bcj3zEz7P
When the %0 load is hoisted, it no longer has TBAA:
The text was updated successfully, but these errors were encountered: