summaryrefslogtreecommitdiffstats
path: root/fpu
diff options
context:
space:
mode:
authorRichard Henderson2018-08-24 14:17:30 +0200
committerPeter Maydell2018-08-24 14:17:30 +0200
commit2f6c74be593ec5219e54d7b4abd4e5a98d7f3efc (patch)
treebab0eccb7050a97fa35dfe9bf7a42bdf51b64460 /fpu
parentsoftfloat: Add scaling int-to-float routines (diff)
downloadqemu-2f6c74be593ec5219e54d7b4abd4e5a98d7f3efc.tar.gz
qemu-2f6c74be593ec5219e54d7b4abd4e5a98d7f3efc.tar.xz
qemu-2f6c74be593ec5219e54d7b4abd4e5a98d7f3efc.zip
softfloat: Add scaling float-to-int routines
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20180814002653.12828-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'fpu')
-rw-r--r--fpu/softfloat.c389
1 files changed, 316 insertions, 73 deletions
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 12f373cbad..59ca356d0e 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -1293,19 +1293,23 @@ float32 float64_to_float32(float64 a, float_status *s)
* Arithmetic.
*/
-static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
+static FloatParts round_to_int(FloatParts a, int rmode,
+ int scale, float_status *s)
{
- if (is_nan(a.cls)) {
+ switch (a.cls) {
+ case float_class_qnan:
+ case float_class_snan:
return return_nan(a, s);
- }
- switch (a.cls) {
case float_class_zero:
case float_class_inf:
- case float_class_qnan:
/* already "integral" */
break;
+
case float_class_normal:
+ scale = MIN(MAX(scale, -0x10000), 0x10000);
+ a.exp += scale;
+
if (a.exp >= DECOMPOSED_BINARY_POINT) {
/* already integral */
break;
@@ -1314,7 +1318,7 @@ static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
bool one;
/* all fractional */
s->float_exception_flags |= float_flag_inexact;
- switch (rounding_mode) {
+ switch (rmode) {
case float_round_nearest_even:
one = a.exp == -1 && a.frac > DECOMPOSED_IMPLICIT_BIT;
break;
@@ -1347,7 +1351,7 @@ static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
uint64_t rnd_mask = rnd_even_mask >> 1;
uint64_t inc;
- switch (rounding_mode) {
+ switch (rmode) {
case float_round_nearest_even:
inc = ((a.frac & rnd_even_mask) != frac_lsbm1 ? frac_lsbm1 : 0);
break;
@@ -1387,28 +1391,28 @@ static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
float16 float16_round_to_int(float16 a, float_status *s)
{
FloatParts pa = float16_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, s);
+ FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
return float16_round_pack_canonical(pr, s);
}
float32 float32_round_to_int(float32 a, float_status *s)
{
FloatParts pa = float32_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, s);
+ FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
return float32_round_pack_canonical(pr, s);
}
float64 float64_round_to_int(float64 a, float_status *s)
{
FloatParts pa = float64_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, s);
+ FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
return float64_round_pack_canonical(pr, s);
}
float64 float64_trunc_to_int(float64 a, float_status *s)
{
FloatParts pa = float64_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, float_round_to_zero, s);
+ FloatParts pr = round_to_int(pa, float_round_to_zero, 0, s);
return float64_round_pack_canonical(pr, s);
}
@@ -1423,13 +1427,13 @@ float64 float64_trunc_to_int(float64 a, float_status *s)
* is returned.
*/
-static int64_t round_to_int_and_pack(FloatParts in, int rmode,
+static int64_t round_to_int_and_pack(FloatParts in, int rmode, int scale,
int64_t min, int64_t max,
float_status *s)
{
uint64_t r;
int orig_flags = get_float_exception_flags(s);
- FloatParts p = round_to_int(in, rmode, s);
+ FloatParts p = round_to_int(in, rmode, scale, s);
switch (p.cls) {
case float_class_snan:
@@ -1469,38 +1473,158 @@ static int64_t round_to_int_and_pack(FloatParts in, int rmode,
}
}
-#define FLOAT_TO_INT(fsz, isz) \
-int ## isz ## _t float ## fsz ## _to_int ## isz(float ## fsz a, \
- float_status *s) \
-{ \
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
- return round_to_int_and_pack(p, s->float_rounding_mode, \
- INT ## isz ## _MIN, INT ## isz ## _MAX,\
- s); \
-} \
- \
-int ## isz ## _t float ## fsz ## _to_int ## isz ## _round_to_zero \
- (float ## fsz a, float_status *s) \
-{ \
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
- return round_to_int_and_pack(p, float_round_to_zero, \
- INT ## isz ## _MIN, INT ## isz ## _MAX,\
- s); \
+int16_t float16_to_int16_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, INT16_MIN, INT16_MAX, s);
+}
+
+int32_t float16_to_int32_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, INT32_MIN, INT32_MAX, s);
+}
+
+int64_t float16_to_int64_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, INT64_MIN, INT64_MAX, s);
+}
+
+int16_t float32_to_int16_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, INT16_MIN, INT16_MAX, s);
+}
+
+int32_t float32_to_int32_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, INT32_MIN, INT32_MAX, s);
+}
+
+int64_t float32_to_int64_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, INT64_MIN, INT64_MAX, s);
+}
+
+int16_t float64_to_int16_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, INT16_MIN, INT16_MAX, s);
+}
+
+int32_t float64_to_int32_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, INT32_MIN, INT32_MAX, s);
+}
+
+int64_t float64_to_int64_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, INT64_MIN, INT64_MAX, s);
+}
+
+int16_t float16_to_int16(float16 a, float_status *s)
+{
+ return float16_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int32_t float16_to_int32(float16 a, float_status *s)
+{
+ return float16_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int64_t float16_to_int64(float16 a, float_status *s)
+{
+ return float16_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int16_t float32_to_int16(float32 a, float_status *s)
+{
+ return float32_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int32_t float32_to_int32(float32 a, float_status *s)
+{
+ return float32_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int64_t float32_to_int64(float32 a, float_status *s)
+{
+ return float32_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int16_t float64_to_int16(float64 a, float_status *s)
+{
+ return float64_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int32_t float64_to_int32(float64 a, float_status *s)
+{
+ return float64_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int64_t float64_to_int64(float64 a, float_status *s)
+{
+ return float64_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int16_t float16_to_int16_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_int16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+int32_t float16_to_int32_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_int32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+int64_t float16_to_int64_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_int64_scalbn(a, float_round_to_zero, 0, s);
+}
+
+int16_t float32_to_int16_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_int16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+int32_t float32_to_int32_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_int32_scalbn(a, float_round_to_zero, 0, s);
}
-FLOAT_TO_INT(16, 16)
-FLOAT_TO_INT(16, 32)
-FLOAT_TO_INT(16, 64)
+int64_t float32_to_int64_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_int64_scalbn(a, float_round_to_zero, 0, s);
+}
-FLOAT_TO_INT(32, 16)
-FLOAT_TO_INT(32, 32)
-FLOAT_TO_INT(32, 64)
+int16_t float64_to_int16_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_int16_scalbn(a, float_round_to_zero, 0, s);
+}
-FLOAT_TO_INT(64, 16)
-FLOAT_TO_INT(64, 32)
-FLOAT_TO_INT(64, 64)
+int32_t float64_to_int32_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_int32_scalbn(a, float_round_to_zero, 0, s);
+}
-#undef FLOAT_TO_INT
+int64_t float64_to_int64_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_int64_scalbn(a, float_round_to_zero, 0, s);
+}
/*
* Returns the result of converting the floating-point value `a' to
@@ -1515,11 +1639,12 @@ FLOAT_TO_INT(64, 64)
* flag.
*/
-static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
- float_status *s)
+static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, int scale,
+ uint64_t max, float_status *s)
{
int orig_flags = get_float_exception_flags(s);
- FloatParts p = round_to_int(in, rmode, s);
+ FloatParts p = round_to_int(in, rmode, scale, s);
+ uint64_t r;
switch (p.cls) {
case float_class_snan:
@@ -1532,8 +1657,6 @@ static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
case float_class_zero:
return 0;
case float_class_normal:
- {
- uint64_t r;
if (p.sign) {
s->float_exception_flags = orig_flags | float_flag_invalid;
return 0;
@@ -1555,45 +1678,165 @@ static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
if (r > max) {
s->float_exception_flags = orig_flags | float_flag_invalid;
return max;
- } else {
- return r;
}
- }
+ return r;
default:
g_assert_not_reached();
}
}
-#define FLOAT_TO_UINT(fsz, isz) \
-uint ## isz ## _t float ## fsz ## _to_uint ## isz(float ## fsz a, \
- float_status *s) \
-{ \
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
- return round_to_uint_and_pack(p, s->float_rounding_mode, \
- UINT ## isz ## _MAX, s); \
-} \
- \
-uint ## isz ## _t float ## fsz ## _to_uint ## isz ## _round_to_zero \
- (float ## fsz a, float_status *s) \
-{ \
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
- return round_to_uint_and_pack(p, float_round_to_zero, \
- UINT ## isz ## _MAX, s); \
+uint16_t float16_to_uint16_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, UINT16_MAX, s);
+}
+
+uint32_t float16_to_uint32_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, UINT32_MAX, s);
+}
+
+uint64_t float16_to_uint64_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, UINT64_MAX, s);
+}
+
+uint16_t float32_to_uint16_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, UINT16_MAX, s);
+}
+
+uint32_t float32_to_uint32_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, UINT32_MAX, s);
+}
+
+uint64_t float32_to_uint64_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, UINT64_MAX, s);
+}
+
+uint16_t float64_to_uint16_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, UINT16_MAX, s);
+}
+
+uint32_t float64_to_uint32_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, UINT32_MAX, s);
+}
+
+uint64_t float64_to_uint64_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, UINT64_MAX, s);
+}
+
+uint16_t float16_to_uint16(float16 a, float_status *s)
+{
+ return float16_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint32_t float16_to_uint32(float16 a, float_status *s)
+{
+ return float16_to_uint32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint64_t float16_to_uint64(float16 a, float_status *s)
+{
+ return float16_to_uint64_scalbn(a, s->float_rounding_mode, 0, s);
}
-FLOAT_TO_UINT(16, 16)
-FLOAT_TO_UINT(16, 32)
-FLOAT_TO_UINT(16, 64)
+uint16_t float32_to_uint16(float32 a, float_status *s)
+{
+ return float32_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
+}
-FLOAT_TO_UINT(32, 16)
-FLOAT_TO_UINT(32, 32)
-FLOAT_TO_UINT(32, 64)
+uint32_t float32_to_uint32(float32 a, float_status *s)
+{
+ return float32_to_uint32_scalbn(a, s->float_rounding_mode, 0, s);
+}
-FLOAT_TO_UINT(64, 16)
-FLOAT_TO_UINT(64, 32)
-FLOAT_TO_UINT(64, 64)
+uint64_t float32_to_uint64(float32 a, float_status *s)
+{
+ return float32_to_uint64_scalbn(a, s->float_rounding_mode, 0, s);
+}
-#undef FLOAT_TO_UINT
+uint16_t float64_to_uint16(float64 a, float_status *s)
+{
+ return float64_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint32_t float64_to_uint32(float64 a, float_status *s)
+{
+ return float64_to_uint32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint64_t float64_to_uint64(float64 a, float_status *s)
+{
+ return float64_to_uint64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint16_t float16_to_uint16_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_uint16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint32_t float16_to_uint32_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_uint32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint64_t float16_to_uint64_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_uint64_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint16_t float32_to_uint16_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_uint16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint32_t float32_to_uint32_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_uint32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint64_t float32_to_uint64_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_uint64_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint16_t float64_to_uint16_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_uint16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint32_t float64_to_uint32_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_uint32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint64_t float64_to_uint64_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_uint64_scalbn(a, float_round_to_zero, 0, s);
+}
/*
* Integer to float conversions