RFR: 8330274: C2 SuperWord: VPointer invar: same sum with different addition order should be equal

Emanuel Peter epeter at openjdk.org
Tue Apr 23 14:58:27 UTC 2024


On Mon, 22 Apr 2024 12:29:18 GMT, Roberto Castañeda Lozano <rcastanedalo at openjdk.org> wrote:

>> This is an enhancement for AutoVectorization.
>> 
>> I want to improve the detection of `invar`s that are equivalent (guaranteed to compute the same value), but don't have the identical node (the computation is in a different order).
>> 
>> Note: only about 100 lines are real changes, the rest is tests. These are the first tests that check vectorization for MemorySegments.
>> 
>> **Solution Sketch: "canonicalize" the invar**
>> 
>> - Extract all summands of the `invar`: make a list.
>>   - Parse through `AddL`, `SubL`, `AddI`, `SubI`, to get summands.
>>   - Bypass `CastLL` and `CastII`
>>   - Recursively treat `ConvI2L`, `LShiftI` and `LShiftL`: i.e. canonicalize their input.
>> 
>> - Sort all extracted summands by node idx.
>> - Add up all summands in new order.
>> 
>> If two `invar`s use the same summands, then we know that after canonicalization the new nodes representing the `invar`s must be the same.
>> 
>> **Example**
>> 
>> 
>> invar1 = b + c + d + a
>> invar2 = d + b + a + c
>> 
>> -> equivalent but not identical nodes
>> 
>> Sort, and add up again:
>> 
>> invar1 = a + b + c + d
>> invar2 = a + b + c + d
>> 
>> -> now the nodes are identical
>> 
>> **Motivation: MemorySegment with invar**
>> 
>> One might think that this is a big of a special case: why would anybody write indices to an Array or MemorySegment where the invar has a different addition order for its summands?
>> 
>> This example did not vectorize, even though it should:
>> https://github.com/openjdk/jdk/blob/78e42d6e311c33548d16c6c74493388d9850238e/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java#L425-L441
>> 
>> Both the `get` and the `set` look like they have the same address, and the address increases by a byte in each iteration.
>> 
>> Upon inspection, I saw that the `invar` that `VPointer` produces for the two operations are not identical: the order of addition of the `invar`'s summands is different, and thus the `invar` nodes are different.
>> 
>> The consequence: Only if we can prove that the two `invar` are identical can we know that the addresses are identical, and that there is no aliasing for loop carried dependencies. Since we have different `invar`, we don't know how the two addresses alias, and that prevents vectorization.
>> 
>> Why does this happen? After parsing, the graph looks like this:
>> ![image](https://github.com/openjdk/jdk/assets/32593061/f768d0b0-0b2f-48f0-bfdc-61e93e62bb4f)
>> 
>> We already see that the two addresses are different only by a `CastLL`, with type `long:>=0`. So...
>
> Fair enough, I agree that, even if there was a solution for this specific case, we would probably encounter other cases where GVN would not be powerful enough to detect the equivalence. I still wonder though what could be causing the `CastLL(invar + iv)` vs. `invar + iv` divergence in your example and whether anything could be done to get rid of it. Maybe worth filing a RFE for further investigation.

@robcasloz are you intending to review, or was that just a drive-by comment/question?

-------------

PR Comment: https://git.openjdk.org/jdk/pull/18795#issuecomment-2072578666


More information about the hotspot-compiler-dev mailing list