All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] target-alpha: An approach to fp insn qualifiers
@ 2009-12-14 18:02 Richard Henderson
  2009-12-14 20:11 ` Laurent Desnogues
  0 siblings, 1 reply; 9+ messages in thread
From: Richard Henderson @ 2009-12-14 18:02 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1196 bytes --]

One of the other folks here (I'm sorry, I've forgotten who as I 
misplaced the mail) passed me a preliminary patch to tackle the missing 
fp rounding mode support.  That patch added helpers to change the 
rounding mode, and injected them before and after every fp insn that 
forced a rounding mode.

After some thought I decided not to pursue this method for the simple 
reason that TCG does not have native floating point code generation. 
Given that we have to call one helper routine to perform the operation, 
we might as well arrange for that same routine to handle the rounding 
mode manipulation.

Indeed, the patch below doesn't just pass the rounding mode to the 
helper, but all of the qualifier fields.  Thus we can avoid a large 
explosion of helper routines for addt{,/u,/su,sui}{,/c,/m,/d}.

To complete the patch I should add some symbolic defines for /s, /u, etc 
to avoid magic constants cluttering the code.  I should figure out what 
I should pass to helper_excp for each arithmetic exception.  I should 
actually implement the arithmetic exceptions.

That said, these two patches are enough to pass the gcc testsuite with 
no regressions over native hardware.

Comments?


r~

[-- Attachment #2: commit-fpu-1 --]
[-- Type: text/plain, Size: 32745 bytes --]

commit 14cb36374f15413abfafb4fc030dcab25a2e0d9a
Author: Richard Henderson <rth@twiddle.net>
Date:   Fri Dec 11 08:40:22 2009 -0800

    Phase 1, adding a "Quals" argument to all of the fpu helpers.

diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index bedd3c0..1521a84 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -41,33 +41,33 @@ DEF_HELPER_1(store_fpcr, void, i64)
 
 DEF_HELPER_1(f_to_memory, i32, i64)
 DEF_HELPER_1(memory_to_f, i64, i32)
-DEF_HELPER_2(addf, i64, i64, i64)
-DEF_HELPER_2(subf, i64, i64, i64)
-DEF_HELPER_2(mulf, i64, i64, i64)
-DEF_HELPER_2(divf, i64, i64, i64)
-DEF_HELPER_1(sqrtf, i64, i64)
+DEF_HELPER_3(addf, i64, i64, i64, i32)
+DEF_HELPER_3(subf, i64, i64, i64, i32)
+DEF_HELPER_3(mulf, i64, i64, i64, i32)
+DEF_HELPER_3(divf, i64, i64, i64, i32)
+DEF_HELPER_2(sqrtf, i64, i64, i32)
 
 DEF_HELPER_1(g_to_memory, i64, i64)
 DEF_HELPER_1(memory_to_g, i64, i64)
-DEF_HELPER_2(addg, i64, i64, i64)
-DEF_HELPER_2(subg, i64, i64, i64)
-DEF_HELPER_2(mulg, i64, i64, i64)
-DEF_HELPER_2(divg, i64, i64, i64)
-DEF_HELPER_1(sqrtg, i64, i64)
+DEF_HELPER_3(addg, i64, i64, i64, i32)
+DEF_HELPER_3(subg, i64, i64, i64, i32)
+DEF_HELPER_3(mulg, i64, i64, i64, i32)
+DEF_HELPER_3(divg, i64, i64, i64, i32)
+DEF_HELPER_2(sqrtg, i64, i64, i32)
 
 DEF_HELPER_1(s_to_memory, i32, i64)
 DEF_HELPER_1(memory_to_s, i64, i32)
-DEF_HELPER_2(adds, i64, i64, i64)
-DEF_HELPER_2(subs, i64, i64, i64)
-DEF_HELPER_2(muls, i64, i64, i64)
-DEF_HELPER_2(divs, i64, i64, i64)
-DEF_HELPER_1(sqrts, i64, i64)
-
-DEF_HELPER_2(addt, i64, i64, i64)
-DEF_HELPER_2(subt, i64, i64, i64)
-DEF_HELPER_2(mult, i64, i64, i64)
-DEF_HELPER_2(divt, i64, i64, i64)
-DEF_HELPER_1(sqrtt, i64, i64)
+DEF_HELPER_3(adds, i64, i64, i64, i32)
+DEF_HELPER_3(subs, i64, i64, i64, i32)
+DEF_HELPER_3(muls, i64, i64, i64, i32)
+DEF_HELPER_3(divs, i64, i64, i64, i32)
+DEF_HELPER_2(sqrts, i64, i64, i32)
+
+DEF_HELPER_3(addt, i64, i64, i64, i32)
+DEF_HELPER_3(subt, i64, i64, i64, i32)
+DEF_HELPER_3(mult, i64, i64, i64, i32)
+DEF_HELPER_3(divt, i64, i64, i64, i32)
+DEF_HELPER_2(sqrtt, i64, i64, i32)
 
 DEF_HELPER_2(cmptun, i64, i64, i64)
 DEF_HELPER_2(cmpteq, i64, i64, i64)
@@ -81,15 +81,15 @@ DEF_HELPER_2(cpys, i64, i64, i64)
 DEF_HELPER_2(cpysn, i64, i64, i64)
 DEF_HELPER_2(cpyse, i64, i64, i64)
 
-DEF_HELPER_1(cvtts, i64, i64)
-DEF_HELPER_1(cvtst, i64, i64)
-DEF_HELPER_1(cvttq, i64, i64)
-DEF_HELPER_1(cvtqs, i64, i64)
-DEF_HELPER_1(cvtqt, i64, i64)
-DEF_HELPER_1(cvtqf, i64, i64)
-DEF_HELPER_1(cvtgf, i64, i64)
-DEF_HELPER_1(cvtgq, i64, i64)
-DEF_HELPER_1(cvtqg, i64, i64)
+DEF_HELPER_2(cvtts, i64, i64, i32)
+DEF_HELPER_2(cvtst, i64, i64, i32)
+DEF_HELPER_2(cvttq, i64, i64, i32)
+DEF_HELPER_2(cvtqs, i64, i64, i32)
+DEF_HELPER_2(cvtqt, i64, i64, i32)
+DEF_HELPER_2(cvtqf, i64, i64, i32)
+DEF_HELPER_2(cvtgf, i64, i64, i32)
+DEF_HELPER_2(cvtgq, i64, i64, i32)
+DEF_HELPER_2(cvtqg, i64, i64, i32)
 DEF_HELPER_1(cvtlq, i64, i64)
 DEF_HELPER_1(cvtql, i64, i64)
 DEF_HELPER_1(cvtqlv, i64, i64)
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index b2abf6c..b12c783 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -370,6 +370,85 @@ uint64_t helper_unpkbw (uint64_t op1)
 
 /* Floating point helpers */
 
+/* If the floating-point qualifiers specified a rounding mode,
+   set that rounding mode and remember the original mode for
+   resetting at the end of the instruction.  */
+static inline uint32_t begin_quals_roundmode(uint32_t qual)
+{
+    uint32_t rm = FP_STATUS.float_rounding_mode, old_rm = rm;
+
+    switch (qual & 0xc0) {
+    case 0x80:
+        rm = float_round_nearest_even;
+        break;
+    case 0x00:
+        rm = float_round_to_zero;
+        break;
+    case 0x40:
+        rm = float_round_down;
+        break;
+    case 0xc0:
+        return old_rm;
+    }
+    set_float_rounding_mode(rm, &FP_STATUS);
+    return old_rm;
+}
+
+/* If the floating-point qualifiers specified extra exception processing
+   (i.e. /u or /su), zero the exception flags so that we can determine if
+   the current instruction raises any exceptions.  Save the old acrued
+   exception status so that we can restore them at the end of the insn.  */
+static inline uint32_t begin_quals_exception(uint32_t qual)
+{
+    uint32_t old_exc = 0;
+    if (qual & 0x500) {
+        old_exc = (uint32_t)FP_STATUS.float_exception_flags << 8;
+        set_float_exception_flags(0, &FP_STATUS);
+    }
+    return old_exc;
+}
+
+/* Begin processing an fp operation.  Return a token that should be passed
+   when completing the fp operation.  */
+static inline uint32_t begin_fp(uint32_t quals)
+{
+    uint32_t ret = 0;
+
+    ret |= begin_quals_roundmode(quals);
+    ret |= begin_quals_exception(quals);
+
+    return ret;
+}
+
+/* End processing an fp operation.  */
+static inline void end_fp(uint32_t quals, uint32_t orig)
+{
+    uint8_t exc = FP_STATUS.float_exception_flags;
+
+    set_float_exception_flags(exc | (orig >> 8), &FP_STATUS);
+    set_float_rounding_mode(orig & 0xff, &FP_STATUS);
+
+    /* TODO: check quals and exc and raise any exceptions needed.  */
+}
+
+/* Raise any exceptions needed for using F, given the insn qualifiers.  */
+static inline void float32_input(uint32_t quals, float32 f)
+{
+    /* If /s is used, no exceptions are raised immediately.  */
+    /* ??? This for userspace only.  If we are emulating the real hw, then
+       we may well need to trap to the kernel for software emulation.  */
+    /* ??? Shouldn't we raise an exception for SNAN?  */
+    if (quals & 0x500)
+        return;
+    /* TODO: Check for inf, nan, denormal and trap.  */
+}
+
+static inline void float64_input(uint32_t quals, float64 f)
+{
+    /* TODO: Exactly like above, except for float64.  */
+}
+
+
 /* F floating (VAX) */
 static inline uint64_t float32_to_f(float32 fa)
 {
@@ -447,52 +526,86 @@ uint64_t helper_memory_to_f (uint32_t a)
     return r;
 }
 
-uint64_t helper_addf (uint64_t a, uint64_t b)
+uint64_t helper_addf (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = f_to_float32(a);
     fb = f_to_float32(b);
+
+    token = begin_fp(quals);
+    float32_input(quals, fa);
+    float32_input(quals, fb);
     fr = float32_add(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_subf (uint64_t a, uint64_t b)
+uint64_t helper_subf (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = f_to_float32(a);
     fb = f_to_float32(b);
+
+    token = begin_fp(quals);
+    float32_input(quals, fa);
+    float32_input(quals, fb);
     fr = float32_sub(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_mulf (uint64_t a, uint64_t b)
+uint64_t helper_mulf (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = f_to_float32(a);
     fb = f_to_float32(b);
+
+    token = begin_fp(quals);
+    float32_input(quals, fa);
+    float32_input(quals, fb);
     fr = float32_mul(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_divf (uint64_t a, uint64_t b)
+uint64_t helper_divf (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = f_to_float32(a);
     fb = f_to_float32(b);
+
+    token = begin_fp(quals);
+    float32_input(quals, fa);
+    float32_input(quals, fb);
     fr = float32_div(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_sqrtf (uint64_t t)
+uint64_t helper_sqrtf (uint64_t t, uint32_t quals)
 {
     float32 ft, fr;
+    uint32_t token;
 
     ft = f_to_float32(t);
+
+    token = begin_fp(quals);
+    float32_input(quals, ft);
     fr = float32_sqrt(ft, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
@@ -574,52 +687,86 @@ uint64_t helper_memory_to_g (uint64_t a)
     return r;
 }
 
-uint64_t helper_addg (uint64_t a, uint64_t b)
+uint64_t helper_addg (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
     fa = g_to_float64(a);
     fb = g_to_float64(b);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
+    float64_input(quals, fb);
     fr = float64_add(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
-uint64_t helper_subg (uint64_t a, uint64_t b)
+uint64_t helper_subg (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
     fa = g_to_float64(a);
     fb = g_to_float64(b);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
+    float64_input(quals, fb);
     fr = float64_sub(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
-uint64_t helper_mulg (uint64_t a, uint64_t b)
+uint64_t helper_mulg (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
-
+    uint32_t token;
+    
     fa = g_to_float64(a);
     fb = g_to_float64(b);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
+    float64_input(quals, fb);
     fr = float64_mul(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
-uint64_t helper_divg (uint64_t a, uint64_t b)
+uint64_t helper_divg (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
     fa = g_to_float64(a);
     fb = g_to_float64(b);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
+    float64_input(quals, fb);
     fr = float64_div(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
-uint64_t helper_sqrtg (uint64_t a)
+uint64_t helper_sqrtg (uint64_t a, uint32_t quals)
 {
     float64 fa, fr;
+    uint32_t token;
 
     fa = g_to_float64(a);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
     fr = float64_sqrt(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
@@ -678,52 +825,86 @@ uint64_t helper_memory_to_s (uint32_t a)
     return float32_to_s_int(a);
 }
 
-uint64_t helper_adds (uint64_t a, uint64_t b)
+uint64_t helper_adds (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = s_to_float32(a);
     fb = s_to_float32(b);
+
+    token = begin_fp(quals);
+    float32_input(quals, fa);
+    float32_input(quals, fb);
     fr = float32_add(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_subs (uint64_t a, uint64_t b)
+uint64_t helper_subs (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = s_to_float32(a);
     fb = s_to_float32(b);
+
+    token = begin_fp(quals);
+    float32_input(quals, fa);
+    float32_input(quals, fb);
     fr = float32_sub(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_muls (uint64_t a, uint64_t b)
+uint64_t helper_muls (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = s_to_float32(a);
     fb = s_to_float32(b);
+
+    token = begin_fp(quals);
+    float32_input(quals, fa);
+    float32_input(quals, fb);
     fr = float32_mul(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_divs (uint64_t a, uint64_t b)
+uint64_t helper_divs (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = s_to_float32(a);
     fb = s_to_float32(b);
+
+    token = begin_fp(quals);
+    float32_input(quals, fa);
+    float32_input(quals, fb);
     fr = float32_div(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_sqrts (uint64_t a)
+uint64_t helper_sqrts (uint64_t a, uint32_t quals)
 {
     float32 fa, fr;
+    uint32_t token;
 
     fa = s_to_float32(a);
+
+    token = begin_fp(quals);
+    float32_input(quals, fa);
     fr = float32_sqrt(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
@@ -745,52 +926,86 @@ static inline uint64_t float64_to_t(float64 fa)
     return r.ll;
 }
 
-uint64_t helper_addt (uint64_t a, uint64_t b)
+uint64_t helper_addt (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
     fa = t_to_float64(a);
     fb = t_to_float64(b);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
+    float64_input(quals, fb);
     fr = float64_add(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
-uint64_t helper_subt (uint64_t a, uint64_t b)
+uint64_t helper_subt (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
     fa = t_to_float64(a);
     fb = t_to_float64(b);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
+    float64_input(quals, fb);
     fr = float64_sub(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+    
     return float64_to_t(fr);
 }
 
-uint64_t helper_mult (uint64_t a, uint64_t b)
+uint64_t helper_mult (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
     fa = t_to_float64(a);
     fb = t_to_float64(b);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
+    float64_input(quals, fb);
     fr = float64_mul(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
-uint64_t helper_divt (uint64_t a, uint64_t b)
+uint64_t helper_divt (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
     fa = t_to_float64(a);
     fb = t_to_float64(b);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
+    float64_input(quals, fb);
     fr = float64_div(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
-uint64_t helper_sqrtt (uint64_t a)
+uint64_t helper_sqrtt (uint64_t a, uint32_t quals)
 {
     float64 fa, fr;
+    uint32_t token;
 
     fa = t_to_float64(a);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
     fr = float64_sqrt(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
@@ -905,70 +1120,131 @@ uint64_t helper_cmpglt(uint64_t a, uint64_t b)
 }
 
 /* Floating point format conversion */
-uint64_t helper_cvtts (uint64_t a)
+uint64_t helper_cvtts (uint64_t a, uint32_t quals)
 {
     float64 fa;
     float32 fr;
+    uint32_t token;
 
     fa = t_to_float64(a);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
     fr = float64_to_float32(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_cvtst (uint64_t a)
+uint64_t helper_cvtst (uint64_t a, uint32_t quals)
 {
     float32 fa;
     float64 fr;
+    uint32_t token;
 
     fa = s_to_float32(a);
+
+    token = begin_fp(quals);
+    float32_input(quals, fa);
     fr = float32_to_float64(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
-uint64_t helper_cvtqs (uint64_t a)
+uint64_t helper_cvtqs (uint64_t a, uint32_t quals)
 {
-    float32 fr = int64_to_float32(a, &FP_STATUS);
+    float32 fr;
+    uint32_t token;
+
+    token = begin_fp(quals);
+    fr = int64_to_float32(a, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_cvttq (uint64_t a)
+uint64_t helper_cvttq (uint64_t a, uint32_t quals)
 {
-    float64 fa = t_to_float64(a);
-    return float64_to_int64_round_to_zero(fa, &FP_STATUS);
+    float64 fa;
+    uint64_t ret;
+    uint32_t token;
+
+    fa = t_to_float64(a);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
+    ret = float64_to_int64(fa, &FP_STATUS);
+    end_fp(quals, token);
+
+    return ret;
 }
 
-uint64_t helper_cvtqt (uint64_t a)
+uint64_t helper_cvtqt (uint64_t a, uint32_t quals)
 {
-    float64 fr = int64_to_float64(a, &FP_STATUS);
+    float64 fr;
+    uint32_t token;
+
+    token = begin_fp(quals);
+    fr = int64_to_float64(a, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
-uint64_t helper_cvtqf (uint64_t a)
+uint64_t helper_cvtqf (uint64_t a, uint32_t quals)
 {
-    float32 fr = int64_to_float32(a, &FP_STATUS);
+    float32 fr;
+    uint32_t token;
+
+    token = begin_fp(quals);
+    fr = int64_to_float32(a, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_cvtgf (uint64_t a)
+uint64_t helper_cvtgf (uint64_t a, uint32_t quals)
 {
     float64 fa;
     float32 fr;
+    uint32_t token;
 
     fa = g_to_float64(a);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
     fr = float64_to_float32(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_cvtgq (uint64_t a)
+uint64_t helper_cvtgq (uint64_t a, uint32_t quals)
 {
-    float64 fa = g_to_float64(a);
-    return float64_to_int64_round_to_zero(fa, &FP_STATUS);
+    float64 fa;
+    uint64_t ret;
+    uint32_t token;
+
+    fa = g_to_float64(a);
+
+    token = begin_fp(quals);
+    float64_input(quals, fa);
+    ret = float64_to_int64(fa, &FP_STATUS);
+    end_fp(quals, token);
+
+    return ret;
 }
 
-uint64_t helper_cvtqg (uint64_t a)
+uint64_t helper_cvtqg (uint64_t a, uint32_t quals)
 {
     float64 fr;
+    uint32_t token;
+
+    token = begin_fp(quals);
     fr = int64_to_float64(a, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index be7e7bf..7b6ff2a 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -442,81 +442,79 @@ static void gen_fcmov(TCGCond inv_cond, int ra, int rb, int rc)
     gen_set_label(l1);
 }
 
-#define FARITH2(name)                                       \
-static inline void glue(gen_f, name)(int rb, int rc)        \
-{                                                           \
-    if (unlikely(rc == 31))                                 \
-      return;                                               \
-                                                            \
-    if (rb != 31)                                           \
-        gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb]);    \
-    else {                                                  \
-        TCGv tmp = tcg_const_i64(0);                        \
-        gen_helper_ ## name (cpu_fir[rc], tmp);            \
-        tcg_temp_free(tmp);                                 \
-    }                                                       \
+#define FARITH2(name)                                   \
+static inline void glue(gen_f, name)(int rb, int rc)    \
+{                                                       \
+    if (unlikely(rc == 31))                             \
+      return;                                           \
+                                                        \
+    if (rb != 31)                                       \
+        gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb]); \
+    else {                                              \
+        TCGv tmp = tcg_const_i64(0);                    \
+        gen_helper_ ## name (cpu_fir[rc], tmp);         \
+        tcg_temp_free(tmp);                             \
+    }                                                   \
 }
-FARITH2(sqrts)
-FARITH2(sqrtf)
-FARITH2(sqrtg)
-FARITH2(sqrtt)
-FARITH2(cvtgf)
-FARITH2(cvtgq)
-FARITH2(cvtqf)
-FARITH2(cvtqg)
-FARITH2(cvtst)
-FARITH2(cvtts)
-FARITH2(cvttq)
-FARITH2(cvtqs)
-FARITH2(cvtqt)
 FARITH2(cvtlq)
 FARITH2(cvtql)
 FARITH2(cvtqlv)
 FARITH2(cvtqlsv)
 
-#define FARITH3(name)                                                     \
-static inline void glue(gen_f, name)(int ra, int rb, int rc)              \
-{                                                                         \
-    if (unlikely(rc == 31))                                               \
-        return;                                                           \
-                                                                          \
-    if (ra != 31) {                                                       \
-        if (rb != 31)                                                     \
-            gen_helper_ ## name (cpu_fir[rc], cpu_fir[ra], cpu_fir[rb]);  \
-        else {                                                            \
-            TCGv tmp = tcg_const_i64(0);                                  \
-            gen_helper_ ## name (cpu_fir[rc], cpu_fir[ra], tmp);          \
-            tcg_temp_free(tmp);                                           \
-        }                                                                 \
-    } else {                                                              \
-        TCGv tmp = tcg_const_i64(0);                                      \
-        if (rb != 31)                                                     \
-            gen_helper_ ## name (cpu_fir[rc], tmp, cpu_fir[rb]);          \
-        else                                                              \
-            gen_helper_ ## name (cpu_fir[rc], tmp, tmp);                   \
-        tcg_temp_free(tmp);                                               \
-    }                                                                     \
+#define QFARITH2(name)                                          \
+static inline void glue(gen_f, name)(int rb, int rc, int opc)   \
+{                                                               \
+    TCGv_i32 quals;                                             \
+    if (unlikely(rc == 31))                                     \
+      return;                                                   \
+    quals = tcg_const_i32(opc & ~0x3f);                         \
+    if (rb != 31)                                               \
+        gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb], quals);  \
+    else {                                                      \
+        TCGv tmp = tcg_const_i64(0);                            \
+        gen_helper_ ## name (cpu_fir[rc], tmp, quals);          \
+        tcg_temp_free(tmp);                                     \
+    }                                                           \
+    tcg_temp_free_i32(quals);                                   \
+}
+QFARITH2(sqrts)
+QFARITH2(sqrtf)
+QFARITH2(sqrtg)
+QFARITH2(sqrtt)
+QFARITH2(cvtgf)
+QFARITH2(cvtgq)
+QFARITH2(cvtqf)
+QFARITH2(cvtqg)
+QFARITH2(cvtst)
+QFARITH2(cvtts)
+QFARITH2(cvttq)
+QFARITH2(cvtqs)
+QFARITH2(cvtqt)
+
+#define FARITH3(name)                                           \
+static inline void glue(gen_f, name)(int ra, int rb, int rc)    \
+{                                                               \
+    TCGv zero, ta, tb;                                          \
+    if (unlikely(rc == 31))                                     \
+        return;                                                 \
+    ta = cpu_fir[ra];                                           \
+    tb = cpu_fir[rb];                                           \
+    if (unlikely(ra == 31)) {                                   \
+        zero = tcg_const_i64(0);                                \
+        ta = zero;                                              \
+    }                                                           \
+    if (unlikely(rb == 31)) {                                   \
+        if (ra != 31)                                           \
+            zero = tcg_const_i64(0);                            \
+        tb = zero;                                              \
+    }                                                           \
+    gen_helper_ ## name (cpu_fir[rc], ta, tb);                  \
+    if (ra == 31 || rb == 31)                                   \
+        tcg_temp_free(zero);                                    \
 }
-
-FARITH3(addf)
-FARITH3(subf)
-FARITH3(mulf)
-FARITH3(divf)
-FARITH3(addg)
-FARITH3(subg)
-FARITH3(mulg)
-FARITH3(divg)
 FARITH3(cmpgeq)
 FARITH3(cmpglt)
 FARITH3(cmpgle)
-FARITH3(adds)
-FARITH3(subs)
-FARITH3(muls)
-FARITH3(divs)
-FARITH3(addt)
-FARITH3(subt)
-FARITH3(mult)
-FARITH3(divt)
 FARITH3(cmptun)
 FARITH3(cmpteq)
 FARITH3(cmptlt)
@@ -525,6 +523,47 @@ FARITH3(cpys)
 FARITH3(cpysn)
 FARITH3(cpyse)
 
+#define QFARITH3(name)                                                  \
+static inline void glue(gen_f, name)(int ra, int rb, int rc, int opc)   \
+{                                                                       \
+    TCGv zero, ta, tb;                                                  \
+    TCGv_i32 quals;                                                     \
+    if (unlikely(rc == 31))                                             \
+        return;                                                         \
+    ta = cpu_fir[ra];                                                   \
+    tb = cpu_fir[rb];                                                   \
+    if (unlikely(ra == 31)) {                                           \
+        zero = tcg_const_i64(0);                                        \
+        ta = zero;                                                      \
+    }                                                                   \
+    if (unlikely(rb == 31)) {                                           \
+        if (ra != 31)                                                   \
+            zero = tcg_const_i64(0);                                    \
+        tb = zero;                                                      \
+    }                                                                   \
+    quals = tcg_const_i32(opc & ~0x3f);                                 \
+    gen_helper_ ## name (cpu_fir[rc], ta, tb, quals);                   \
+    tcg_temp_free_i32(quals);                                           \
+    if (ra == 31 || rb == 31)                                           \
+        tcg_temp_free(zero);                                            \
+}
+QFARITH3(addf)
+QFARITH3(subf)
+QFARITH3(mulf)
+QFARITH3(divf)
+QFARITH3(addg)
+QFARITH3(subg)
+QFARITH3(mulg)
+QFARITH3(divg)
+QFARITH3(adds)
+QFARITH3(subs)
+QFARITH3(muls)
+QFARITH3(divs)
+QFARITH3(addt)
+QFARITH3(subt)
+QFARITH3(mult)
+QFARITH3(divt)
+
 static inline uint64_t zapnot_mask(uint8_t lit)
 {
     uint64_t mask = 0;
@@ -1607,7 +1646,7 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
         }
         break;
     case 0x14:
-        switch (fpfn) { /* f11 & 0x3F */
+        switch (fpfn) { /* fn11 & 0x3F */
         case 0x04:
             /* ITOFS */
             if (!(ctx->amask & AMASK_FIX))
@@ -1626,13 +1665,13 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
             /* SQRTF */
             if (!(ctx->amask & AMASK_FIX))
                 goto invalid_opc;
-            gen_fsqrtf(rb, rc);
+            gen_fsqrtf(rb, rc, fn11);
             break;
         case 0x0B:
             /* SQRTS */
             if (!(ctx->amask & AMASK_FIX))
                 goto invalid_opc;
-            gen_fsqrts(rb, rc);
+            gen_fsqrts(rb, rc, fn11);
             break;
         case 0x14:
             /* ITOFF */
@@ -1663,13 +1702,13 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
             /* SQRTG */
             if (!(ctx->amask & AMASK_FIX))
                 goto invalid_opc;
-            gen_fsqrtg(rb, rc);
+            gen_fsqrtg(rb, rc, fn11);
             break;
         case 0x02B:
             /* SQRTT */
             if (!(ctx->amask & AMASK_FIX))
                 goto invalid_opc;
-            gen_fsqrtt(rb, rc);
+            gen_fsqrtt(rb, rc, fn11);
             break;
         default:
             goto invalid_opc;
@@ -1677,47 +1716,42 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
         break;
     case 0x15:
         /* VAX floating point */
-        /* XXX: rounding mode and trap are ignored (!) */
-        switch (fpfn) { /* f11 & 0x3F */
+        switch (fpfn) { /* fn11 & 0x3F */
         case 0x00:
             /* ADDF */
-            gen_faddf(ra, rb, rc);
+            gen_faddf(ra, rb, rc, fn11);
             break;
         case 0x01:
             /* SUBF */
-            gen_fsubf(ra, rb, rc);
+            gen_fsubf(ra, rb, rc, fn11);
             break;
         case 0x02:
             /* MULF */
-            gen_fmulf(ra, rb, rc);
+            gen_fmulf(ra, rb, rc, fn11);
             break;
         case 0x03:
             /* DIVF */
-            gen_fdivf(ra, rb, rc);
+            gen_fdivf(ra, rb, rc, fn11);
             break;
         case 0x1E:
             /* CVTDG */
-#if 0 // TODO
-            gen_fcvtdg(rb, rc);
-#else
+            /* TODO */
             goto invalid_opc;
-#endif
-            break;
         case 0x20:
             /* ADDG */
-            gen_faddg(ra, rb, rc);
+            gen_faddg(ra, rb, rc, fn11);
             break;
         case 0x21:
             /* SUBG */
-            gen_fsubg(ra, rb, rc);
+            gen_fsubg(ra, rb, rc, fn11);
             break;
         case 0x22:
             /* MULG */
-            gen_fmulg(ra, rb, rc);
+            gen_fmulg(ra, rb, rc, fn11);
             break;
         case 0x23:
             /* DIVG */
-            gen_fdivg(ra, rb, rc);
+            gen_fdivg(ra, rb, rc, fn11);
             break;
         case 0x25:
             /* CMPGEQ */
@@ -1733,27 +1767,23 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
             break;
         case 0x2C:
             /* CVTGF */
-            gen_fcvtgf(rb, rc);
+            gen_fcvtgf(rb, rc, fn11);
             break;
         case 0x2D:
             /* CVTGD */
-#if 0 // TODO
-            gen_fcvtgd(rb, rc);
-#else
+            /* TODO */
             goto invalid_opc;
-#endif
-            break;
         case 0x2F:
             /* CVTGQ */
-            gen_fcvtgq(rb, rc);
+            gen_fcvtgq(rb, rc, fn11);
             break;
         case 0x3C:
             /* CVTQF */
-            gen_fcvtqf(rb, rc);
+            gen_fcvtqf(rb, rc, fn11);
             break;
         case 0x3E:
             /* CVTQG */
-            gen_fcvtqg(rb, rc);
+            gen_fcvtqg(rb, rc, fn11);
             break;
         default:
             goto invalid_opc;
@@ -1761,39 +1791,38 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
         break;
     case 0x16:
         /* IEEE floating-point */
-        /* XXX: rounding mode and traps are ignored (!) */
-        switch (fpfn) { /* f11 & 0x3F */
+        switch (fpfn) { /* fn11 & 0x3F */
         case 0x00:
             /* ADDS */
-            gen_fadds(ra, rb, rc);
+            gen_fadds(ra, rb, rc, fn11);
             break;
         case 0x01:
             /* SUBS */
-            gen_fsubs(ra, rb, rc);
+            gen_fsubs(ra, rb, rc, fn11);
             break;
         case 0x02:
             /* MULS */
-            gen_fmuls(ra, rb, rc);
+            gen_fmuls(ra, rb, rc, fn11);
             break;
         case 0x03:
             /* DIVS */
-            gen_fdivs(ra, rb, rc);
+            gen_fdivs(ra, rb, rc, fn11);
             break;
         case 0x20:
             /* ADDT */
-            gen_faddt(ra, rb, rc);
+            gen_faddt(ra, rb, rc, fn11);
             break;
         case 0x21:
             /* SUBT */
-            gen_fsubt(ra, rb, rc);
+            gen_fsubt(ra, rb, rc, fn11);
             break;
         case 0x22:
             /* MULT */
-            gen_fmult(ra, rb, rc);
+            gen_fmult(ra, rb, rc, fn11);
             break;
         case 0x23:
             /* DIVT */
-            gen_fdivt(ra, rb, rc);
+            gen_fdivt(ra, rb, rc, fn11);
             break;
         case 0x24:
             /* CMPTUN */
@@ -1812,26 +1841,25 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
             gen_fcmptle(ra, rb, rc);
             break;
         case 0x2C:
-            /* XXX: incorrect */
             if (fn11 == 0x2AC || fn11 == 0x6AC) {
                 /* CVTST */
-                gen_fcvtst(rb, rc);
+                gen_fcvtst(rb, rc, fn11);
             } else {
                 /* CVTTS */
-                gen_fcvtts(rb, rc);
+                gen_fcvtts(rb, rc, fn11);
             }
             break;
         case 0x2F:
             /* CVTTQ */
-            gen_fcvttq(rb, rc);
+            gen_fcvttq(rb, rc, fn11);
             break;
         case 0x3C:
             /* CVTQS */
-            gen_fcvtqs(rb, rc);
+            gen_fcvtqs(rb, rc, fn11);
             break;
         case 0x3E:
             /* CVTQT */
-            gen_fcvtqt(rb, rc);
+            gen_fcvtqt(rb, rc, fn11);
             break;
         default:
             goto invalid_opc;

[-- Attachment #3: commit-fpu-2 --]
[-- Type: text/plain, Size: 4886 bytes --]

commit a0cc18be5837339ad6da257a93597fc81a28c042
Author: Richard Henderson <rth@twiddle.net>
Date:   Mon Dec 14 09:31:22 2009 -0800

    target-alpha: Fix cvttq.
    
    The alpha fp-integer conversion instruction truncates
    instead of saturating like the generic IEEE version does.

diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index b12c783..3bb0020 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -24,7 +24,7 @@
 
 /*****************************************************************************/
 /* Exceptions processing helpers */
-void helper_excp (int excp, int error)
+void QEMU_NORETURN helper_excp (int excp, int error)
 {
     env->exception_index = excp;
     env->error_code = error;
@@ -1166,15 +1166,112 @@ uint64_t helper_cvtqs (uint64_t a, uint32_t quals)
 
 uint64_t helper_cvttq (uint64_t a, uint32_t quals)
 {
-    float64 fa;
-    uint64_t ret;
-    uint32_t token;
-
-    fa = t_to_float64(a);
+    uint64_t ret, frac;
+    uint32_t token, exp, sign, exc = 0;
 
     token = begin_fp(quals);
-    float64_input(quals, fa);
-    ret = float64_to_int64(fa, &FP_STATUS);
+
+    /* Alpha integer conversion does not saturate, as the generic routine
+       does.  Instead it supplies a truncated result.  This fact is relied
+       upon by GCC in that without overflow enabled we can get unsigned
+       conversion for free with the same instruction.  */
+
+    sign = (a >> 63);
+    exp = (uint32_t)(a >> 52) & 0x7ff;
+    frac = a & 0xfffffffffffffull;
+
+    if (exp == 0) {
+        ret = 0;
+        if (frac != 0) {
+            /* ??? If DNZ set, map to zero without trapping.  */
+            /* ??? Figure out what kind of exception signal to send.  */
+            if (!(quals & 0x400))
+                helper_excp(EXCP_ARITH, 0);
+            goto do_underflow;
+        }
+    } else if (exp == 0x7ff) {
+        /* In keeping with the truncation result, both infinity and NaN
+           give result of zero.  See Table B-2 in the Alpha Architecture
+           Handbook.  */
+        ret = 0;
+        exc = float_flag_invalid;
+
+        /* Without /s qualifier, both Inf and NaN trap.  SNaN always traps. */
+        if (!(quals & 0x400) || (frac & 0x4000000000000ull))
+            helper_excp(EXCP_ARITH, 0);
+    } else {
+        int32_t shift;
+
+        /* 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, but we
+               must still set inexact for overflow.  */
+            if (shift < 63) {
+                ret = frac << shift;
+                if ((ret >> shift) != frac)
+                    exc = float_flag_inexact;
+            } else {
+                exc = float_flag_inexact;
+                ret = 0;
+            }
+        } else if (shift == 0) {
+            /* The exponent is exactly right for the 52-bit fraction.  */
+            ret = frac;
+        } 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 {
+            do_underflow:
+                /* The exponent is so small we shift out everything.  */
+                ret = 0;
+                round = 1;
+            }
+
+            if (round) {
+                exc = float_flag_inexact;
+                switch (FP_STATUS.float_rounding_mode) {
+                case float_round_nearest_even:
+                    if (round == (1ull << 63)) {
+                        /* The remaining 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:
+                    if (!sign)
+                        ret += 1;
+                    break;
+                case float_round_down:
+                    if (sign)
+                        ret += 1;
+                    break;
+                }
+            }
+        }
+
+        if (sign)
+            ret = -ret;
+    }
+
+    if (exc)
+        float_raise(exc, &FP_STATUS);
     end_fp(quals, token);
 
     return ret;

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] target-alpha: An approach to fp insn qualifiers
  2009-12-14 18:02 [Qemu-devel] target-alpha: An approach to fp insn qualifiers Richard Henderson
@ 2009-12-14 20:11 ` Laurent Desnogues
  2009-12-14 22:21   ` Richard Henderson
  2009-12-15  0:31   ` Richard Henderson
  0 siblings, 2 replies; 9+ messages in thread
From: Laurent Desnogues @ 2009-12-14 20:11 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Mon, Dec 14, 2009 at 7:02 PM, Richard Henderson <rth@twiddle.net> wrote:
> One of the other folks here (I'm sorry, I've forgotten who as I misplaced
> the mail) passed me a preliminary patch to tackle the missing fp rounding
> mode support.  That patch added helpers to change the rounding mode, and
> injected them before and after every fp insn that forced a rounding mode.

That was me.

> After some thought I decided not to pursue this method for the simple reason
> that TCG does not have native floating point code generation.

I have started implementing TCG FP, but lack the time and desire to
complete it.  The speed up was pretty good when running on an ARM
host with a fast FPU.

> Given that we
> have to call one helper routine to perform the operation, we might as well
> arrange for that same routine to handle the rounding mode manipulation.
>
> Indeed, the patch below doesn't just pass the rounding mode to the helper,
> but all of the qualifier fields.  Thus we can avoid a large explosion of
> helper routines for addt{,/u,/su,sui}{,/c,/m,/d}.

I don't really like passing parts of opcodes to helpers, but as you say
that prevents explosion of helpers.  OTOH you could do lazy calls to
helpers that set rounding modes with my approach of separating them
from computation.

I'll take a closer look at your patch tomorrow.

> To complete the patch I should add some symbolic defines for /s, /u, etc to
> avoid magic constants cluttering the code.  I should figure out what I
> should pass to helper_excp for each arithmetic exception.  I should actually
> implement the arithmetic exceptions.
>
> That said, these two patches are enough to pass the gcc testsuite with no
> regressions over native hardware.

Can you give SPECint 2K equake a try? The symptom was the presence
of many NaN's.  If you don't have access to SPEC2K I'll try it.


Laurent

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] target-alpha: An approach to fp insn qualifiers
  2009-12-14 20:11 ` Laurent Desnogues
@ 2009-12-14 22:21   ` Richard Henderson
  2009-12-15  0:31   ` Richard Henderson
  1 sibling, 0 replies; 9+ messages in thread
From: Richard Henderson @ 2009-12-14 22:21 UTC (permalink / raw)
  To: Laurent Desnogues; +Cc: qemu-devel

On 12/14/2009 12:11 PM, Laurent Desnogues wrote:
> I don't really like passing parts of opcodes to helpers, but as you say
> that prevents explosion of helpers.  OTOH you could do lazy calls to
> helpers that set rounding modes with my approach of separating them
> from computation.

I don't particularly like it either, I just thought it was a bit
more efficient, given the current state of TCG.

If it's not acceptable, I can try to do some macro magic in both
op_helper.c and helper.h to do function replication on the /u,/su,/sui
bits and then follow your lead on the lazy rounding mode setting.

> Can you give SPECint 2K equake a try? The symptom was the presence
> of many NaN's.  If you don't have access to SPEC2K I'll try it.

Yes, I can.  I'll see about setting this up tonight.


r~

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] target-alpha: An approach to fp insn qualifiers
  2009-12-14 20:11 ` Laurent Desnogues
  2009-12-14 22:21   ` Richard Henderson
@ 2009-12-15  0:31   ` Richard Henderson
  2009-12-15  3:50     ` Richard Henderson
  1 sibling, 1 reply; 9+ messages in thread
From: Richard Henderson @ 2009-12-15  0:31 UTC (permalink / raw)
  To: Laurent Desnogues; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 215 bytes --]

On 12/14/2009 12:11 PM, Laurent Desnogues wrote:
> I'll take a closer look at your patch tomorrow.

For the record, I believe this finishes what I had in mind for the 
exception handling there in op_handler.c.


r~

[-- Attachment #2: commit-fpu-3 --]
[-- Type: text/plain, Size: 30931 bytes --]

commit ce6c2abc1d5d437dde980b4addc7da0f0f5de252
Author: Richard Henderson <rth@twiddle.net>
Date:   Mon Dec 14 16:27:39 2009 -0800

    target-alpha: Implement arithmetic exceptions for IEEE fp.

diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index c0dff4b..c1c0470 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -430,9 +430,13 @@ enum {
 };
 
 /* Arithmetic exception */
-enum {
-    EXCP_ARITH_OVERFLOW,
-};
+#define EXC_M_IOV	(1<<16)		/* Integer Overflow */
+#define EXC_M_INE	(1<<15)		/* Inexact result */
+#define EXC_M_UNF	(1<<14)		/* Underflow */
+#define EXC_M_FOV	(1<<13)		/* Overflow */
+#define EXC_M_DZE	(1<<12)		/* Division by zero */
+#define EXC_M_INV	(1<<11)		/* Invalid operation */
+#define EXC_M_SWC	(1<<10)		/* Software completion */
 
 enum {
     IR_V0   = 0,
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index a658f97..a29f785 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -27,41 +27,13 @@
 
 uint64_t cpu_alpha_load_fpcr (CPUState *env)
 {
-    uint64_t ret = 0;
-    int flags, mask;
-
-    flags = env->fp_status.float_exception_flags;
-    ret |= (uint64_t) flags << 52;
-    if (flags)
-        ret |= FPCR_SUM;
-    env->ipr[IPR_EXC_SUM] &= ~0x3E;
-    env->ipr[IPR_EXC_SUM] |= flags << 1;
-
-    mask = env->fp_status.float_exception_mask;
-    if (mask & float_flag_invalid)
-        ret |= FPCR_INVD;
-    if (mask & float_flag_divbyzero)
-        ret |= FPCR_DZED;
-    if (mask & float_flag_overflow)
-        ret |= FPCR_OVFD;
-    if (mask & float_flag_underflow)
-        ret |= FPCR_UNFD;
-    if (mask & float_flag_inexact)
-        ret |= FPCR_INED;
-
-    switch (env->fp_status.float_rounding_mode) {
-    case float_round_nearest_even:
-        ret |= 2ULL << FPCR_DYN_SHIFT;
-        break;
-    case float_round_down:
-        ret |= 1ULL << FPCR_DYN_SHIFT;
-        break;
-    case float_round_up:
-        ret |= 3ULL << FPCR_DYN_SHIFT;
-        break;
-    case float_round_to_zero:
-        break;
-    }
+    uint64_t ret = env->fp_status.float_exception_flags;
+
+    if (ret)
+      ret = FPCR_SUM | (ret << 52);
+
+    ret |= env->fpcr & ~(FPCR_SUM | FPCR_STATUS_MASK);
+
     return ret;
 }
 
@@ -69,6 +41,8 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
 {
     int round_mode, mask;
 
+    env->fpcr = val;
+
     set_float_exception_flags((val >> 52) & 0x3F, &env->fp_status);
 
     mask = 0;
@@ -86,6 +60,7 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
 
     switch ((val >> FPCR_DYN_SHIFT) & 3) {
     case 0:
+    default:
         round_mode = float_round_to_zero;
         break;
     case 1:
@@ -99,6 +74,11 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
         break;
     }
     set_float_rounding_mode(round_mode, &env->fp_status);
+
+    mask = 0;
+    if ((val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD))
+        mask = 1;
+    set_flush_to_zero(mask, &env->fp_status);
 }
 
 #if defined(CONFIG_USER_ONLY)
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 3bb0020..d031f56 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -78,7 +78,7 @@ uint64_t helper_addqv (uint64_t op1, uint64_t op2)
     uint64_t tmp = op1;
     op1 += op2;
     if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return op1;
 }
@@ -88,7 +88,7 @@ uint64_t helper_addlv (uint64_t op1, uint64_t op2)
     uint64_t tmp = op1;
     op1 = (uint32_t)(op1 + op2);
     if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return op1;
 }
@@ -98,7 +98,7 @@ uint64_t helper_subqv (uint64_t op1, uint64_t op2)
     uint64_t res;
     res = op1 - op2;
     if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return res;
 }
@@ -108,7 +108,7 @@ uint64_t helper_sublv (uint64_t op1, uint64_t op2)
     uint32_t res;
     res = op1 - op2;
     if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return res;
 }
@@ -118,7 +118,7 @@ uint64_t helper_mullv (uint64_t op1, uint64_t op2)
     int64_t res = (int64_t)op1 * (int64_t)op2;
 
     if (unlikely((int32_t)res != res)) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return (int64_t)((int32_t)res);
 }
@@ -130,7 +130,7 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
     muls64(&tl, &th, op1, op2);
     /* If th != 0 && th != -1, then we had an overflow */
     if (unlikely((th + 1) > 1)) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return tl;
 }
@@ -370,87 +370,175 @@ uint64_t helper_unpkbw (uint64_t op1)
 
 /* Floating point helpers */
 
+/* ??? Not implemented is setting EXC_MASK, containing a bitmask of
+   destination registers of instructions that have caused arithmetic
+   traps.  Not needed for userspace emulation, or for complete 
+   emulation of the entire fpu stack within qemu.  But we would need
+   it to invoke a guest kernel's entArith trap handler properly.
+   
+   It would be possible to encode the FP destination register in the
+   QUAL parameter for the FPU helpers below; additional changes would
+   be required for ADD/V et al above.  */
+
+#define QUAL_RM_N	0x080	/* Round mode nearest even */
+#define QUAL_RM_C	0x000	/* Round mode chopped */
+#define QUAL_RM_M	0x040	/* Round mode minus infinity */
+#define QUAL_RM_D	0x0c0	/* Round mode dynamic */
+#define QUAL_RM_MASK	0x0c0
+
+#define QUAL_U		0x100	/* Underflow enable (fp output) */
+#define QUAL_V		0x100	/* Overflow enable (int output) */
+#define QUAL_S		0x400	/* Software completion enable */
+#define QUAL_I		0x200	/* Inexact detection enable */
+
 /* If the floating-point qualifiers specified a rounding mode,
    set that rounding mode and remember the original mode for
    resetting at the end of the instruction.  */
-static inline uint32_t begin_quals_roundmode(uint32_t qual)
+static inline uint32_t begin_fp_roundmode(uint32_t qual)
 {
     uint32_t rm = FP_STATUS.float_rounding_mode, old_rm = rm;
 
-    switch (qual & 0xc0) {
-    case 0x80:
+    switch (qual & QUAL_RM_MASK) {
+    default:
+    case QUAL_RM_N:
         rm = float_round_nearest_even;
         break;
-    case 0x00:
+    case QUAL_RM_C:
         rm = float_round_to_zero;
         break;
-    case 0x40:
+    case QUAL_RM_M:
         rm = float_round_down;
         break;
-    case 0xc0:
+    case QUAL_RM_D:
         return old_rm;
     }
-    set_float_rounding_mode(rm, &FP_STATUS);
+    if (old_rm != rm)
+        set_float_rounding_mode(rm, &FP_STATUS);
     return old_rm;
 }
 
-/* If the floating-point qualifiers specified extra exception processing
-   (i.e. /u or /su), zero the exception flags so that we can determine if
-   the current instruction raises any exceptions.  Save the old acrued
-   exception status so that we can restore them at the end of the insn.  */
-static inline uint32_t begin_quals_exception(uint32_t qual)
+/* Zero the exception flags so that we can determine if the current
+   instruction raises any exceptions.  Save the old acrued exception
+   status so that we can restore them at the end of the insn.  */
+static inline uint32_t begin_fp_exception(void)
 {
-    uint32_t old_exc = 0;
-    if (qual & 0x500) {
-        old_exc = (uint32_t)FP_STATUS.float_exception_flags << 8;
-        set_float_exception_flags(0, &FP_STATUS);
-    }
+    uint32_t old_exc = (uint32_t)FP_STATUS.float_exception_flags << 8;
+    set_float_exception_flags(0, &FP_STATUS);
     return old_exc;
 }
 
+static inline uint32_t begin_fp_flush_to_zero(uint32_t quals)
+{
+    /* If underflow detection is disabled, silently flush to zero.
+       Note that flush-to-zero mode may already be enabled via the FPCR.  */
+    if ((quals & QUAL_U) == 0 && !FP_STATUS.flush_to_zero) {
+        set_flush_to_zero(1, &FP_STATUS);
+        return 0x10000;
+    }
+    return 0;
+}
+
 /* Begin processing an fp operation.  Return a token that should be passed
    when completing the fp operation.  */
-static inline uint32_t begin_fp(uint32_t quals)
+static uint32_t begin_fp(uint32_t quals)
 {
     uint32_t ret = 0;
 
-    ret |= begin_quals_roundmode(quals);
-    ret |= begin_quals_exception(quals);
+    ret |= begin_fp_roundmode(quals);
+    ret |= begin_fp_flush_to_zero(quals);
+    ret |= begin_fp_exception();
 
     return ret;
 }
 
 /* End processing an fp operation.  */
-static inline void end_fp(uint32_t quals, uint32_t orig)
-{
-    uint8_t exc = FP_STATUS.float_exception_flags;
 
-    set_float_exception_flags(exc | (orig >> 8), &FP_STATUS);
-    set_float_rounding_mode(orig & 0xff, &FP_STATUS);
+static inline void end_fp_roundmode(uint32_t orig)
+{
+    uint32_t rm = FP_STATUS.float_rounding_mode, old_rm = orig & 0xff;
+    if (unlikely(rm != old_rm))
+        set_float_rounding_mode(old_rm, &FP_STATUS);
+}
 
-    /* TODO: check quals and exc and raise any exceptions needed.  */
+static inline void end_fp_flush_to_zero(uint32_t orig)
+{
+    if (orig & 0x10000)
+        set_flush_to_zero(0, &FP_STATUS);
 }
 
-/* Raise any exceptions needed for using F, given the insn qualifiers.  */
-static inline void float32_input(uint32_t quals, float32 f)
+static void end_fp_exception(uint32_t quals, uint32_t orig)
 {
-    /* If /s is used, no exceptions are raised immediately.  */
-    /* ??? This for userspace only.  If we are emulating the real hw, then
-       we may well need to trap to the kernel for software emulation.  */
-    /* ??? Shouldn't we raise an exception for SNAN?  */
-    if (quals & 0x500)
-        return;
-    /* TODO: Check for inf, nan, denormal and trap.  */
+    uint8_t exc = FP_STATUS.float_exception_flags;
+
+    /* If inexact detection is disabled, silently clear it.  */
+    if ((quals & QUAL_I) == 0)
+        exc &= ~float_flag_inexact;
+
+    orig = (orig >> 8) & 0xff;
+    set_float_exception_flags(exc | orig, &FP_STATUS);
+
+    /* Raise an exception as required.  */
+    if (unlikely(exc)) {
+        if (quals & QUAL_S)
+            exc &= ~FP_STATUS.float_exception_mask;
+        if (exc) {
+            uint32_t hw_exc = 0;
+
+            if (exc & float_flag_invalid)
+                hw_exc |= EXC_M_INV;
+            if (exc & float_flag_divbyzero)
+                hw_exc |= EXC_M_DZE;
+            if (exc & float_flag_overflow)
+                hw_exc |= EXC_M_FOV;
+            if (exc & float_flag_underflow)
+                hw_exc |= EXC_M_UNF;
+            if (exc & float_flag_inexact)
+                hw_exc |= EXC_M_INE;
+
+            helper_excp(EXCP_ARITH, hw_exc);
+        }
+    }
 }
 
-static inline void float64_input(uint32_t quals, float64 f)
+static void end_fp(uint32_t quals, uint32_t orig)
 {
-    /* TODO: Exactly like above, except for float64.  */
+    end_fp_roundmode(orig);
+    end_fp_flush_to_zero(orig);
+    end_fp_exception(quals, orig);
 }
 
+static uint64_t remap_ieee_input(uint32_t quals, uint64_t a)
+{
+    uint64_t frac;
+    uint32_t exp;
+
+    exp = (uint32_t)(a >> 52) & 0x7ff;
+    frac = a & 0xfffffffffffffull;
+
+    if (exp == 0) {
+        if (frac != 0) {
+            /* If DNZ is set, flush denormals to zero on input.  */
+            if (env->fpcr & FPCR_DNZ)
+                a = a & (1ull << 63);
+            /* If software completion not enabled, trap.  */
+            else if ((quals & QUAL_S) == 0)
+                helper_excp(EXCP_ARITH, EXC_M_UNF);
+        }
+    } else if (exp == 0x7ff) {
+        /* Infinity or NaN.  If software completion is not enabled, trap.
+           If /s is enabled, we'll properly signal for SNaN on output.  */
+        /* ??? I'm not sure these exception bit flags are correct.  I do
+           know that the Linux kernel, at least, doesn't rely on them and
+           just emulates the insn to figure out what exception to use.  */
+        if ((quals & QUAL_S) == 0)
+            helper_excp(EXCP_ARITH, frac ? EXC_M_INV : EXC_M_FOV);
+    }
+
+    return a;
+}
 
 /* F floating (VAX) */
-static inline uint64_t float32_to_f(float32 fa)
+static uint64_t float32_to_f(float32 fa)
 {
     uint64_t r, exp, mant, sig;
     CPU_FloatU a;
@@ -483,7 +571,7 @@ static inline uint64_t float32_to_f(float32 fa)
     return r;
 }
 
-static inline float32 f_to_float32(uint64_t a)
+static float32 f_to_float32(uint64_t a)
 {
     uint32_t exp, mant_sig;
     CPU_FloatU r;
@@ -535,8 +623,6 @@ uint64_t helper_addf (uint64_t a, uint64_t b, uint32_t quals)
     fb = f_to_float32(b);
 
     token = begin_fp(quals);
-    float32_input(quals, fa);
-    float32_input(quals, fb);
     fr = float32_add(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -552,8 +638,6 @@ uint64_t helper_subf (uint64_t a, uint64_t b, uint32_t quals)
     fb = f_to_float32(b);
 
     token = begin_fp(quals);
-    float32_input(quals, fa);
-    float32_input(quals, fb);
     fr = float32_sub(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -569,8 +653,6 @@ uint64_t helper_mulf (uint64_t a, uint64_t b, uint32_t quals)
     fb = f_to_float32(b);
 
     token = begin_fp(quals);
-    float32_input(quals, fa);
-    float32_input(quals, fb);
     fr = float32_mul(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -586,8 +668,6 @@ uint64_t helper_divf (uint64_t a, uint64_t b, uint32_t quals)
     fb = f_to_float32(b);
 
     token = begin_fp(quals);
-    float32_input(quals, fa);
-    float32_input(quals, fb);
     fr = float32_div(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -602,7 +682,6 @@ uint64_t helper_sqrtf (uint64_t t, uint32_t quals)
     ft = f_to_float32(t);
 
     token = begin_fp(quals);
-    float32_input(quals, ft);
     fr = float32_sqrt(ft, &FP_STATUS);
     end_fp(quals, token);
 
@@ -611,7 +690,7 @@ uint64_t helper_sqrtf (uint64_t t, uint32_t quals)
 
 
 /* G floating (VAX) */
-static inline uint64_t float64_to_g(float64 fa)
+static uint64_t float64_to_g(float64 fa)
 {
     uint64_t r, exp, mant, sig;
     CPU_DoubleU a;
@@ -644,7 +723,7 @@ static inline uint64_t float64_to_g(float64 fa)
     return r;
 }
 
-static inline float64 g_to_float64(uint64_t a)
+static float64 g_to_float64(uint64_t a)
 {
     uint64_t exp, mant_sig;
     CPU_DoubleU r;
@@ -696,8 +775,6 @@ uint64_t helper_addg (uint64_t a, uint64_t b, uint32_t quals)
     fb = g_to_float64(b);
 
     token = begin_fp(quals);
-    float64_input(quals, fa);
-    float64_input(quals, fb);
     fr = float64_add(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -713,8 +790,6 @@ uint64_t helper_subg (uint64_t a, uint64_t b, uint32_t quals)
     fb = g_to_float64(b);
 
     token = begin_fp(quals);
-    float64_input(quals, fa);
-    float64_input(quals, fb);
     fr = float64_sub(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -730,8 +805,6 @@ uint64_t helper_mulg (uint64_t a, uint64_t b, uint32_t quals)
     fb = g_to_float64(b);
 
     token = begin_fp(quals);
-    float64_input(quals, fa);
-    float64_input(quals, fb);
     fr = float64_mul(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -747,8 +820,6 @@ uint64_t helper_divg (uint64_t a, uint64_t b, uint32_t quals)
     fb = g_to_float64(b);
 
     token = begin_fp(quals);
-    float64_input(quals, fa);
-    float64_input(quals, fb);
     fr = float64_div(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -763,7 +834,6 @@ uint64_t helper_sqrtg (uint64_t a, uint32_t quals)
     fa = g_to_float64(a);
 
     token = begin_fp(quals);
-    float64_input(quals, fa);
     fr = float64_sqrt(fa, &FP_STATUS);
     end_fp(quals, token);
 
@@ -774,7 +844,7 @@ uint64_t helper_sqrtg (uint64_t a, uint32_t quals)
 /* 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)
+static uint64_t float32_to_s_int(uint32_t fi)
 {
     uint32_t frac = fi & 0x7fffff;
     uint32_t sign = fi >> 31;
@@ -796,7 +866,7 @@ static inline uint64_t float32_to_s_int(uint32_t fi)
             | ((uint64_t)frac << 29));
 }
 
-static inline uint64_t float32_to_s(float32 fa)
+static uint64_t float32_to_s(float32 fa)
 {
     CPU_FloatU a;
     a.f = fa;
@@ -825,17 +895,19 @@ uint64_t helper_memory_to_s (uint32_t a)
     return float32_to_s_int(a);
 }
 
+static float32 input_s(uint32_t quals, uint64_t a)
+{
+    return s_to_float32(remap_ieee_input(quals, a));
+}
+
 uint64_t helper_adds (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
     uint32_t token;
 
-    fa = s_to_float32(a);
-    fb = s_to_float32(b);
-
     token = begin_fp(quals);
-    float32_input(quals, fa);
-    float32_input(quals, fb);
+    fa = input_s(quals, a);
+    fb = input_s(quals, b);
     fr = float32_add(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -847,12 +919,9 @@ uint64_t helper_subs (uint64_t a, uint64_t b, uint32_t quals)
     float32 fa, fb, fr;
     uint32_t token;
 
-    fa = s_to_float32(a);
-    fb = s_to_float32(b);
-
     token = begin_fp(quals);
-    float32_input(quals, fa);
-    float32_input(quals, fb);
+    fa = input_s(quals, a);
+    fb = input_s(quals, b);
     fr = float32_sub(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -864,12 +933,9 @@ uint64_t helper_muls (uint64_t a, uint64_t b, uint32_t quals)
     float32 fa, fb, fr;
     uint32_t token;
 
-    fa = s_to_float32(a);
-    fb = s_to_float32(b);
-
     token = begin_fp(quals);
-    float32_input(quals, fa);
-    float32_input(quals, fb);
+    fa = input_s(quals, a);
+    fb = input_s(quals, b);
     fr = float32_mul(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -881,12 +947,9 @@ uint64_t helper_divs (uint64_t a, uint64_t b, uint32_t quals)
     float32 fa, fb, fr;
     uint32_t token;
 
-    fa = s_to_float32(a);
-    fb = s_to_float32(b);
-
     token = begin_fp(quals);
-    float32_input(quals, fa);
-    float32_input(quals, fb);
+    fa = input_s(quals, a);
+    fb = input_s(quals, b);
     fr = float32_div(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -898,10 +961,8 @@ uint64_t helper_sqrts (uint64_t a, uint32_t quals)
     float32 fa, fr;
     uint32_t token;
 
-    fa = s_to_float32(a);
-
     token = begin_fp(quals);
-    float32_input(quals, fa);
+    fa = input_s(quals, a);
     fr = float32_sqrt(fa, &FP_STATUS);
     end_fp(quals, token);
 
@@ -926,17 +987,20 @@ static inline uint64_t float64_to_t(float64 fa)
     return r.ll;
 }
 
+/* Raise any exceptions needed for using F, given the insn qualifiers.  */
+static float64 input_t(uint32_t quals, uint64_t a)
+{
+    return t_to_float64(remap_ieee_input(quals, a));
+}
+
 uint64_t helper_addt (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
     uint32_t token;
 
-    fa = t_to_float64(a);
-    fb = t_to_float64(b);
-
     token = begin_fp(quals);
-    float64_input(quals, fa);
-    float64_input(quals, fb);
+    fa = input_t(quals, a);
+    fb = input_t(quals, b);
     fr = float64_add(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -948,12 +1012,9 @@ uint64_t helper_subt (uint64_t a, uint64_t b, uint32_t quals)
     float64 fa, fb, fr;
     uint32_t token;
 
-    fa = t_to_float64(a);
-    fb = t_to_float64(b);
-
     token = begin_fp(quals);
-    float64_input(quals, fa);
-    float64_input(quals, fb);
+    fa = input_t(quals, a);
+    fb = input_t(quals, b);
     fr = float64_sub(fa, fb, &FP_STATUS);
     end_fp(quals, token);
     
@@ -965,12 +1026,9 @@ uint64_t helper_mult (uint64_t a, uint64_t b, uint32_t quals)
     float64 fa, fb, fr;
     uint32_t token;
 
-    fa = t_to_float64(a);
-    fb = t_to_float64(b);
-
     token = begin_fp(quals);
-    float64_input(quals, fa);
-    float64_input(quals, fb);
+    fa = input_t(quals, a);
+    fb = input_t(quals, b);
     fr = float64_mul(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -982,12 +1040,9 @@ uint64_t helper_divt (uint64_t a, uint64_t b, uint32_t quals)
     float64 fa, fb, fr;
     uint32_t token;
 
-    fa = t_to_float64(a);
-    fb = t_to_float64(b);
-
     token = begin_fp(quals);
-    float64_input(quals, fa);
-    float64_input(quals, fb);
+    fa = input_t(quals, a);
+    fb = input_t(quals, b);
     fr = float64_div(fa, fb, &FP_STATUS);
     end_fp(quals, token);
 
@@ -999,10 +1054,8 @@ uint64_t helper_sqrtt (uint64_t a, uint32_t quals)
     float64 fa, fr;
     uint32_t token;
 
-    fa = t_to_float64(a);
-
     token = begin_fp(quals);
-    float64_input(quals, fa);
+    fa = input_t(quals, a);
     fr = float64_sqrt(fa, &FP_STATUS);
     end_fp(quals, token);
 
@@ -1028,6 +1081,8 @@ uint64_t helper_cpyse(uint64_t a, uint64_t b)
 
 
 /* Comparisons */
+/* ??? Software completion qualifier missing.  */
+
 uint64_t helper_cmptun (uint64_t a, uint64_t b)
 {
     float64 fa, fb;
@@ -1126,10 +1181,8 @@ uint64_t helper_cvtts (uint64_t a, uint32_t quals)
     float32 fr;
     uint32_t token;
 
-    fa = t_to_float64(a);
-
     token = begin_fp(quals);
-    float64_input(quals, fa);
+    fa = input_t(quals, a);
     fr = float64_to_float32(fa, &FP_STATUS);
     end_fp(quals, token);
 
@@ -1142,10 +1195,8 @@ uint64_t helper_cvtst (uint64_t a, uint32_t quals)
     float64 fr;
     uint32_t token;
 
-    fa = s_to_float32(a);
-
     token = begin_fp(quals);
-    float32_input(quals, fa);
+    fa = input_s(quals, a);
     fr = float32_to_float64(fa, &FP_STATUS);
     end_fp(quals, token);
 
@@ -1164,115 +1215,125 @@ uint64_t helper_cvtqs (uint64_t a, uint32_t quals)
     return float32_to_s(fr);
 }
 
-uint64_t helper_cvttq (uint64_t a, uint32_t quals)
-{
-    uint64_t ret, frac;
-    uint32_t token, exp, sign, exc = 0;
-
-    token = begin_fp(quals);
+/* Implement float64 to uint64 conversion without overflow enabled.
+   In this mode we must supply the truncated result.  This behaviour
+   is used by the compiler to get unsigned conversion for free with
+   the same instruction.  */
 
-    /* Alpha integer conversion does not saturate, as the generic routine
-       does.  Instead it supplies a truncated result.  This fact is relied
-       upon by GCC in that without overflow enabled we can get unsigned
-       conversion for free with the same instruction.  */
+static uint64_t cvttq_noqual_internal(uint64_t a, uint32_t rounding_mode)
+{
+    uint64_t frac, ret = 0;
+    uint32_t exp, sign;
+    int shift;
 
     sign = (a >> 63);
     exp = (uint32_t)(a >> 52) & 0x7ff;
     frac = a & 0xfffffffffffffull;
 
-    if (exp == 0) {
-        ret = 0;
-        if (frac != 0) {
-            /* ??? If DNZ set, map to zero without trapping.  */
-            /* ??? Figure out what kind of exception signal to send.  */
-            if (!(quals & 0x400))
-                helper_excp(EXCP_ARITH, 0);
-            goto do_underflow;
-        }
-    } else if (exp == 0x7ff) {
-        /* In keeping with the truncation result, both infinity and NaN
-           give result of zero.  See Table B-2 in the Alpha Architecture
-           Handbook.  */
-        ret = 0;
-        exc = float_flag_invalid;
+    /* We already handled denormals in remap_ieee_input; infinities and
+       nans are defined to return zero as per truncation.  */
+    if (exp == 0 || exp == 0x7ff)
+        return 0;
 
-        /* Without /s qualifier, both Inf and NaN trap.  SNaN always traps. */
-        if (!(quals & 0x400) || (frac & 0x4000000000000ull))
-            helper_excp(EXCP_ARITH, 0);
+    /* Restore implicit bit.  */
+    frac |= 0x10000000000000ull;
+
+    /* Note that neither overflow exceptions nor inexact exceptions
+       are desired.  This lets us streamline the checks quite a bit.  */
+    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 < 63) {
+            ret = frac << shift;
+        }
     } else {
-        int32_t shift;
-
-        /* 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, but we
-               must still set inexact for overflow.  */
-            if (shift < 63) {
-                ret = frac << shift;
-                if ((ret >> shift) != frac)
-                    exc = float_flag_inexact;
-            } else {
-                exc = float_flag_inexact;
-                ret = 0;
-            }
-        } else if (shift == 0) {
-            /* The exponent is exactly right for the 52-bit fraction.  */
-            ret = frac;
+        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 {
-            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 {
-            do_underflow:
-                /* The exponent is so small we shift out everything.  */
-                ret = 0;
-                round = 1;
-            }
+            /* The exponent is so small we shift out everything.
+               Leave a sticky bit for proper rounding below.  */
+            round = 1;
+        }
 
-            if (round) {
-                exc = float_flag_inexact;
-                switch (FP_STATUS.float_rounding_mode) {
-                case float_round_nearest_even:
-                    if (round == (1ull << 63)) {
-                        /* The remaining 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:
-                    if (!sign)
-                        ret += 1;
-                    break;
-                case float_round_down:
-                    if (sign)
-                        ret += 1;
-                    break;
+        if (round) {
+            switch (rounding_mode) {
+            case float_round_nearest_even:
+                if (round == (1ull << 63)) {
+                    /* Remaining 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:
+                if (!sign)
+                    ret += 1;
+                break;
+            case float_round_down:
+                if (sign)
+                    ret += 1;
+                break;
             }
         }
-
-        if (sign)
-            ret = -ret;
     }
 
-    if (exc)
-        float_raise(exc, &FP_STATUS);
-    end_fp(quals, token);
+    if (sign)
+        ret = -ret;
+    return ret;
+}
+
+uint64_t helper_cvttq (uint64_t a, uint32_t quals)
+{
+    uint64_t ret;
+
+    a = remap_ieee_input(quals, a);
+
+    if (quals & QUAL_V) {
+        float64 fa = t_to_float64(a);
+        uint32_t token;
+
+        token = begin_fp_exception();
+        if ((quals & QUAL_RM_MASK) == QUAL_RM_C) {
+            ret = float64_to_int64_round_to_zero(fa, &FP_STATUS);
+        } else {
+            token |= begin_fp_roundmode(quals);
+            ret = float64_to_int64(fa, &FP_STATUS);
+            end_fp_roundmode(token);
+        }
+        end_fp_exception(quals, token);
+    } else {
+        uint32_t round_mode;
+
+        switch (quals & QUAL_RM_MASK) {
+        case QUAL_RM_N:
+            round_mode = float_round_nearest_even;
+            break;
+        case QUAL_RM_C:
+        default:
+            round_mode = float_round_to_zero;
+            break;
+        case QUAL_RM_M:
+            round_mode = float_round_down;
+            break;
+        case QUAL_RM_D:
+            round_mode = FP_STATUS.float_rounding_mode;
+            break;
+        }
+
+        ret = cvttq_noqual_internal(a, round_mode);
+    }
 
     return ret;
 }
@@ -1310,7 +1371,6 @@ uint64_t helper_cvtgf (uint64_t a, uint32_t quals)
     fa = g_to_float64(a);
 
     token = begin_fp(quals);
-    float64_input(quals, fa);
     fr = float64_to_float32(fa, &FP_STATUS);
     end_fp(quals, token);
 
@@ -1326,7 +1386,6 @@ uint64_t helper_cvtgq (uint64_t a, uint32_t quals)
     fa = g_to_float64(a);
 
     token = begin_fp(quals);
-    float64_input(quals, fa);
     ret = float64_to_int64(fa, &FP_STATUS);
     end_fp(quals, token);
 
@@ -1352,35 +1411,24 @@ uint64_t helper_cvtlq (uint64_t a)
     return (lo & 0x3FFFFFFF) | (hi & 0xc0000000);
 }
 
-static inline uint64_t __helper_cvtql(uint64_t a, int s, int v)
-{
-    uint64_t r;
-
-    r = ((uint64_t)(a & 0xC0000000)) << 32;
-    r |= ((uint64_t)(a & 0x7FFFFFFF)) << 29;
-
-    if (v && (int64_t)((int32_t)r) != (int64_t)r) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
-    }
-    if (s) {
-        /* TODO */
-    }
-    return r;
-}
-
 uint64_t helper_cvtql (uint64_t a)
 {
-    return __helper_cvtql(a, 0, 0);
+    return ((a & 0xC0000000) << 32) | ((a & 0x7FFFFFFF) << 29);
 }
 
 uint64_t helper_cvtqlv (uint64_t a)
 {
-    return __helper_cvtql(a, 0, 1);
+    if ((int32_t)a != (int64_t)a)
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
+    return helper_cvtql(a);
 }
 
 uint64_t helper_cvtqlsv (uint64_t a)
 {
-    return __helper_cvtql(a, 1, 1);
+    /* ??? I'm pretty sure there's nothing that /sv needs to do that /v
+       doesn't do.  The only thing I can think is that /sv is a valid
+       instruction merely for completeness in the ISA.  */
+    return helper_cvtqlv(a);
 }
 
 /* PALcode support special instructions */

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] target-alpha: An approach to fp insn qualifiers
  2009-12-15  0:31   ` Richard Henderson
@ 2009-12-15  3:50     ` Richard Henderson
  2009-12-15 11:31       ` Laurent Desnogues
                         ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Richard Henderson @ 2009-12-15  3:50 UTC (permalink / raw)
  To: Laurent Desnogues; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 684 bytes --]

On 12/14/2009 04:31 PM, Richard Henderson wrote:
> On 12/14/2009 12:11 PM, Laurent Desnogues wrote:
>> I'll take a closer look at your patch tomorrow.
>
> For the record, I believe this finishes what I had in mind for the
> exception handling there in op_handler.c.

Hmph.  One more patch for correctness.  With this 183.equake runs 
correctly.  I couldn't remember all the hoops to get runspec.pl to work, 
to do the whole testsuite, but I did run this one by hand.

./quake-amd64: Done. Terminating the simulation.

real	0m34.943s
user	0m34.913s
sys	0m0.024s

./quake-axp: Done. Terminating the simulation.

real	33m24.105s
user	33m23.674s
sys	0m0.116s

with identical output.


r~

[-- Attachment #2: commit-fpu-4 --]
[-- Type: text/plain, Size: 7279 bytes --]

commit daf11ad5cd50c56d44e36e4ea334c660f8fe4c16
Author: Richard Henderson <rth@twiddle.net>
Date:   Mon Dec 14 19:46:57 2009 -0800

    target-alpha: Don't ever saturate cvttq.
    
    The previous patch tried allowing saturation if /S;
    that doesn't match what the kernels generate.

diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index d031f56..2d1c3d5 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -1220,120 +1220,106 @@ uint64_t helper_cvtqs (uint64_t a, uint32_t quals)
    is used by the compiler to get unsigned conversion for free with
    the same instruction.  */
 
-static uint64_t cvttq_noqual_internal(uint64_t a, uint32_t rounding_mode)
+static uint64_t cvttq_internal(uint64_t a)
 {
     uint64_t frac, ret = 0;
-    uint32_t exp, sign;
+    uint32_t exp, sign, exc = 0;
     int shift;
 
     sign = (a >> 63);
     exp = (uint32_t)(a >> 52) & 0x7ff;
     frac = a & 0xfffffffffffffull;
 
-    /* We already handled denormals in remap_ieee_input; infinities and
-       nans are defined to return zero as per truncation.  */
-    if (exp == 0 || exp == 0x7ff)
-        return 0;
-
-    /* Restore implicit bit.  */
-    frac |= 0x10000000000000ull;
-
-    /* Note that neither overflow exceptions nor inexact exceptions
-       are desired.  This lets us streamline the checks quite a bit.  */
-    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 < 63) {
-            ret = frac << shift;
-        }
+    if (exp == 0) {
+        if (unlikely(frac != 0))
+            goto do_underflow;
+    } else if (exp == 0x7ff) {
+        if (frac == 0)
+            exc = float_flag_overflow;
+        else
+            exc = float_flag_invalid;
     } 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);
+        /* Restore implicit bit.  */
+        frac |= 0x10000000000000ull;
+
+        /* Note that neither overflow exceptions nor inexact exceptions
+           are desired.  This lets us streamline the checks quite a bit.  */
+        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 < 63) {
+                ret = frac << shift;
+                if ((ret >> shift) != frac)
+                    exc = float_flag_overflow;
+            }
         } else {
-            /* The exponent is so small we shift out everything.
-               Leave a sticky bit for proper rounding below.  */
-            round = 1;
-        }
+            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) {
-            switch (rounding_mode) {
-            case float_round_nearest_even:
-                if (round == (1ull << 63)) {
-                    /* Remaining fraction is exactly 0.5; round to even.  */
-                    ret += (ret & 1);
-                } else if (round > (1ull << 63)) {
-                    ret += 1;
+            if (round) {
+                exc = float_flag_inexact;
+                switch (FP_STATUS.float_rounding_mode) {
+                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:
+                    if (!sign)
+                        ret += 1;
+                    break;
+                case float_round_down:
+                    if (sign)
+                        ret += 1;
+                    break;
                 }
-                break;
-            case float_round_to_zero:
-                break;
-            case float_round_up:
-                if (!sign)
-                    ret += 1;
-                break;
-            case float_round_down:
-                if (sign)
-                    ret += 1;
-                break;
             }
         }
+        if (sign)
+            ret = -ret;
     }
+    if (unlikely(exc))
+        float_raise(exc, &FP_STATUS);
 
-    if (sign)
-        ret = -ret;
     return ret;
 }
 
 uint64_t helper_cvttq (uint64_t a, uint32_t quals)
 {
     uint64_t ret;
+    uint32_t token;
 
-    a = remap_ieee_input(quals, a);
-
-    if (quals & QUAL_V) {
-        float64 fa = t_to_float64(a);
-        uint32_t token;
-
-        token = begin_fp_exception();
-        if ((quals & QUAL_RM_MASK) == QUAL_RM_C) {
-            ret = float64_to_int64_round_to_zero(fa, &FP_STATUS);
-        } else {
-            token |= begin_fp_roundmode(quals);
-            ret = float64_to_int64(fa, &FP_STATUS);
-            end_fp_roundmode(token);
-        }
-        end_fp_exception(quals, token);
-    } else {
-        uint32_t round_mode;
-
-        switch (quals & QUAL_RM_MASK) {
-        case QUAL_RM_N:
-            round_mode = float_round_nearest_even;
-            break;
-        case QUAL_RM_C:
-        default:
-            round_mode = float_round_to_zero;
-            break;
-        case QUAL_RM_M:
-            round_mode = float_round_down;
-            break;
-        case QUAL_RM_D:
-            round_mode = FP_STATUS.float_rounding_mode;
-            break;
-        }
+    /* ??? There's an arugument to be made that when /S is enabled, we
+       should provide the standard IEEE saturated result, instead of
+       the truncated result that we *must* provide when /V is disabled.
+       However, that's not how either the Tru64 or Linux completion
+       handlers actually work, and GCC knows it.  */
 
-        ret = cvttq_noqual_internal(a, round_mode);
-    }
+    token = begin_fp(quals);
+    a = remap_ieee_input(quals, a);
+    ret = cvttq_internal(a);
+    end_fp(quals, token);
 
     return ret;
 }

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] target-alpha: An approach to fp insn qualifiers
  2009-12-15  3:50     ` Richard Henderson
@ 2009-12-15 11:31       ` Laurent Desnogues
  2009-12-15 16:17         ` Richard Henderson
  2009-12-15 17:32       ` Vince Weaver
  2009-12-17 17:18       ` Vince Weaver
  2 siblings, 1 reply; 9+ messages in thread
From: Laurent Desnogues @ 2009-12-15 11:31 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, Dec 15, 2009 at 4:50 AM, Richard Henderson <rth@twiddle.net> wrote:
> On 12/14/2009 04:31 PM, Richard Henderson wrote:
>>
>> On 12/14/2009 12:11 PM, Laurent Desnogues wrote:
>>>
>>> I'll take a closer look at your patch tomorrow.
>>
>> For the record, I believe this finishes what I had in mind for the
>> exception handling there in op_handler.c.
>
> Hmph.  One more patch for correctness.  With this 183.equake runs correctly.
>  I couldn't remember all the hoops to get runspec.pl to work, to do the
> whole testsuite, but I did run this one by hand.
>
> ./quake-amd64: Done. Terminating the simulation.
>
> real    0m34.943s
> user    0m34.913s
> sys     0m0.024s
>
> ./quake-axp: Done. Terminating the simulation.
>
> real    33m24.105s
> user    33m23.674s
> sys     0m0.116s
>
> with identical output.

Well equake works me with the last set of patches you sent (that is
without using this FPU patch you just sent).  Can you confirm?


Laurent

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] target-alpha: An approach to fp insn qualifiers
  2009-12-15 11:31       ` Laurent Desnogues
@ 2009-12-15 16:17         ` Richard Henderson
  0 siblings, 0 replies; 9+ messages in thread
From: Richard Henderson @ 2009-12-15 16:17 UTC (permalink / raw)
  To: Laurent Desnogues; +Cc: qemu-devel

On 12/15/2009 03:31 AM, Laurent Desnogues wrote:
> Well equake works me with the last set of patches you sent (that is
> without using this FPU patch you just sent).  Can you confirm?

GCC testsuite breaks with the saturating cvttq so I didn't even try.
If equake works, it just means that it doesn't do any conversions to 
unsigned long.


r~

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] target-alpha: An approach to fp insn qualifiers
  2009-12-15  3:50     ` Richard Henderson
  2009-12-15 11:31       ` Laurent Desnogues
@ 2009-12-15 17:32       ` Vince Weaver
  2009-12-17 17:18       ` Vince Weaver
  2 siblings, 0 replies; 9+ messages in thread
From: Vince Weaver @ 2009-12-15 17:32 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Laurent Desnogues, qemu-devel

On Mon, 14 Dec 2009, Richard Henderson wrote:

> On 12/14/2009 04:31 PM, Richard Henderson wrote:
> 
> Hmph.  One more patch for correctness.  With this 183.equake runs correctly.
> I couldn't remember all the hoops to get runspec.pl to work, to do the whole
> testsuite, but I did run this one by hand.

This is great!  About a year ago I had been steadily working on getting 
all of spec2k to run under alpha qemu but then other projects came up and 
I didn't have time.

I'll re-run once the patches get applied to see if any more of the 
benchmarks have issues.  My notes from before your patches showed the 
following benchmarks had issues:

perlbmk.perfect   WRONG_OUTPUT
eon.rushmeier     wrong_results
eon.kajiya        wrong_results
eon.cook          wrong_results
art.110           never finished
art.470           never finished
vpr.place         Arithmetic trap.
vpr.route         Arithmetic trap.
mesa              Arithmetic trap.
wupwise           wrong results (NaN)
lucas             Arithmetic trap.
equake            wrong results (NaN)
sixtrack          Fortran runtime error: Invalid string input in item 1
facerec           Arithmetic trap.
fma3d             MMU data fault
ammp              Arithmetic trap.
galgel            broken?
twolf             Arithmetic trap.
apsi              MMU data fault


Vince

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] target-alpha: An approach to fp insn qualifiers
  2009-12-15  3:50     ` Richard Henderson
  2009-12-15 11:31       ` Laurent Desnogues
  2009-12-15 17:32       ` Vince Weaver
@ 2009-12-17 17:18       ` Vince Weaver
  2 siblings, 0 replies; 9+ messages in thread
From: Vince Weaver @ 2009-12-17 17:18 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Laurent Desnogues, qemu-devel

On Mon, 14 Dec 2009, Richard Henderson wrote:

> On 12/14/2009 04:31 PM, Richard Henderson wrote:
> 
> Hmph.  One more patch for correctness.  With this 183.equake runs correctly.

I just finished running all of spec2k Alpha through Qemu.

With these patches installed (the 4 fpu ones, and the 5 from the earlier 
thread) on top of current Qemu, pretty much all of the floating point 
issues have been fixed!

Before, at least 19 of the spec2k benchmarks didn't run for various 
reasons.  Now only two fail, sixtrack and fma3d.  And I think those two 
are probably syscall related, though I haven't had chance to look in 
detail.

#sixtrack     	 At line 343 of file daten.f Fortran runtime error: End of file
#fma3d	     	 FMA-3D> Fatal Error Reported. Job Terminated.

So it would be great if the alpha patches could be merged.

Vince

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2009-12-17 17:18 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-12-14 18:02 [Qemu-devel] target-alpha: An approach to fp insn qualifiers Richard Henderson
2009-12-14 20:11 ` Laurent Desnogues
2009-12-14 22:21   ` Richard Henderson
2009-12-15  0:31   ` Richard Henderson
2009-12-15  3:50     ` Richard Henderson
2009-12-15 11:31       ` Laurent Desnogues
2009-12-15 16:17         ` Richard Henderson
2009-12-15 17:32       ` Vince Weaver
2009-12-17 17:18       ` Vince Weaver

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.