Browse Source

target/alpha: Use float64_to_int64_modulo for CVTTQ

For the most part we can use the new generic routine,
though exceptions need some post-processing to sort
invalid from integer overflow.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-Id: <20230527141910.1885950-4-richard.henderson@linaro.org>
pull/240/head
Richard Henderson 3 years ago
parent
commit
aa3bad5b59
  1. 87
      target/alpha/fpu_helper.c

87
target/alpha/fpu_helper.c

@ -453,78 +453,29 @@ uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode)
{
uint64_t frac, ret = 0;
uint32_t exp, sign, exc = 0;
int shift;
float64 fa;
int64_t ret;
uint32_t exc;
sign = (a >> 63);
exp = (uint32_t)(a >> 52) & 0x7ff;
frac = a & 0xfffffffffffffull;
fa = t_to_float64(a);
ret = float64_to_int64_modulo(fa, roundmode, &FP_STATUS);
if (exp == 0) {
if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) {
goto do_underflow;
}
} else if (exp == 0x7ff) {
exc = FPCR_INV;
} else {
/* Restore implicit bit. */
frac |= 0x10000000000000ull;
shift = exp - 1023 - 52;
if (shift >= 0) {
/* In this case the number is so large that we must shift
the fraction left. There is no rounding to do. */
if (shift < 64) {
ret = frac << shift;
}
/* Check for overflow. Note the special case of -0x1p63. */
if (shift >= 11 && a != 0xC3E0000000000000ull) {
exc = FPCR_IOV | FPCR_INE;
}
} else {
uint64_t round;
/* In this case the number is smaller than the fraction as
represented by the 52 bit number. Here we must think
about rounding the result. Handle this by shifting the
fractional part of the number into the high bits of ROUND.
This will let us efficiently handle round-to-nearest. */
shift = -shift;
if (shift < 63) {
ret = frac >> shift;
round = frac << (64 - shift);
} else {
/* The exponent is so small we shift out everything.
Leave a sticky bit for proper rounding below. */
do_underflow:
round = 1;
}
exc = get_float_exception_flags(&FP_STATUS);
if (unlikely(exc)) {
set_float_exception_flags(0, &FP_STATUS);
if (round) {
exc = FPCR_INE;
switch (roundmode) {
case float_round_nearest_even:
if (round == (1ull << 63)) {
/* Fraction is exactly 0.5; round to even. */
ret += (ret & 1);
} else if (round > (1ull << 63)) {
ret += 1;
}
break;
case float_round_to_zero:
break;
case float_round_up:
ret += 1 - sign;
break;
case float_round_down:
ret += sign;
break;
}
/* We need to massage the resulting exceptions. */
if (exc & float_flag_invalid_cvti) {
/* Overflow, either normal or infinity. */
if (float64_is_infinity(fa)) {
exc = FPCR_INV;
} else {
exc = FPCR_IOV | FPCR_INE;
}
}
if (sign) {
ret = -ret;
} else if (exc & float_flag_invalid) {
exc = FPCR_INV;
} else if (exc & float_flag_inexact) {
exc = FPCR_INE;
}
}
env->error_code = exc;

Loading…
Cancel
Save