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>
This commit is contained in:
Richard Henderson 2023-05-27 07:19:09 -07:00
parent 7012b69184
commit aa3bad5b59

View File

@ -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;
exc = get_float_exception_flags(&FP_STATUS);
if (unlikely(exc)) {
set_float_exception_flags(0, &FP_STATUS);
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) {
/* 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;
}
} 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;
}
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;
}
}
}
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;