From c38b64f8a9d663593075c6b9fe22eb145dccd98d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 8 Mar 2018 12:17:28 -0500 Subject: [PATCH] fpu/softfloat: re-factor minmax Let's do the same re-factor treatment for minmax functions. I still use the MACRO trick to expand but now all the checking code is common. Backports commit 89360067071b1844bf745682e18db7dde74cdb8d from qemu --- qemu/aarch64.h | 6 + qemu/aarch64eb.h | 6 + qemu/arm.h | 6 + qemu/armeb.h | 6 + qemu/fpu/softfloat.c | 219 +++++++++++++++++++---------------- qemu/header_gen.py | 6 + qemu/include/fpu/softfloat.h | 6 + qemu/m68k.h | 6 + qemu/mips.h | 6 + qemu/mips64.h | 6 + qemu/mips64el.h | 6 + qemu/mipsel.h | 6 + qemu/powerpc.h | 6 + qemu/sparc.h | 6 + qemu/sparc64.h | 6 + qemu/x86_64.h | 6 + 16 files changed, 210 insertions(+), 99 deletions(-) diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 07ea7f45..17095299 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -492,7 +492,13 @@ #define float16_div float16_div_aarch64 #define float16_is_quiet_nan float16_is_quiet_nan_aarch64 #define float16_is_signaling_nan float16_is_signaling_nan_aarch64 +#define float16_max float16_max_aarch64 +#define float16_maxnum float16_maxnum_aarch64 +#define float16_maxnummag float16_maxnummag_aarch64 #define float16_maybe_silence_nan float16_maybe_silence_nan_aarch64 +#define float16_min float16_min_aarch64 +#define float16_minnum float16_minnum_aarch64 +#define float16_minnummag float16_minnummag_aarch64 #define float16_mul float16_mul_aarch64 #define float16_muladd float16_muladd_aarch64 #define float16_round_to_int float16_round_to_int_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index 11a09015..455074fd 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -492,7 +492,13 @@ #define float16_div float16_div_aarch64eb #define float16_is_quiet_nan float16_is_quiet_nan_aarch64eb #define float16_is_signaling_nan float16_is_signaling_nan_aarch64eb +#define float16_max float16_max_aarch64eb +#define float16_maxnum float16_maxnum_aarch64eb +#define float16_maxnummag float16_maxnummag_aarch64eb #define float16_maybe_silence_nan float16_maybe_silence_nan_aarch64eb +#define float16_min float16_min_aarch64eb +#define float16_minnum float16_minnum_aarch64eb +#define float16_minnummag float16_minnummag_aarch64eb #define float16_mul float16_mul_aarch64eb #define float16_muladd float16_muladd_aarch64eb #define float16_round_to_int float16_round_to_int_aarch64eb diff --git a/qemu/arm.h b/qemu/arm.h index 8bd378ac..063ab518 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -492,7 +492,13 @@ #define float16_div float16_div_arm #define float16_is_quiet_nan float16_is_quiet_nan_arm #define float16_is_signaling_nan float16_is_signaling_nan_arm +#define float16_max float16_max_arm +#define float16_maxnum float16_maxnum_arm +#define float16_maxnummag float16_maxnummag_arm #define float16_maybe_silence_nan float16_maybe_silence_nan_arm +#define float16_min float16_min_arm +#define float16_minnum float16_minnum_arm +#define float16_minnummag float16_minnummag_arm #define float16_mul float16_mul_arm #define float16_muladd float16_muladd_arm #define float16_round_to_int float16_round_to_int_arm diff --git a/qemu/armeb.h b/qemu/armeb.h index a94db789..219f388f 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -492,7 +492,13 @@ #define float16_div float16_div_armeb #define float16_is_quiet_nan float16_is_quiet_nan_armeb #define float16_is_signaling_nan float16_is_signaling_nan_armeb +#define float16_max float16_max_armeb +#define float16_maxnum float16_maxnum_armeb +#define float16_maxnummag float16_maxnummag_armeb #define float16_maybe_silence_nan float16_maybe_silence_nan_armeb +#define float16_min float16_min_armeb +#define float16_minnum float16_minnum_armeb +#define float16_minnummag float16_minnummag_armeb #define float16_mul float16_mul_armeb #define float16_muladd float16_muladd_armeb #define float16_round_to_int float16_round_to_int_armeb diff --git a/qemu/fpu/softfloat.c b/qemu/fpu/softfloat.c index 319f1fc4..b09bb75e 100644 --- a/qemu/fpu/softfloat.c +++ b/qemu/fpu/softfloat.c @@ -1697,6 +1697,126 @@ float64 float64_scalbn(float64 a, int n, float_status *status) return float64_round_pack_canonical(pr, status); } +/* Float Min/Max */ +/* min() and max() functions. These can't be implemented as + * 'compare and pick one input' because that would mishandle + * NaNs and +0 vs -0. + * + * minnum() and maxnum() functions. These are similar to the min() + * and max() functions but if one of the arguments is a QNaN and + * the other is numerical then the numerical argument is returned. + * SNaNs will get quietened before being returned. + * minnum() and maxnum correspond to the IEEE 754-2008 minNum() + * and maxNum() operations. min() and max() are the typical min/max + * semantics provided by many CPUs which predate that specification. + * + * minnummag() and maxnummag() functions correspond to minNumMag() + * and minNumMag() from the IEEE-754 2008. + */ +static FloatParts minmax_floats(FloatParts a, FloatParts b, bool ismin, + bool ieee, bool ismag, float_status *s) +{ + if (unlikely(is_nan(a.cls) || is_nan(b.cls))) { + if (ieee) { + /* Takes two floating-point values `a' and `b', one of + * which is a NaN, and returns the appropriate NaN + * result. If either `a' or `b' is a signaling NaN, + * the invalid exception is raised. + */ + if (is_snan(a.cls) || is_snan(b.cls)) { + return pick_nan(a, b, s); + } else if (is_nan(a.cls) && !is_nan(b.cls)) { + return b; + } else if (is_nan(b.cls) && !is_nan(a.cls)) { + return a; + } + } + return pick_nan(a, b, s); + } else { + int a_exp, b_exp; + bool a_sign, b_sign; + + switch (a.cls) { + case float_class_normal: + a_exp = a.exp; + break; + case float_class_inf: + a_exp = INT_MAX; + break; + case float_class_zero: + a_exp = INT_MIN; + break; + default: + g_assert_not_reached(); + break; + } + switch (b.cls) { + case float_class_normal: + b_exp = b.exp; + break; + case float_class_inf: + b_exp = INT_MAX; + break; + case float_class_zero: + b_exp = INT_MIN; + break; + default: + g_assert_not_reached(); + break; + } + + a_sign = a.sign; + b_sign = b.sign; + if (ismag) { + a_sign = b_sign = 0; + } + + if (a_sign == b_sign) { + bool a_less = a_exp < b_exp; + if (a_exp == b_exp) { + a_less = a.frac < b.frac; + } + return a_sign ^ a_less ^ ismin ? b : a; + } else { + return a_sign ^ ismin ? b : a; + } + } +} + +#define MINMAX(sz, name, ismin, isiee, ismag) \ +float ## sz float ## sz ## _ ## name(float ## sz a, float ## sz b, \ + float_status *s) \ +{ \ + FloatParts pa = float ## sz ## _unpack_canonical(a, s); \ + FloatParts pb = float ## sz ## _unpack_canonical(b, s); \ + FloatParts pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ + \ + return float ## sz ## _round_pack_canonical(pr, s); \ +} + +MINMAX(16, min, true, false, false) +MINMAX(16, minnum, true, true, false) +MINMAX(16, minnummag, true, true, true) +MINMAX(16, max, false, false, false) +MINMAX(16, maxnum, false, true, false) +MINMAX(16, maxnummag, false, true, true) + +MINMAX(32, min, true, false, false) +MINMAX(32, minnum, true, true, false) +MINMAX(32, minnummag, true, true, true) +MINMAX(32, max, false, false, false) +MINMAX(32, maxnum, false, true, false) +MINMAX(32, maxnummag, false, true, true) + +MINMAX(64, min, true, false, false) +MINMAX(64, minnum, true, true, false) +MINMAX(64, minnummag, true, true, true) +MINMAX(64, max, false, false, false) +MINMAX(64, maxnum, false, true, false) +MINMAX(64, maxnummag, false, true, true) + +#undef MINMAX + /*---------------------------------------------------------------------------- | Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 | and 7, and returns the properly rounded 32-bit integer corresponding to the @@ -6839,105 +6959,6 @@ int float128_compare_quiet(float128 a, float128 b, float_status *status) return float128_compare_internal(a, b, 1, status); } -/* min() and max() functions. These can't be implemented as - * 'compare and pick one input' because that would mishandle - * NaNs and +0 vs -0. - * - * minnum() and maxnum() functions. These are similar to the min() - * and max() functions but if one of the arguments is a QNaN and - * the other is numerical then the numerical argument is returned. - * minnum() and maxnum correspond to the IEEE 754-2008 minNum() - * and maxNum() operations. min() and max() are the typical min/max - * semantics provided by many CPUs which predate that specification. - * - * minnummag() and maxnummag() functions correspond to minNumMag() - * and minNumMag() from the IEEE-754 2008. - */ -#define MINMAX(s) \ -static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \ - int ismin, int isieee, \ - int ismag, float_status *status) \ -{ \ - flag aSign, bSign; \ - uint ## s ## _t av, bv, aav, abv; \ - a = float ## s ## _squash_input_denormal(a, status); \ - b = float ## s ## _squash_input_denormal(b, status); \ - if (float ## s ## _is_any_nan(a) || \ - float ## s ## _is_any_nan(b)) { \ - if (isieee) { \ - if (float ## s ## _is_quiet_nan(a, status) && \ - !float ## s ##_is_any_nan(b)) { \ - return b; \ - } else if (float ## s ## _is_quiet_nan(b, status) && \ - !float ## s ## _is_any_nan(a)) { \ - return a; \ - } \ - } \ - return propagateFloat ## s ## NaN(a, b, status); \ - } \ - aSign = extractFloat ## s ## Sign(a); \ - bSign = extractFloat ## s ## Sign(b); \ - av = float ## s ## _val(a); \ - bv = float ## s ## _val(b); \ - if (ismag) { \ - aav = float ## s ## _abs(av); \ - abv = float ## s ## _abs(bv); \ - if (aav != abv) { \ - if (ismin) { \ - return (aav < abv) ? a : b; \ - } else { \ - return (aav < abv) ? b : a; \ - } \ - } \ - } \ - if (aSign != bSign) { \ - if (ismin) { \ - return aSign ? a : b; \ - } else { \ - return aSign ? b : a; \ - } \ - } else { \ - if (ismin) { \ - return (aSign ^ (av < bv)) ? a : b; \ - } else { \ - return (aSign ^ (av < bv)) ? b : a; \ - } \ - } \ -} \ - \ -float ## s float ## s ## _min(float ## s a, float ## s b, float_status *status) \ -{ \ - return float ## s ## _minmax(a, b, 1, 0, 0, status); \ -} \ - \ -float ## s float ## s ## _max(float ## s a, float ## s b, float_status *status) \ -{ \ - return float ## s ## _minmax(a, b, 0, 0, 0, status); \ -} \ - \ -float ## s float ## s ## _minnum(float ## s a, float ## s b, float_status *status) \ -{ \ - return float ## s ## _minmax(a, b, 1, 1, 0, status); \ -} \ - \ -float ## s float ## s ## _maxnum(float ## s a, float ## s b, float_status *status) \ -{ \ - return float ## s ## _minmax(a, b, 0, 1, 0, status); \ -} \ - \ -float ## s float ## s ## _minnummag(float ## s a, float ## s b, float_status *status) \ -{ \ - return float ## s ## _minmax(a, b, 1, 1, 1, status); \ -} \ - \ -float ## s float ## s ## _maxnummag(float ## s a, float ## s b, float_status *status) \ -{ \ - return float ## s ## _minmax(a, b, 0, 1, 1, status); \ -} - -MINMAX(32) -MINMAX(64) - floatx80 floatx80_scalbn(floatx80 a, int n, float_status *status) { flag aSign; diff --git a/qemu/header_gen.py b/qemu/header_gen.py index b94a1d20..7b13bd5f 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -498,7 +498,13 @@ symbols = ( 'float16_div', 'float16_is_quiet_nan', 'float16_is_signaling_nan', + 'float16_max', + 'float16_maxnum', + 'float16_maxnummag', 'float16_maybe_silence_nan', + 'float16_min', + 'float16_minnum', + 'float16_minnummag', 'float16_mul', 'float16_muladd', 'float16_round_to_int', diff --git a/qemu/include/fpu/softfloat.h b/qemu/include/fpu/softfloat.h index b39d2c21..574b9403 100644 --- a/qemu/include/fpu/softfloat.h +++ b/qemu/include/fpu/softfloat.h @@ -252,6 +252,12 @@ float16 float16_mul(float16, float16, float_status *status); float16 float16_muladd(float16, float16, float16, int, float_status *status); float16 float16_div(float16, float16, float_status *status); float16 float16_scalbn(float16, int, float_status *status); +float16 float16_min(float16, float16, float_status *status); +float16 float16_max(float16, float16, float_status *status); +float16 float16_minnum(float16, float16, float_status *status); +float16 float16_maxnum(float16, float16, float_status *status); +float16 float16_minnummag(float16, float16, float_status *status); +float16 float16_maxnummag(float16, float16, float_status *status); int float16_is_quiet_nan(float16, float_status *status); int float16_is_signaling_nan(float16, float_status *status); diff --git a/qemu/m68k.h b/qemu/m68k.h index 6a8a580b..23d5a5d7 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -492,7 +492,13 @@ #define float16_div float16_div_m68k #define float16_is_quiet_nan float16_is_quiet_nan_m68k #define float16_is_signaling_nan float16_is_signaling_nan_m68k +#define float16_max float16_max_m68k +#define float16_maxnum float16_maxnum_m68k +#define float16_maxnummag float16_maxnummag_m68k #define float16_maybe_silence_nan float16_maybe_silence_nan_m68k +#define float16_min float16_min_m68k +#define float16_minnum float16_minnum_m68k +#define float16_minnummag float16_minnummag_m68k #define float16_mul float16_mul_m68k #define float16_muladd float16_muladd_m68k #define float16_round_to_int float16_round_to_int_m68k diff --git a/qemu/mips.h b/qemu/mips.h index a6b7f215..b7de7269 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -492,7 +492,13 @@ #define float16_div float16_div_mips #define float16_is_quiet_nan float16_is_quiet_nan_mips #define float16_is_signaling_nan float16_is_signaling_nan_mips +#define float16_max float16_max_mips +#define float16_maxnum float16_maxnum_mips +#define float16_maxnummag float16_maxnummag_mips #define float16_maybe_silence_nan float16_maybe_silence_nan_mips +#define float16_min float16_min_mips +#define float16_minnum float16_minnum_mips +#define float16_minnummag float16_minnummag_mips #define float16_mul float16_mul_mips #define float16_muladd float16_muladd_mips #define float16_round_to_int float16_round_to_int_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 06ba754a..5e7c30ab 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -492,7 +492,13 @@ #define float16_div float16_div_mips64 #define float16_is_quiet_nan float16_is_quiet_nan_mips64 #define float16_is_signaling_nan float16_is_signaling_nan_mips64 +#define float16_max float16_max_mips64 +#define float16_maxnum float16_maxnum_mips64 +#define float16_maxnummag float16_maxnummag_mips64 #define float16_maybe_silence_nan float16_maybe_silence_nan_mips64 +#define float16_min float16_min_mips64 +#define float16_minnum float16_minnum_mips64 +#define float16_minnummag float16_minnummag_mips64 #define float16_mul float16_mul_mips64 #define float16_muladd float16_muladd_mips64 #define float16_round_to_int float16_round_to_int_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 782fa295..850dfad4 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -492,7 +492,13 @@ #define float16_div float16_div_mips64el #define float16_is_quiet_nan float16_is_quiet_nan_mips64el #define float16_is_signaling_nan float16_is_signaling_nan_mips64el +#define float16_max float16_max_mips64el +#define float16_maxnum float16_maxnum_mips64el +#define float16_maxnummag float16_maxnummag_mips64el #define float16_maybe_silence_nan float16_maybe_silence_nan_mips64el +#define float16_min float16_min_mips64el +#define float16_minnum float16_minnum_mips64el +#define float16_minnummag float16_minnummag_mips64el #define float16_mul float16_mul_mips64el #define float16_muladd float16_muladd_mips64el #define float16_round_to_int float16_round_to_int_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 88ebbe11..5c53eb7b 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -492,7 +492,13 @@ #define float16_div float16_div_mipsel #define float16_is_quiet_nan float16_is_quiet_nan_mipsel #define float16_is_signaling_nan float16_is_signaling_nan_mipsel +#define float16_max float16_max_mipsel +#define float16_maxnum float16_maxnum_mipsel +#define float16_maxnummag float16_maxnummag_mipsel #define float16_maybe_silence_nan float16_maybe_silence_nan_mipsel +#define float16_min float16_min_mipsel +#define float16_minnum float16_minnum_mipsel +#define float16_minnummag float16_minnummag_mipsel #define float16_mul float16_mul_mipsel #define float16_muladd float16_muladd_mipsel #define float16_round_to_int float16_round_to_int_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index fb3d870a..1e38dcf6 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -492,7 +492,13 @@ #define float16_div float16_div_powerpc #define float16_is_quiet_nan float16_is_quiet_nan_powerpc #define float16_is_signaling_nan float16_is_signaling_nan_powerpc +#define float16_max float16_max_powerpc +#define float16_maxnum float16_maxnum_powerpc +#define float16_maxnummag float16_maxnummag_powerpc #define float16_maybe_silence_nan float16_maybe_silence_nan_powerpc +#define float16_min float16_min_powerpc +#define float16_minnum float16_minnum_powerpc +#define float16_minnummag float16_minnummag_powerpc #define float16_mul float16_mul_powerpc #define float16_muladd float16_muladd_powerpc #define float16_round_to_int float16_round_to_int_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index e46019b9..fd863c07 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -492,7 +492,13 @@ #define float16_div float16_div_sparc #define float16_is_quiet_nan float16_is_quiet_nan_sparc #define float16_is_signaling_nan float16_is_signaling_nan_sparc +#define float16_max float16_max_sparc +#define float16_maxnum float16_maxnum_sparc +#define float16_maxnummag float16_maxnummag_sparc #define float16_maybe_silence_nan float16_maybe_silence_nan_sparc +#define float16_min float16_min_sparc +#define float16_minnum float16_minnum_sparc +#define float16_minnummag float16_minnummag_sparc #define float16_mul float16_mul_sparc #define float16_muladd float16_muladd_sparc #define float16_round_to_int float16_round_to_int_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 018bafaf..80d940dd 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -492,7 +492,13 @@ #define float16_div float16_div_sparc64 #define float16_is_quiet_nan float16_is_quiet_nan_sparc64 #define float16_is_signaling_nan float16_is_signaling_nan_sparc64 +#define float16_max float16_max_sparc64 +#define float16_maxnum float16_maxnum_sparc64 +#define float16_maxnummag float16_maxnummag_sparc64 #define float16_maybe_silence_nan float16_maybe_silence_nan_sparc64 +#define float16_min float16_min_sparc64 +#define float16_minnum float16_minnum_sparc64 +#define float16_minnummag float16_minnummag_sparc64 #define float16_mul float16_mul_sparc64 #define float16_muladd float16_muladd_sparc64 #define float16_round_to_int float16_round_to_int_sparc64 diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 330e523d..e00cb274 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -492,7 +492,13 @@ #define float16_div float16_div_x86_64 #define float16_is_quiet_nan float16_is_quiet_nan_x86_64 #define float16_is_signaling_nan float16_is_signaling_nan_x86_64 +#define float16_max float16_max_x86_64 +#define float16_maxnum float16_maxnum_x86_64 +#define float16_maxnummag float16_maxnummag_x86_64 #define float16_maybe_silence_nan float16_maybe_silence_nan_x86_64 +#define float16_min float16_min_x86_64 +#define float16_minnum float16_minnum_x86_64 +#define float16_minnummag float16_minnummag_x86_64 #define float16_mul float16_mul_x86_64 #define float16_muladd float16_muladd_x86_64 #define float16_round_to_int float16_round_to_int_x86_64