8387073: C2: StoreNode::Ideal wrongly optimizes away scalar store before masked vector store#31695
8387073: C2: StoreNode::Ideal wrongly optimizes away scalar store before masked vector store#31695mhaessig wants to merge 3 commits into
Conversation
|
👋 Welcome back mhaessig! A progress list of the required criteria for merging this PR into |
|
❗ This change is not yet ready to be integrated. |
|
The total number of required reviews for this PR has been set to 2 based on the presence of this label: |
Webrevs
|
11644fc to
28eab9b
Compare
chhagedorn
left a comment
There was a problem hiding this comment.
That looks reasonable to me. Have you already filed a follow-up RFE to revisit it in JDK 28?
| st->as_Store()->memory_size() <= this->memory_size()) { | ||
| st->as_Store()->memory_size() <= this->memory_size() && | ||
| !this->is_StoreVectorMasked() && !this->is_StoreVectorScatterMasked() && | ||
| !this->is_predicated_vector()) { |
There was a problem hiding this comment.
Is is_predicated_vector actually required here? Or could it be an assert?
| static boolean[] boolArr = new boolean[] {true, true}; | ||
| static byte[] byteArr = new byte[] {(byte)42}; | ||
|
|
||
| static boolean[] testBool() { | ||
| return Arrays.copyOf(boolArr, 4); | ||
| } | ||
|
|
||
| static byte[] testByte() { | ||
| // Should be zero-padded, but we seem to get non-zero values. | ||
| return Arrays.copyOf(byteArr, 4); | ||
| } |
There was a problem hiding this comment.
It would be nice if we could have a bit more testing in this area.
I was super surprised that we have not caught this earlier.
Idea: look for similar methods, and test them all for random arrays and lengths (constant and variable).
There was a problem hiding this comment.
Also: maybe more types, including oop?
| final List<TemplateToken> tests = new ArrayList<>(); | ||
| tests.addAll(CodeGenerationDataNameType.VECTOR_VECTOR_TYPES | ||
| .stream() | ||
| .filter(vec -> vec.byteSize() <= maxVecByteSize) |
There was a problem hiding this comment.
Why do you do this filtering? At least a comment would be nice ;)
There was a problem hiding this comment.
What I would recommend: guard the IR rules instead, using MaxVectorSize. That would allow us to still do result verification for the other cases.
|
|
||
| if (st->in(MemNode::Address)->eqv_uncast(address) && | ||
| st->as_Store()->memory_size() <= this->memory_size()) { | ||
| st->as_Store()->memory_size() <= this->memory_size() && |
There was a problem hiding this comment.
Optional: Can you also file an RFE to allow overlaps that don't require the address to be the same?
Neither of us probably has time, but I think we could probably find someone for it in the wider community ;)
| // For IR-verification we need more than two lanes. To prevent flakyness, we skip verification | ||
| // for vectors of longs because there are other StoreL nodes in this method. | ||
| if (vec.length <= 2 || vec.elementType.name().equals("long")) { | ||
| return scope(""); | ||
| } |
There was a problem hiding this comment.
Could we get the IR matching to be "sharper" by matching more parts of the dump string, somehow?
| // IR verification of vectors of int needs special handling due to an additional | ||
| // node in used for address computation when not using COH. | ||
| if (vec.elementType.name().equals("int")) { | ||
| return scope( | ||
| let("ptyIR", ptyIR), | ||
| """ | ||
| @IR(counts = {IRNode.STORE_#ptyIR, "= 1", | ||
| IRNode.VECTOR_STORE_MASK, "= 1"}, | ||
| applyIf = {"UseCompactObjectHeaders", "true"}, | ||
| applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) | ||
| @IR(counts = {IRNode.STORE_#ptyIR, "= 2", | ||
| IRNode.VECTOR_STORE_MASK, "= 1"}, | ||
| applyIf = {"UseCompactObjectHeaders", "false"}, | ||
| applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) | ||
| """ | ||
| ); | ||
| } |
There was a problem hiding this comment.
Can you explain the IR shapes a bit more here? What exactly makes the difference why we end up with one or two stores?
| // Mask with one element set to false. | ||
| VectorMask<#boxedTy> mask = VectorMask.fromLong(#species, -1 - (1 << #idx)); |
There was a problem hiding this comment.
Having a completely random mask would also be nice, no? Or does that mess with something?
There was a problem hiding this comment.
Maybe you need it to not constant fold away? I suppose we could also try with a local constant mask, and a mask that gets loaded from somewhere, i.e. a static field. To both cover possible constant folding and variable mask.
| var v = #vecTy.broadcast(#species, broadcastVal); | ||
| v.intoArray(a, 0, mask); |
There was a problem hiding this comment.
Do you know why this is needed? I did not spend enough time on it when I found the reproducer. But it seems a bit strange to me.
StoreNode::Ideal()optimizes back-to-back stores to the same address by removing the earlier store if it is the same size or narrower than the later store when we haveUseAVX >= 3orUseSVE > 0. This optimization is incorrect if the later store is a masked vector store as it might not overwrite all bits of the preceding store.This PR fixes this issue by plainly disabling the optimization for masked stores. We could conceivably enable the optimization for masked stores if we can prove that the mask overwrites all of the preceding store, but this fix is aimed at correctness before the 27 release. Thus, such optimizations are filed as follow-up RFEs.
Testing:
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/31695/head:pull/31695$ git checkout pull/31695Update a local copy of the PR:
$ git checkout pull/31695$ git pull https://git.openjdk.org/jdk.git pull/31695/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 31695View PR using the GUI difftool:
$ git pr show -t 31695Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/31695.diff
Using Webrev
Link to Webrev Comment