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.

Backports commit 88808a022c06f98d81cd3f2d105a5734c5614839 from qemu
This commit is contained in:
Richard Henderson 2018-05-14 08:39:20 -04:00 committed by Lioncash
parent e403957a5e
commit 67740bbc7f
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
17 changed files with 83 additions and 6 deletions

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_aarch64
#define helper_vfp_toshd helper_vfp_toshd_aarch64
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_aarch64
#define helper_vfp_toshh helper_vfp_toshh_aarch64
#define helper_vfp_toshs helper_vfp_toshs_aarch64
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_aarch64
#define helper_vfp_tosid helper_vfp_tosid_aarch64
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_aarch64
#define helper_vfp_touhd helper_vfp_touhd_aarch64
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_aarch64
#define helper_vfp_touhh helper_vfp_touhh_aarch64
#define helper_vfp_touhs helper_vfp_touhs_aarch64
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_aarch64
#define helper_vfp_touid helper_vfp_touid_aarch64

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_aarch64eb
#define helper_vfp_toshd helper_vfp_toshd_aarch64eb
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_aarch64eb
#define helper_vfp_toshh helper_vfp_toshh_aarch64eb
#define helper_vfp_toshs helper_vfp_toshs_aarch64eb
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_aarch64eb
#define helper_vfp_tosid helper_vfp_tosid_aarch64eb
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_aarch64eb
#define helper_vfp_touhd helper_vfp_touhd_aarch64eb
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_aarch64eb
#define helper_vfp_touhh helper_vfp_touhh_aarch64eb
#define helper_vfp_touhs helper_vfp_touhs_aarch64eb
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_aarch64eb
#define helper_vfp_touid helper_vfp_touid_aarch64eb

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_arm
#define helper_vfp_toshd helper_vfp_toshd_arm
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_arm
#define helper_vfp_toshh helper_vfp_toshh_arm
#define helper_vfp_toshs helper_vfp_toshs_arm
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_arm
#define helper_vfp_tosid helper_vfp_tosid_arm
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_arm
#define helper_vfp_touhd helper_vfp_touhd_arm
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_arm
#define helper_vfp_touhh helper_vfp_touhh_arm
#define helper_vfp_touhs helper_vfp_touhs_arm
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_arm
#define helper_vfp_touid helper_vfp_touid_arm

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_armeb
#define helper_vfp_toshd helper_vfp_toshd_armeb
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_armeb
#define helper_vfp_toshh helper_vfp_toshh_armeb
#define helper_vfp_toshs helper_vfp_toshs_armeb
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_armeb
#define helper_vfp_tosid helper_vfp_tosid_armeb
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_armeb
#define helper_vfp_touhd helper_vfp_touhd_armeb
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_armeb
#define helper_vfp_touhh helper_vfp_touhh_armeb
#define helper_vfp_touhs helper_vfp_touhs_armeb
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_armeb
#define helper_vfp_touid helper_vfp_touid_armeb

View file

@ -1707,6 +1707,7 @@ symbols = (
'helper_vfp_subs',
'helper_vfp_toshd',
'helper_vfp_toshd_round_to_zero',
'helper_vfp_toshh',
'helper_vfp_toshs',
'helper_vfp_toshs_round_to_zero',
'helper_vfp_tosid',
@ -1724,6 +1725,7 @@ symbols = (
'helper_vfp_tosqs',
'helper_vfp_touhd',
'helper_vfp_touhd_round_to_zero',
'helper_vfp_touhh',
'helper_vfp_touhs',
'helper_vfp_touhs_round_to_zero',
'helper_vfp_touid',

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_m68k
#define helper_vfp_toshd helper_vfp_toshd_m68k
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_m68k
#define helper_vfp_toshh helper_vfp_toshh_m68k
#define helper_vfp_toshs helper_vfp_toshs_m68k
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_m68k
#define helper_vfp_tosid helper_vfp_tosid_m68k
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_m68k
#define helper_vfp_touhd helper_vfp_touhd_m68k
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_m68k
#define helper_vfp_touhh helper_vfp_touhh_m68k
#define helper_vfp_touhs helper_vfp_touhs_m68k
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_m68k
#define helper_vfp_touid helper_vfp_touid_m68k

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_mips
#define helper_vfp_toshd helper_vfp_toshd_mips
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_mips
#define helper_vfp_toshh helper_vfp_toshh_mips
#define helper_vfp_toshs helper_vfp_toshs_mips
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_mips
#define helper_vfp_tosid helper_vfp_tosid_mips
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_mips
#define helper_vfp_touhd helper_vfp_touhd_mips
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_mips
#define helper_vfp_touhh helper_vfp_touhh_mips
#define helper_vfp_touhs helper_vfp_touhs_mips
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_mips
#define helper_vfp_touid helper_vfp_touid_mips

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_mips64
#define helper_vfp_toshd helper_vfp_toshd_mips64
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_mips64
#define helper_vfp_toshh helper_vfp_toshh_mips64
#define helper_vfp_toshs helper_vfp_toshs_mips64
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_mips64
#define helper_vfp_tosid helper_vfp_tosid_mips64
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_mips64
#define helper_vfp_touhd helper_vfp_touhd_mips64
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_mips64
#define helper_vfp_touhh helper_vfp_touhh_mips64
#define helper_vfp_touhs helper_vfp_touhs_mips64
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_mips64
#define helper_vfp_touid helper_vfp_touid_mips64

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_mips64el
#define helper_vfp_toshd helper_vfp_toshd_mips64el
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_mips64el
#define helper_vfp_toshh helper_vfp_toshh_mips64el
#define helper_vfp_toshs helper_vfp_toshs_mips64el
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_mips64el
#define helper_vfp_tosid helper_vfp_tosid_mips64el
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_mips64el
#define helper_vfp_touhd helper_vfp_touhd_mips64el
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_mips64el
#define helper_vfp_touhh helper_vfp_touhh_mips64el
#define helper_vfp_touhs helper_vfp_touhs_mips64el
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_mips64el
#define helper_vfp_touid helper_vfp_touid_mips64el

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_mipsel
#define helper_vfp_toshd helper_vfp_toshd_mipsel
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_mipsel
#define helper_vfp_toshh helper_vfp_toshh_mipsel
#define helper_vfp_toshs helper_vfp_toshs_mipsel
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_mipsel
#define helper_vfp_tosid helper_vfp_tosid_mipsel
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_mipsel
#define helper_vfp_touhd helper_vfp_touhd_mipsel
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_mipsel
#define helper_vfp_touhh helper_vfp_touhh_mipsel
#define helper_vfp_touhs helper_vfp_touhs_mipsel
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_mipsel
#define helper_vfp_touid helper_vfp_touid_mipsel

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_powerpc
#define helper_vfp_toshd helper_vfp_toshd_powerpc
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_powerpc
#define helper_vfp_toshh helper_vfp_toshh_powerpc
#define helper_vfp_toshs helper_vfp_toshs_powerpc
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_powerpc
#define helper_vfp_tosid helper_vfp_tosid_powerpc
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_powerpc
#define helper_vfp_touhd helper_vfp_touhd_powerpc
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_powerpc
#define helper_vfp_touhh helper_vfp_touhh_powerpc
#define helper_vfp_touhs helper_vfp_touhs_powerpc
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_powerpc
#define helper_vfp_touid helper_vfp_touid_powerpc

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_sparc
#define helper_vfp_toshd helper_vfp_toshd_sparc
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_sparc
#define helper_vfp_toshh helper_vfp_toshh_sparc
#define helper_vfp_toshs helper_vfp_toshs_sparc
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_sparc
#define helper_vfp_tosid helper_vfp_tosid_sparc
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_sparc
#define helper_vfp_touhd helper_vfp_touhd_sparc
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_sparc
#define helper_vfp_touhh helper_vfp_touhh_sparc
#define helper_vfp_touhs helper_vfp_touhs_sparc
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_sparc
#define helper_vfp_touid helper_vfp_touid_sparc

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_sparc64
#define helper_vfp_toshd helper_vfp_toshd_sparc64
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_sparc64
#define helper_vfp_toshh helper_vfp_toshh_sparc64
#define helper_vfp_toshs helper_vfp_toshs_sparc64
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_sparc64
#define helper_vfp_tosid helper_vfp_tosid_sparc64
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_sparc64
#define helper_vfp_touhd helper_vfp_touhd_sparc64
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_sparc64
#define helper_vfp_touhh helper_vfp_touhh_sparc64
#define helper_vfp_touhs helper_vfp_touhs_sparc64
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_sparc64
#define helper_vfp_touid helper_vfp_touid_sparc64

View file

@ -10676,11 +10676,60 @@ VFP_CONV_FIX_A64(sq, s, 32, 64, int64)
VFP_CONV_FIX(uh, s, 32, 32, uint16)
VFP_CONV_FIX(ul, s, 32, 32, uint32)
VFP_CONV_FIX_A64(uq, s, 32, 64, uint64)
VFP_CONV_FIX_A64(sl, h, 16, 32, int32)
VFP_CONV_FIX_A64(ul, h, 16, 32, uint32)
#undef VFP_CONV_FIX
#undef VFP_CONV_FIX_FLOAT
#undef VFP_CONV_FLOAT_FIX_ROUND
#undef VFP_CONV_FIX_A64
/* Conversion to/from f16 can overflow to infinity before/after scaling.
* Therefore we convert to f64 (which does not round), scale,
* and then convert f64 to f16 (which may round).
*/
static float16 do_postscale_fp16(float64 f, int shift, float_status *fpst)
{
return float64_to_float16(float64_scalbn(f, -shift, fpst), true, fpst);
}
float16 HELPER(vfp_sltoh)(uint32_t x, uint32_t shift, void *fpst)
{
return do_postscale_fp16(int32_to_float64(x, fpst), shift, fpst);
}
float16 HELPER(vfp_ultoh)(uint32_t x, uint32_t shift, void *fpst)
{
return do_postscale_fp16(uint32_to_float64(x, fpst), shift, fpst);
}
static float64 do_prescale_fp16(float16 f, int shift, float_status *fpst)
{
if (unlikely(float16_is_any_nan(f))) {
float_raise(float_flag_invalid, fpst);
return 0;
} else {
int old_exc_flags = get_float_exception_flags(fpst);
float64 ret;
ret = float16_to_float64(f, true, fpst);
ret = float64_scalbn(ret, shift, fpst);
old_exc_flags |= get_float_exception_flags(fpst)
& float_flag_input_denormal;
set_float_exception_flags(old_exc_flags, fpst);
return ret;
}
}
uint32_t HELPER(vfp_toshh)(float16 x, uint32_t shift, void *fpst)
{
return float64_to_int16(do_prescale_fp16(x, shift, fpst), fpst);
}
uint32_t HELPER(vfp_touhh)(float16 x, uint32_t shift, void *fpst)
{
return float64_to_uint16(do_prescale_fp16(x, shift, fpst), fpst);
}
/* Set the current fp rounding mode and return the old one.
* The argument is a softfloat float_round_ value.

View file

@ -151,8 +151,8 @@ DEF_HELPER_3(vfp_toshd_round_to_zero, i64, f64, i32, ptr)
DEF_HELPER_3(vfp_tosld_round_to_zero, i64, f64, i32, ptr)
DEF_HELPER_3(vfp_touhd_round_to_zero, i64, f64, i32, ptr)
DEF_HELPER_3(vfp_tould_round_to_zero, i64, f64, i32, ptr)
DEF_HELPER_3(vfp_toulh, i32, f16, i32, ptr)
DEF_HELPER_3(vfp_toslh, i32, f16, i32, ptr)
DEF_HELPER_3(vfp_touhh, i32, f16, i32, ptr)
DEF_HELPER_3(vfp_toshh, i32, f16, i32, ptr)
DEF_HELPER_3(vfp_toshs, i32, f32, i32, ptr)
DEF_HELPER_3(vfp_tosls, i32, f32, i32, ptr)
DEF_HELPER_3(vfp_tosqs, i64, f32, i32, ptr)

View file

@ -7632,9 +7632,9 @@ static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar,
switch (size) {
case MO_16:
if (is_u) {
fn = gen_helper_vfp_toulh;
fn = gen_helper_vfp_touhh;
} else {
fn = gen_helper_vfp_toslh;
fn = gen_helper_vfp_toshh;
}
break;
case MO_32:

View file

@ -1701,6 +1701,7 @@
#define helper_vfp_subs helper_vfp_subs_x86_64
#define helper_vfp_toshd helper_vfp_toshd_x86_64
#define helper_vfp_toshd_round_to_zero helper_vfp_toshd_round_to_zero_x86_64
#define helper_vfp_toshh helper_vfp_toshh_x86_64
#define helper_vfp_toshs helper_vfp_toshs_x86_64
#define helper_vfp_toshs_round_to_zero helper_vfp_toshs_round_to_zero_x86_64
#define helper_vfp_tosid helper_vfp_tosid_x86_64
@ -1718,6 +1719,7 @@
#define helper_vfp_tosqs helper_vfp_tosqs_x86_64
#define helper_vfp_touhd helper_vfp_touhd_x86_64
#define helper_vfp_touhd_round_to_zero helper_vfp_touhd_round_to_zero_x86_64
#define helper_vfp_touhh helper_vfp_touhh_x86_64
#define helper_vfp_touhs helper_vfp_touhs_x86_64
#define helper_vfp_touhs_round_to_zero helper_vfp_touhs_round_to_zero_x86_64
#define helper_vfp_touid helper_vfp_touid_x86_64