8316679: C2 SuperWord: wrong result, load should not be moved before store if not comparable#15864
8316679: C2 SuperWord: wrong result, load should not be moved before store if not comparable#15864eme64 wants to merge 8 commits intoopenjdk:masterfrom
Conversation
…store if not comparable
|
👋 Welcome back epeter! A progress list of the required criteria for merging this PR into |
Webrevs
|
|
@eme64 This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be: You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been no new commits pushed to the ➡️ To integrate this PR with the above commit message to the |
|
Thank you for detailed explanation. |
|
@vnkozlov The issue with knowing if different array references can alias (if they are the same) is something that is currently not implemented for SuperWord. But it could theoretically be solved outside of SuperWord, by putting them on separate memory slices. I think this is definately a separate RFE and would not just benefit SuperWord. Alternatively, we could do special logic inside SuperWord, determining if references can be proven not to be the same. Or even specualte / trap. The last one would be powerful, and probably the most beneficial in general. In most cases different array references are actually different arrays, but we cannot know that at compile time, because they are for example two arguments to a method. |
|
I like the idea to add loop predicate to check arrays difference. It can be folded by compiler based on EA analysis: we were talking for long time to add instance ID for not global escaping arrays regardless their size. And yes, we can do that outside SuperWord. |
TobiHartmann
left a comment
There was a problem hiding this comment.
Thanks for the nice summary. The fix looks good to me.
| * @test | ||
| * @requires vm.compiler2.enabled | ||
| * @bug 8316679 | ||
| * @summary In SuperWord::output, LoadVector can be moved before StoreVector, but only if it is proven to be safe. |
There was a problem hiding this comment.
The test should have @key randomness
| b[inv + i + 0]++; | ||
| b[inv + i + 1]++; | ||
| b[inv + i + 2]++; | ||
| b[inv + i + 3]++; |
There was a problem hiding this comment.
You might want to remove the extra whitespaces in the index expressions.
|
Thanks @TobiHartmann @vnkozlov for the reviews! |
|
Going to push as commit 48f1a92.
Your commit was automatically rebased without conflicts. |
Context
In
SuperWord::output, we replace the scalars with vectors, pack by pack.In JDK-8052081 (changeset) we added an optimization to move the memory state of a LoadVector as early as possible. We go up the memory chain, and skip any
StoreVectorthat provably can never alias with theLoadVector(provably no overlap).Details
For this, we must understand the following function
VPointer::cmp:jdk/src/hotspot/share/opto/vectorization.hpp
Lines 110 to 120 in 96781ba
We have 4 possible states:
NotComparablemeans that we cannot determine the relative offsets between the two memory addresses. We have no guarantee about aliasing at all.Lessmeans that one address lies before the other,Greatermeans that it comes after.Equalmeans that the two memory regions have an overlap or are identical. To determine overlap, we must know the position of the pointer, as well as thememory_sizeof each memory reference.VPointer::not_equalis true iff we get statesLessorGreater(we know there cannot be overlap).VPointer::comparableis true iff the state isNotComparable, hence we have no guarantee about aliasing.Problem
Currently, there are 2 bugs in this "move-load-before-store" logic:
not_equalbut also the!comparablecase. However, when the two pointers are not comparable, that could be due to different invariants for example (seeTestMovingLoadBeforeStore.java). The two pointers are not comparable, because we do not know the relative position, due to the invariants. But this exactly means that we cannot know at compile-time that there will not be aliasing. Thus, we cannot allow moving a load before such a store. Otherwise we may get wrong results. (*)StoreVector. This is not correct, we need to compare all elements of the load-pack with theStoreVector. Otherwise it may be that the first element lays below/before the memory region of theStoreVector(Less), but the last element of the load-pack for example could have overlap with theStoreVector(Equal).We could fix both issues at once. But I am fixing them separately, first JDK-8316679, which can be backported to JDK-11, and then JDK-8316594 which only seems to have caused regressions in JDK-22.
Testing
I added correpsonding regression tests.
Tier1-6 + stress-testing.
Performance testing.
(*) We also use
!not_equalinSuperWord::dependence_graphto determine if two memrefs need to have a dependency edge. The condition there and the condition here (for move-load-before-store) should be equivalent.jdk/src/hotspot/share/opto/superword.cpp
Lines 1112 to 1116 in 96781ba
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/15864/head:pull/15864$ git checkout pull/15864Update a local copy of the PR:
$ git checkout pull/15864$ git pull https://git.openjdk.org/jdk.git pull/15864/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 15864View PR using the GUI difftool:
$ git pr show -t 15864Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/15864.diff
Webrev
Link to Webrev Comment