RFR: 8307446: RISC-V: Improve performance of floating point to integer conversion

Xiaolin Zheng xlinzheng at openjdk.org
Fri May 5 03:04:16 UTC 2023


On Thu, 4 May 2023 14:12:19 GMT, Vladimir Kempik <vkempik at openjdk.org> wrote:

>> Hi, 
>> 
>> can I have reviews for this change that improves the performance of floating point to integer conversion?
>> 
>> Currently, risc-v port converts floating point to integer using `FCVT_SAFE` in macroAssembler_riscv.cpp.
>> 
>> The main issue here is Java spec returns 0 when the floating point number is NaN [1].
>> But for RISC-V ISA, instructions converting a floating-point value to an integer value (`FCVT.W.S`/`FCVT.L.S`/`FCVT.W.D`/`FCVT.L.D`) return the largest/smallest value when the floating point number is NaN [2].
>> That requires additional logic to handle the case when the src of conversion is NaN, as the following code did:
>> 
>> 
>> #define FCVT_SAFE(FLOATCVT, FLOATEQ)                                                             \
>> void MacroAssembler:: FLOATCVT##_safe(Register dst, FloatRegister src, Register tmp) {           \
>>   Label L_Okay;                                                                                  \
>>   fscsr(zr);                                                                                     \
>>   FLOATCVT(dst, src);                                                                            \
>>   frcsr(tmp);                                                                                    \
>>   andi(tmp, tmp, 0x1E);                                                                          \
>>   beqz(tmp, L_Okay);                                                                             \
>>   FLOATEQ(tmp, src, src);                                                                        \
>>   bnez(tmp, L_Okay);                                                                             \
>>   mv(dst, zr);                                                                                   \
>>   bind(L_Okay);                                                                                  \
>> }
>> 
>> FCVT_SAFE(fcvt_w_s, feq_s)
>> FCVT_SAFE(fcvt_l_s, feq_s)
>> FCVT_SAFE(fcvt_w_d, feq_d)
>> FCVT_SAFE(fcvt_l_d, feq_d)
>> 
>> 
>> We can improve the logic of NaN checking with the `fclass` instruction just as [JDK-8297359](https://bugs.openjdk.org/browse/JDK-8297359) did.
>> 
>> Here are the JMH results, we can got an obvious improvement for `f2i`/`f2l`/`d2i`/`d2l` conversions (source: [FloatConversion.java](https://gist.github.com/feilongjiang/b59bdd8db8460242bafac4a2ee6c2e06#file-floatconversion-java), tests on HiFive Unmatched board):
>> 
>> 
>> Before:
>> 
>> Benchmark                     (size)   Mode  Cnt   Score   Error   Units
>> FloatConversion.doubleToInt     2048  thrpt   15  29.311 ± 0.063  ops/ms
>> FloatConversion.doubleToLong    2048  thrpt   15  29.914 ± 0.023  ops/ms
>> FloatConversion.floatToInt      2048  thrpt   15  30.530 ± 0.011  ops/ms
>> FloatConversion.floatToLong     2048  thrpt   15  29.657 ± 0.021  ops/ms
>> 
>> Benchmark                     (size)   Mode  Cnt   Score   Error   Units
>> FloatConversion.doubleToInt     2048  thrpt   15  29.335 ± 0.014  ops/ms
>> FloatConversion.doubleToLong    2048  thrpt   15  29.919 ± 0.022  ops/ms
>> FloatConversion.floatToInt      2048  thrpt   15  30.523 ± 0.026  ops/ms
>> FloatConversion.floatToLong     2048  thrpt   15  29.670 ± 0.011  ops/ms
>> 
>> Benchmark                     (size)   Mode  Cnt   Score   Error   Units
>> FloatConversion.doubleToInt     2048  thrpt   15  29.344 ± 0.017  ops/ms
>> FloatConversion.doubleToLong    2048  thrpt   15  29.908 ± 0.060  ops/ms
>> FloatConversion.floatToInt      2048  thrpt   15  30.539 ± 0.009  ops/ms
>> FloatConversion.floatToLong     2048  thrpt   15  29.676 ± 0.013  ops/ms
>> 
>> ---------------------------------------------------------------------------
>> 
>> After:
>> 
>> Benchmark                     (size)   Mode  Cnt   Score   Error   Units
>> FloatConversion.doubleToInt     2048  thrpt   15  65.903 ± 0.385  ops/ms
>> FloatConversion.doubleToLong    2048  thrpt   15  66.491 ± 0.057  ops/ms
>> FloatConversion.floatToInt      2048  thrpt   15  68.045 ± 0.061  ops/ms
>> FloatConversion.floatToLong     2048  thrpt   15  68.441 ± 0.077  ops/ms
>> 
>> Benchmark                     (size)   Mode  Cnt   Score   Error   Units
>> FloatConversion.doubleToInt     2048  thrpt   15  66.015 ± 0.059  ops/ms
>> FloatConversion.doubleToLong    2048  thrpt   15  66.511 ± 0.059  ops/ms
>> FloatConversion.floatToInt      2048  thrpt   15  68.077 ± 0.051  ops/ms
>> FloatConversion.floatToLong     2048  thrpt   15  68.467 ± 0.076  ops/ms
>> 
>> Benchmark                     (size)   Mode  Cnt   Score   Error   Units
>> FloatConversion.doubleToInt     2048  thrpt   15  65.999 ± 0.067  ops/ms
>> FloatConversion.doubleToLong    2048  thrpt   15  66.454 ± 0.090  ops/ms
>> FloatConversion.floatToInt      2048  thrpt   15  68.048 ± 0.055  ops/ms
>> FloatConversion.floatToLong     2048  thrpt   15  68.467 ± 0.054  ops/ms
>> 
>> 
>> 1. https://docs.oracle.com/javase/specs/jls/se20/html/jls-5.html#jls-5.1.3
>> 2. https://github.com/riscv/riscv-isa-manual/blob/63aeaada9b2fee7ca15e5c6b6a28f3b710fb7e58/src/f-st-ext.adoc?plain=1#L365-L386
>> 
>> ## Testing:
>> - [x] tier1~3 on Unmatched board (release build)
>
> src/hotspot/cpu/riscv/macroAssembler_riscv.cpp line 4075:
> 
>> 4073:   bind(do_convert);                                                                       \
>> 4074:   FLOATCVT(dst, src);                                                                     \
>> 4075:   bind(done);                                                                             \
> 
> what about reducing the branching?
> 
> e.g.
> 
> mv (dst, zr); //pretty cheap anyway
> fclass(..);
> andi(tmp, tmp, 0b1100000000);
> bnez(tmp, done);
>   FLOATCVT(dst, src);                                                                    
> bind(done);

After applying this results look better:


Benchmark                     (size)   Mode  Cnt    Score   Error   Units
FloatConversion.doubleToInt     2048  thrpt   15  286.038 ± 1.472  ops/ms
FloatConversion.doubleToLong    2048  thrpt   15  289.585 ± 1.501  ops/ms
FloatConversion.floatToInt      2048  thrpt   15  294.313 ± 1.263  ops/ms
FloatConversion.floatToLong     2048  thrpt   15  273.749 ± 2.261  ops/ms


Stable.

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

PR Review Comment: https://git.openjdk.org/jdk/pull/13800#discussion_r1185662747


More information about the hotspot-dev mailing list