If inner loop is loop independent or doesn't carry any dependency then, loop interchange is not profitable. Also if outer loop is not loop independent then, loop interchange is not profitable. if inner loop has dependence and outer loop is loop independent then, it is profitable to interchange to enable inner loop parallelism. Corrected the dependency checking inside isProfitableForVectorization(). Also addresses the endless interchange problem. If Cache analysis could decide the loop order then, isProfitable will not invoke isProfitableForVectorization for decidinding better loop interchange.
Details
- Reviewers
fhahn congzhe Meinersbur bmahjour - Group Reviewers
Restricted Project - Commits
- rGee7188c8b2ab: [LoopInterchange] Correcting the profitability check
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
1100–1101 | Does you patch cover this TODO? | |
1100–1101 | Shouldn't the condition on Row[InnerLoopId] and Row[OuterLoopId] be exact opposite? That is, it is profitable if the innermost loop has loop-carried dependencies while the outer has not? | |
1125–1137 | Should this only be considered if InnerLoopId is actually an innermost loop (The only kind LoopVectorize can currently process)? |
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
1100–1101 | Corrected the dependency checking and corrected the comments. | |
1100–1101 | Corrected the dependency check. If inner loop has loop carried dependency and outer loop is loop independent then, loop interchange is considered as profitable for vectorization. |
llvm/test/Transforms/LoopInterchange/pr43797-lcssa-for-multiple-outer-loop-blocks.ll | ||
---|---|---|
11 ↗ | (On Diff #467235) | These changes are not needed after correcting the dependency check in loop interchange. |
Following changes are made as per the comments. If inner loop is loop independent or doesn't carry any dependency then, loop interchange is not considered as profitable. Also if outer loop is not loop independent then, loop interchange is not considered as profitable. If inner loop has dependence and outer loop is loop independent then, it is profitable to interchange to enable inner loop parallelism.
@Meinersbur and @bmahjour, Could you get the chance to review the code I modified as per your comment?
This looks better now, but the problem of "endless interchange" is still not addressed. Per discussion in the loop opt call, we should only use CacheCost when it was able to calculate a valid cost and the loops can be sorted based on "strictly less than" ordering relationship. Only when CacheCost result is indeterminate (eg. two loops have equal cost) or when it is unable to calculate the cost (eg. due to delinearization issues), we should fall back to the isProfitableForVectorization() function.
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
1105 | not not -> not |
This looks better now, but the problem of "endless interchange" is still not addressed. Per discussion in the loop opt call, we should only use CacheCost when it was able to calculate a valid cost and the loops can be sorted based on "strictly less than" ordering relationship. Only when CacheCost result is indeterminate (eg. two loops have equal cost) or when it is unable to calculate the cost (eg. due to delinearization issues), we should fall back to the isProfitableForVectorization() function.
Corrected the "endless interchange" possibility. Now isProfitableForVectorization() only invokes when two loops have equal cost or it is unable to calculate the cost.
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
1105 | corrected |
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
1141 |
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
1138–1139 | Consider updating this message. Suggestion: "Interchanging loops not considered to improve cache locality nor vectorization." | |
1141 | This is exactly the else branch of the cache analysis logic. It does not consider the fallback Cost < -LoopInterchangeCostThreshold legacy cost model. Please avoid the code duplication and needing to loop up the CostMap again. |
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
1115–1121 | The structure suggested in the LoopWG call. The more general pattern/refactoring would be: std::optional<bool> shouldInterchange = isProfitableAccordingLoopCacheAnalysis(..); if (shouldInterchange.has_value()) return shouldInterchange.get_value(); shouldInterchange = isProfitableAccordingInstrOrderCost(..); if (shouldInterchange.has_value()) return shouldInterchange.get_value(); shouldInterchange = isProfitableForVectorization(..); if (shouldInterchange.has_value()) return shouldInterchange.get_value(); emitOptimizationRemark("Don't know"); However, this changes when the emitOptimizationRemark is called. If we would not want to change this, it would be (which corresponds to the current structure but with refactoring): std::optional<bool> shouldInterchange = isProfitableAccordingLoopCacheAnalysis(..); if (!shouldInterchange.has_value()) { shouldInterchange = isProfitableAccordingInstrOrderCost(..); if (!shouldInterchange.has_value()) { shouldInterchange = isProfitableForVectorization(..); } } if (!shouldInterchange.has_value()) emitOptimizationRemark("Don't know"); else if (!shouldInterchange.get_value()) emitOptimizationRemark("Profitability heuristic indicates this loop is good as-is"); although I would prefer the former over the nested if-else chain and instead emit different optimization remarks for each of the heuristic that indicates that/why the loops should (NOT) be interchanged. |
As per the Michael 's comments. Code inside isProfitable function is cleaned.
Added test case. With two loop interchange passes make sure that, there is no endless interchange. Before this patch there is endless loop interchange possibility. There is no endless interchange after this patch.
I would suggest to revise the summary and/or the title to describe that this patch now also addresses the endless interchange problem, in addition to correction in isProfitableForVectorization().
llvm/test/Transforms/LoopInterchange/profitability.ll | ||
---|---|---|
179 | I would suggest to apply --check-prefix=PROFIT only to interchange_05() and not to other existing tests. Because this opt command line runs interchange twice and shows that there would have been endless interchange with interchange_05() before this patch but there is no endless interchange after this patch, which applies only to interchange_05() and is not related to other tests. |
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
1133 | Is it possible to make LoopInterchangeCostMeaningfulnessThreshold an opt flag so we can assign its value more flexibly? Possibly rename it to LegacyCostModelThreshold or whatever is more appropriate. static cl::opt<int> LegacyCostModelThreshold( "legacy-cost-threshold", cl::init(10), cl::Hidden, cl::desc("The threshold for the legacy cost model to be considered.")); |
Added comments in Test case 05 for better understanding.
Corrected the comment in Test case 01. The loop interchange decision is made from the Cache cost analysis and is not from vectorization.
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
1101–1104 | nit: isProfitableAccordingToLoopCacheAnalysis, or isProfitablePerLoopCacheAnalysis | |
1126–1137 | nit: isProfitableAccordingToInstrOrderCost, or isProfitablePerInstrOrderCost | |
1168 | It could be worth adding some comments for this function that describe what it does now, and how it prevents endless interchange from happening. | |
llvm/test/Transforms/LoopInterchange/profitability.ll | ||
175 | nit: may leads->may lead |
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
64 | I don't see why we need two options to control the legacy cost model. | |
1117 | We should return nullopt when/if InnerIndex == OuterIndex | |
1146 | since the idea is to call this function only when CC has failed or been indecisive, we don't need to pass CC to this function and check it here. | |
llvm/test/Transforms/LoopInterchange/profitability.ll | ||
171–176 | reword: This tests to make sure, that multiple invocations of loop interchange will not undo previous interchange and will converge to a particular order determined by the profitability analysis. |
llvm/lib/Transforms/Scalar/LoopInterchange.cpp | ||
---|---|---|
64 | This new parameter added as per @Meinersbur comments in Inline. This is considered as the upper limit of InstrOrderCost. | |
1117 | The CostMap is assigned with unique number to each loop. So this condition "InnerIndex == OuterIndex" will not satisfy. But LoopCost may be same, CC->getLoopCost(*InnerLoop) == CC->getLoopCost(*OuterLoop) checking can be added for returning nullopt. |
perserve-lcssa.ll corrected, Instruction order cost is 0, Not profitable to interchange.
loop-interchange-optimization-remarks.ll remark message corrected.
All comments are updated.
Hi @bmahjour, Changes are made as per your comments. Could you get the time to review it.
Hi @Meinersbur, Some changes are done over your suggested comments (https://reviews.llvm.org/D135808?id=474010#inline-1332682)
LGTM.
Sorry I didn't find time to review it.
llvm/test/Transforms/LoopInterchange/perserve-lcssa.ll | ||
---|---|---|
172 | The test fails for me with the latest version because of opaque pointers emitted by opt. Regeneration of the test should fix this. |