On Mon, Jun 30, 2014 at 11:39:43AM -0700, Richard Henderson wrote: > Looks good. > > I've split it up into a couple of smaller patches, made some sylistic tweaks > and pushed it to > > git://github.com/rth7680/qemu.git axp-next > > I'm starting to do some testing now, but a glance though would be helpful. > Especially to see if I didn't make some silly mistake in the process.
The only problem I see at a glance is that CVTTQ should raise IOV|INE in ranges 2^63..2^64-1 and -2^64+1..-2^63-1 as well. That's what this || ((int64_t)(ret-sign) < 0) thing there was about and yes, it does match the behaviour of actual hardware (verified both on EV45 and EV67). FWIW, it might be better to do what float64_to_int64_round_to_zero() is doing - i.e. if (shift >= 0) { if (shift < 64) ret = frac << shift; if (shift < 11 || a == LIT64(0xC3E0000000000000)) exc = 0; } since frac is between 1ULL<<52 and (1ULL<<53)-1, i.e. shift greater than 11 is guaranteed to overflow, shift less than 11 is guaranteed not to and shift exactly 11 won't overflow only in one case - frac == 1ULL<<52, sign = 1 (i.e. when we have -2^63 there). BTW, shift == 63 is interesting - we certainly overflow, but we want the result to be 0 or 2^63 depending on the least significant bit of mantissa, not "always 0". IOW, 0x4720000000000000 should yield IOV|INE, with result being 0 and 0x4720000000000001 - IOV|INE and result 0x8000000000000000. Again, verified on actual hardware; the last patch I posted had been incorrect in the last case (both cases yield 0 with it, same as in mainline qemu). Incremental on top of your branch would be diff --git a/target-alpha/fpu_helper.c b/target-alpha/fpu_helper.c --- a/target-alpha/fpu_helper.c +++ b/target-alpha/fpu_helper.c @@ -722,12 +722,10 @@ static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a, /* In this case the number is so large that we must shift the fraction left. There is no rounding to do. */ exc = float_flag_int_overflow | float_flag_inexact; - if (shift < 63) { - ret = frac << shift; - if ((ret >> shift) == frac) { - exc = 0; - } - } + if (shift < 64) + ret = frac << shift; + if (shift < 11 || a == LIT64( 0xC3E0000000000000)) + exc = 0; } else { uint64_t round;