All of lore.kernel.org
 help / color / mirror / Atom feed
From: Richard Henderson <rth@twiddle.net>
To: Laurent Desnogues <laurent.desnogues@gmail.com>
Cc: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] target-alpha: An approach to fp insn qualifiers
Date: Mon, 14 Dec 2009 19:50:04 -0800	[thread overview]
Message-ID: <4B27076C.6020806@twiddle.net> (raw)
In-Reply-To: <4B26D8EF.10801@twiddle.net>

[-- 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;
 }

  reply	other threads:[~2009-12-15  3:50 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B27076C.6020806@twiddle.net \
    --to=rth@twiddle.net \
    --cc=laurent.desnogues@gmail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.