qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

target/arm: Fix float16 to/from int16

The instruction "ucvtf v0.4h, v04h, #2", with input 0x8000u,
overflows the intermediate float16 to infinity before we have a
chance to scale the output. Use float64 as the intermediate type
so that no input argument (uint32_t in this case) can overflow
or round before scaling. Given the declared argument, the signed
int32_t function has the same problem.

When converting from float16 to integer, using u/int32_t instead
of u/int16_t means that the bounding is incorrect.

Cc: qemu-stable@nongnu.org
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20180502221552.3873-4-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 88808a022c06f98d81cd3f2d105a5734c5614839)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>

authored by

Richard Henderson and committed by
Michael Roth
c708ce7d 0aaf1cca

+55 -6
+51 -2
target/arm/helper.c
··· 11409 11409 VFP_CONV_FIX(uh, s, 32, 32, uint16) 11410 11410 VFP_CONV_FIX(ul, s, 32, 32, uint32) 11411 11411 VFP_CONV_FIX_A64(uq, s, 32, 64, uint64) 11412 - VFP_CONV_FIX_A64(sl, h, 16, 32, int32) 11413 - VFP_CONV_FIX_A64(ul, h, 16, 32, uint32) 11412 + 11414 11413 #undef VFP_CONV_FIX 11415 11414 #undef VFP_CONV_FIX_FLOAT 11416 11415 #undef VFP_CONV_FLOAT_FIX_ROUND 11416 + #undef VFP_CONV_FIX_A64 11417 + 11418 + /* Conversion to/from f16 can overflow to infinity before/after scaling. 11419 + * Therefore we convert to f64 (which does not round), scale, 11420 + * and then convert f64 to f16 (which may round). 11421 + */ 11422 + 11423 + static float16 do_postscale_fp16(float64 f, int shift, float_status *fpst) 11424 + { 11425 + return float64_to_float16(float64_scalbn(f, -shift, fpst), true, fpst); 11426 + } 11427 + 11428 + float16 HELPER(vfp_sltoh)(uint32_t x, uint32_t shift, void *fpst) 11429 + { 11430 + return do_postscale_fp16(int32_to_float64(x, fpst), shift, fpst); 11431 + } 11432 + 11433 + float16 HELPER(vfp_ultoh)(uint32_t x, uint32_t shift, void *fpst) 11434 + { 11435 + return do_postscale_fp16(uint32_to_float64(x, fpst), shift, fpst); 11436 + } 11437 + 11438 + static float64 do_prescale_fp16(float16 f, int shift, float_status *fpst) 11439 + { 11440 + if (unlikely(float16_is_any_nan(f))) { 11441 + float_raise(float_flag_invalid, fpst); 11442 + return 0; 11443 + } else { 11444 + int old_exc_flags = get_float_exception_flags(fpst); 11445 + float64 ret; 11446 + 11447 + ret = float16_to_float64(f, true, fpst); 11448 + ret = float64_scalbn(ret, shift, fpst); 11449 + old_exc_flags |= get_float_exception_flags(fpst) 11450 + & float_flag_input_denormal; 11451 + set_float_exception_flags(old_exc_flags, fpst); 11452 + 11453 + return ret; 11454 + } 11455 + } 11456 + 11457 + uint32_t HELPER(vfp_toshh)(float16 x, uint32_t shift, void *fpst) 11458 + { 11459 + return float64_to_int16(do_prescale_fp16(x, shift, fpst), fpst); 11460 + } 11461 + 11462 + uint32_t HELPER(vfp_touhh)(float16 x, uint32_t shift, void *fpst) 11463 + { 11464 + return float64_to_uint16(do_prescale_fp16(x, shift, fpst), fpst); 11465 + } 11417 11466 11418 11467 /* Set the current fp rounding mode and return the old one. 11419 11468 * The argument is a softfloat float_round_ value.
+2 -2
target/arm/helper.h
··· 149 149 DEF_HELPER_3(vfp_tosld_round_to_zero, i64, f64, i32, ptr) 150 150 DEF_HELPER_3(vfp_touhd_round_to_zero, i64, f64, i32, ptr) 151 151 DEF_HELPER_3(vfp_tould_round_to_zero, i64, f64, i32, ptr) 152 - DEF_HELPER_3(vfp_toulh, i32, f16, i32, ptr) 153 - DEF_HELPER_3(vfp_toslh, i32, f16, i32, ptr) 152 + DEF_HELPER_3(vfp_touhh, i32, f16, i32, ptr) 153 + DEF_HELPER_3(vfp_toshh, i32, f16, i32, ptr) 154 154 DEF_HELPER_3(vfp_toshs, i32, f32, i32, ptr) 155 155 DEF_HELPER_3(vfp_tosls, i32, f32, i32, ptr) 156 156 DEF_HELPER_3(vfp_tosqs, i64, f32, i32, ptr)
+2 -2
target/arm/translate-a64.c
··· 7263 7263 switch (size) { 7264 7264 case MO_16: 7265 7265 if (is_u) { 7266 - fn = gen_helper_vfp_toulh; 7266 + fn = gen_helper_vfp_touhh; 7267 7267 } else { 7268 - fn = gen_helper_vfp_toslh; 7268 + fn = gen_helper_vfp_toshh; 7269 7269 } 7270 7270 break; 7271 7271 case MO_32: