From d0af544555473e2cbac58903577e042ed5c50fa9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 13 Dec 2009 17:50:46 -0800 Subject: target-alpha: Fix float32_to_s vs zero exponent. There was a bug in float32_to_s that incorrectly mapped a zero exponent to 0x38. This meant 0.0f != 0. At the same time, fix a generic type punning bug in helper_memory_to_s and helper_s_to_memory. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-alpha/op_helper.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'target-alpha') diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index ff120ade3b..b2abf6c785 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -625,37 +625,57 @@ uint64_t helper_sqrtg (uint64_t a) /* S floating (single) */ + +/* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */ +static inline uint64_t float32_to_s_int(uint32_t fi) +{ + uint32_t frac = fi & 0x7fffff; + uint32_t sign = fi >> 31; + uint32_t exp_msb = (fi >> 30) & 1; + uint32_t exp_low = (fi >> 23) & 0x7f; + uint32_t exp; + + exp = (exp_msb << 10) | exp_low; + if (exp_msb) { + if (exp_low == 0x7f) + exp = 0x7ff; + } else { + if (exp_low != 0x00) + exp |= 0x380; + } + + return (((uint64_t)sign << 63) + | ((uint64_t)exp << 52) + | ((uint64_t)frac << 29)); +} + static inline uint64_t float32_to_s(float32 fa) { CPU_FloatU a; - uint64_t r; - a.f = fa; + return float32_to_s_int(a.l); +} - r = (((uint64_t)(a.l & 0xc0000000)) << 32) | (((uint64_t)(a.l & 0x3fffffff)) << 29); - if (((a.l & 0x7f800000) != 0x7f800000) && (!(a.l & 0x40000000))) - r |= 0x7ll << 59; - return r; +static inline uint32_t s_to_float32_int(uint64_t a) +{ + return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); } static inline float32 s_to_float32(uint64_t a) { CPU_FloatU r; - r.l = ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); + r.l = s_to_float32_int(a); return r.f; } uint32_t helper_s_to_memory (uint64_t a) { - /* Memory format is the same as float32 */ - float32 fa = s_to_float32(a); - return *(uint32_t*)(&fa); + return s_to_float32_int(a); } uint64_t helper_memory_to_s (uint32_t a) { - /* Memory format is the same as float32 */ - return float32_to_s(*(float32*)(&a)); + return float32_to_s_int(a); } uint64_t helper_adds (uint64_t a, uint64_t b) -- cgit v1.2.3