On Mon, 29 Jun 2026 12:56:17 GMT, Andrew Haley <[email protected]> wrote:

>> Ehsan Behrangi has refreshed the contents of this pull request, and previous 
>> commits have been removed. The incremental views will show differences 
>> compared to the previous content of the PR. The pull request contains one 
>> new commit since the last revision:
>> 
>>   8385513: AArch64: Improve ArraysSupport.vectorizedHashCode performance for 
>> large arrays
>>   
>>   The current AArch64 implementation of ArraysSupport.vectorizedHashCode
>>   processes polynomial reductions in relatively small groups, which limits
>>   parallelism in the hash accumulation path for large arrays.
>>   
>>   This change increases polynomial batch size to 16-element groups using a
>>   larger precomputed powers-of-31 table. The updated implementation enables
>>   more independent multiply operations and reduces dependency chains in the
>>   main hashing loop.
>>   
>>   The optimization also reduces generated stub size for all supported
>>   element types, lowering instruction cache pressure in hot hashing
>>   workloads.
>>   
>>   The optimization applies to boolean[], byte[], char[], short[], and
>>   int[] array hashing paths and is enabled only for array lengths >= 8.
>>   Shorter arrays continue to use the existing scalar implementation.
>>   
>>   Generated stub size reduction:
>>   | Element type | New size | JDK 25 size | Reduction |
>>   | ------------ | -------- | ----------- | --------- |
>>   | boolean      | 332 B    | 428 B       | -96 B     |
>>   | byte         | 332 B    | 428 B       | -96 B     |
>>   | char         | 332 B    | 408 B       | -76 B     |
>>   | short        | 332 B    | 408 B       | -76 B     |
>>   | int          | 300 B    | 324 B       | -24 B     |
>>   
>>   ----------------------------------------------------
>>   BYTE[] Arrays.hashCode throughput (ops/ms):
>>   Lengths below 8 use the existing scalar path and are therefore expected to 
>> show no meaningful change.
>>   
>>   | Length | Baseline | New    | Improvement |
>>   |--------|----------|--------|-------------|
>>   | 2      | 696842   | 681572 | -2.2%       |
>>   | 7      | 349082   | 349392 | +0.1%       |
>>   | 8      | 309193   | 395677 | +28.0%      |
>>   | 9      | 294240   | 367510 | +24.9%      |
>>   | 15     | 160372   | 202718 | +26.4%      |
>>   | 16     | 241651   | 348854 | +44.4%      |
>>   | 17     | 228929   | 308820 | +34.9%      |
>>   | 23     | 139463   | 186679 | +33.9%      |
>>   | 24     | 177955   | 253809 | +42.6%      |
>>   | 25     | 173594   | 253786 | +46.2%      |
>>   | 31     | 113638   ...
>
> src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp line 9175:
> 
>> 9173: 
>> 9174:     const Register tmp    = rscratch1;
>> 9175:     const Register pow16  = rscratch2;
> 
> Please don't alias `rscratch1` and `rscratch2`. They are freely used by 
> assembler macros.

Fixed.

> src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp line 9253:
> 
>> 9251:     __ cbz(blocks, L_tail_setup);
>> 9252:     // pow16 = 31^16 mod 2^32 = 0x50A9DE01
>> 9253:     __ movw(pow16, 1353309697);
> 
> Suggestion:
> 
>     __ movw(pow16, intpow(31, 16));

Fixed.

> src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp line 9315:
> 
>> 9313:       __ addv(v_block2, Assembler::T4S, v_block2, v_block3);
>> 9314:       __ addv(v_block0, Assembler::T4S, v_block0, v_block2);
>> 9315: 
> 
> This looks like you're doing the final reduction inside the loop, rather than 
> leaving it until the end of the loop. But why are you doing that?

The current organization is intentional. I considered carrying the 
lane-position weights across loop iterations, similar to the x86_64 
implementation, as well as the previous AArch64 implementation.

The previous AArch64 implementation worked well on some cores by creating 
multiple smaller multiplication chains to help hide multiply latency for long 
arrays. In my measurements on recent Arm Neoverse cores (for example, Neoverse 
V2 and N2), reducing each 16-element block to a scalar block hash and then 
performing the scalar Horner update exposed more independent work to the 
scheduler and produced better performance than carrying vector accumulators 
across loop iterations.

The horizontal reduction is relatively inexpensive on these cores and can 
overlap with the vector multiply/add work, making the per-block reduction a 
good tradeoff.

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

PR Review Comment: https://git.openjdk.org/jdk/pull/31674#discussion_r3500360065
PR Review Comment: https://git.openjdk.org/jdk/pull/31674#discussion_r3500359114
PR Review Comment: https://git.openjdk.org/jdk/pull/31674#discussion_r3500357929

Reply via email to