RFR: 8324751: C2 SuperWord: Aliasing Analysis runtime check [v11]
Vladimir Kozlov
kvn at openjdk.org
Sun Aug 17 22:55:24 UTC 2025
On Thu, 14 Aug 2025 14:35:53 GMT, Emanuel Peter <epeter at openjdk.org> wrote:
>> This is a big patch, but about 3.5k lines are tests. And a large part of the VM changes is comments / proofs.
>>
>> I am adding a dynamic (runtime) aliasing check to the auto-vectorizer (SuperWord). We use the infrastructure from https://github.com/openjdk/jdk/pull/22016:
>> - Use the auto-vectorization `predicate` when available: we speculate that there is no aliasing, else we trap and re-compile without the predicate.
>> - If the predicate is not available, we use `multiversioning`, i.e. we have a `fast_loop` where there is no aliasing, and hence vectorization. And a `slow_loop` if the check fails, with no vectorization.
>>
>> --------------------------
>>
>> **Where to start reviewing**
>>
>> - `src/hotspot/share/opto/mempointer.hpp`:
>> - Read the class comment for `MemPointerRawSummand`.
>> - Familiarize yourself with the `MemPointer Linearity Corrolary`. We need it for the proofs of the aliasing runtime checks.
>>
>> - `src/hotspot/share/opto/vectorization.cpp`:
>> - Read the explanations and proofs above `VPointer::can_make_speculative_aliasing_check_with`. It explains how the aliasing runtime check works.
>>
>> - `src/hotspot/share/opto/vtransform.hpp`:
>> - Understand the difference between weak and strong edges.
>>
>> If you need to see some examples, then look at the tests:
>> - `test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java`: simple array cases. IR rules that check for vectors and in somecases if we used multiversioning.
>> - `test/micro/org/openjdk/bench/vm/compiler/VectorAliasing.java`: the miro-benchmarks I show below. Simple array cases.
>> - `test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentAliasing.java`: a bit advanced, but similar cases.
>> - `test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingFuzzer.java`: very large and rather compliex. Generates random loops, some with and some without aliasing at runtime. IR verification, but mostly currently only for array cases, MemorySegment cases have some issues (see comments).
>> --------------------------
>>
>> **Details**
>>
>> Most fundamentally:
>> - I had to refactor / extend `MemPointer` so that we have access to `MemPointerRawSummand`s.
>> - These raw summands us to reconstruct the `VPointer` at any `iv` value with `VPointer::make_pointer_expression(Node* iv_value)`.
>> - With the raw summands, a pointer may look like this: `p = base + ConvI2L(x + 2) + ConvI2L(y + 2)`
>> - With "regular" summands, this gets simplified to `p = base + 4L +ConvI2L(x) + Conv...
>
> Emanuel Peter has updated the pull request incrementally with one additional commit since the last revision:
>
> more documentation for Christian
I have few comments
src/hotspot/share/opto/c2_globals.hpp line 367:
> 365: \
> 366: product(bool, UseAutoVectorizationPredicate, true, DIAGNOSTIC, \
> 367: "Use AutoVectorization predicate (for speculative compilation)") \
I do not see benchmarks results with this flag off.
src/hotspot/share/opto/c2_globals.hpp line 370:
> 368: \
> 369: product(bool, UseAutoVectorizationSpeculativeAliasingChecks, true, DIAGNOSTIC, \
> 370: "Use Multiversioning or Predicate to add aliasing runtime checks") \
This flag description implies that it should depend on `LoopMultiversioning` and `UseAutoVectorizationPredicate` flags settings but I did not find such checks.
src/hotspot/share/opto/loopUnswitch.cpp line 569:
> 567: // optimizations. That means the slow_loop should still be correct, but
> 568: // a bit slower, as there is no unrolling etc.
> 569: if (!LoopMultiversioningOptimizeSlowLoop) {
Do we really need this in product? Your benchmarks results shows that we need to optimize slow loop. I can bet nobody will use this flag in real word.
src/hotspot/share/opto/mempointer.hpp line 403:
> 401: // Given:
> 402: // (C0) pointer p and its MemPointer mp, which is constructed with safe decompositions.
> 403: // (C1) a summand "scale_v * v" that occurs in mp.
What is `v` here? And related `scale_v`? In previous text you used `scale_i * variable_i`. Is it the same.
src/hotspot/share/opto/mempointer.hpp line 404:
> 402: // (C0) pointer p and its MemPointer mp, which is constructed with safe decompositions.
> 403: // (C1) a summand "scale_v * v" that occurs in mp.
> 404: // (C2) a strided range r = [lo, lo + stride_v, .. hi] for v.
If `hi` inclusive or exclusive?
src/hotspot/share/opto/mempointer.hpp line 406:
> 404: // (C2) a strided range r = [lo, lo + stride_v, .. hi] for v.
> 405: // (C3) for all v in this strided range r we know that p is within bounds of its memory object.
> 406: // (C4) abs(scale_v * stride_v) < 2^31.
(C4) Is confusing if you read it first. But late I see `mp(v1) = mp(v0) + scale_v * stride_v` expression and now I know why you need this.
src/hotspot/share/opto/mempointer.hpp line 444:
> 442: // = summand_rest + scale_v * (v0 + stride_v) + con
> 443: // = summand_rest + scale_v * v0 + scale_v * stride_v + con
> 444: // = summand_rest + scale_v * v0 + scale_v * stride_v + con
the same 2 lines
src/hotspot/share/opto/mempointer.hpp line 674:
> 672: // to be as simple as possible. For example, the pointer:
> 673: //
> 674: // pointer = base + 2L * ConvI2L(i + 4 * j + con1) + con2
Is this `MemPointerRawSummand` form?
src/hotspot/share/opto/predicates.hpp line 48:
> 46: * above which Regular Predicates can be created later after parsing.
> 47: *
> 48: * There are initially four Parse Predicates for each loop:
You listed 5 parse predicates
src/hotspot/share/opto/vectorization.cpp line 491:
> 489: // any iv value in the strided range r = [init, init + iv_stride, .. limit).
> 490: //
> 491: // for all iv in r: p1(iv) + size1 <= p2(iv) OR p2(iv) + size2 <= p1(iv)
What are `size*` ?
src/hotspot/share/opto/vectorization.cpp line 515:
> 513: // pointer p:
> 514: // (C0) is given by the construction of VPointer vp, which simply wraps a MemPointer mp.
> 515: // (c1) with v = iv and scale_v = iv_scale
You have explanation here but not in `mempointer.hpp`
-------------
PR Review: https://git.openjdk.org/jdk/pull/24278#pullrequestreview-3126462478
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281025986
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281025783
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281021994
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281030830
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281035285
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281036905
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281040501
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281043402
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281045284
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281048563
PR Review Comment: https://git.openjdk.org/jdk/pull/24278#discussion_r2281047772
More information about the hotspot-compiler-dev
mailing list