Hi Kaz,
Kaz Kojima wrote:
BTW, it looks that softfp __unord?f2 routines check signaling NaNs
only. This makes __builtin_isnan return false for quiet NaNs for
which current fp-bit ones return true when -mieee enabled. Perhaps
that change of behavior might be OK for software FP.
I use the attached patch to handle the QNaNs in the assembly solf-fp.
Need to be updated for trunk (and update the dates in changelogs). Will do.
Cheers
Christian
2010-04-20 Christian Bruel <[email protected]>
* gcc.dg/builtins-nan.c: New test.
2010-04-20 Christian Bruel <[email protected]>
* config/sh/ieee-754-df.S (nedf2f): Don't check Qbit for NaNs.
* config/sh/ieee-754-sf.S (nesf2f): Likewise.
* config/sh/sh.md (cmpunsf_i1, cmpundf_i1): Likewise. Clobber R2.
2010-04-20 Christian Bruel <[email protected]>
* gcc.dg/builtins-nan.c: New test.
2010-04-20 Christian Bruel <[email protected]>
* config/sh/ieee-754-df.S (nedf2f): Don't check Qbit for NaNs.
* config/sh/ieee-754-sf.S (nesf2f): Likewise.
* config/sh/sh.md (cmpunsf_i1, cmpundf_i1): Likewise. Clobber R2.
Index: gcc/config/sh/ieee-754-df.S
===================================================================
--- gcc/config/sh/ieee-754-df.S (revision 1352)
+++ gcc/config/sh/ieee-754-df.S (revision 1373)
@@ -88,11 +88,12 @@
HIDDEN_FUNC(GLOBAL(nedf2f))
GLOBAL(nedf2f):
cmp/eq DBL0L,DBL1L
+ bf.s LOCAL(ne)
+ mov #1,r0
+ cmp/eq DBL0H,DBL1H
mov.l LOCAL(c_DF_NAN_MASK),r1
- bf LOCAL(ne)
- cmp/eq DBL0H,DBL1H
- not DBL0H,r0
- bt LOCAL(check_nan)
+ bt.s LOCAL(check_nan)
+ not DBL0H,r0
mov DBL0H,r0
or DBL1H,r0
add r0,r0
@@ -100,11 +101,17 @@
or DBL0L,r0
LOCAL(check_nan):
tst r1,r0
- rts
+ bt.s LOCAL(nan)
+ mov #12,r2
+ shll16 r2
+ xor r2,r1
+ tst r1,r0
+LOCAL(nan):
movt r0
LOCAL(ne):
rts
- mov #1,r0
+ nop
+
.balign 4
LOCAL(c_DF_NAN_MASK):
.long DF_NAN_MASK
Index: gcc/config/sh/ieee-754-sf.S
===================================================================
--- gcc/config/sh/ieee-754-sf.S (revision 1352)
+++ gcc/config/sh/ieee-754-sf.S (revision 1373)
@@ -55,19 +55,27 @@
the values are NaN. */
cmp/eq r4,r5
mov.l LOCAL(c_SF_NAN_MASK),r1
+ bt.s LOCAL(check_nan)
not r4,r0
- bt LOCAL(check_nan)
mov r4,r0
or r5,r0
rts
add r0,r0
LOCAL(check_nan):
tst r1,r0
+ bt.s LOCAL(nan)
+ mov #96,r2
+ shll16 r2
+ xor r2,r1
+ tst r1,r0
+LOCAL(nan):
rts
movt r0
+
.balign 4
LOCAL(c_SF_NAN_MASK):
.long SF_NAN_MASK
+LOCAL(c_SF_SNAN_MASK):
ENDFUNC(GLOBAL(nesf2f))
#endif /* L_nesf2f */
Index: gcc/config/sh/sh.md
===================================================================
--- gcc/config/sh/sh.md (revision 1352)
+++ gcc/config/sh/sh.md (revision 1373)
@@ -11182,6 +11182,7 @@
(clobber (reg:SI T_REG))
(clobber (reg:SI PR_REG))
(clobber (reg:SI R1_REG))
+ (clobber (reg:SI R2_REG))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
"TARGET_SH1 && ! TARGET_SH2E"
"jsr @%1%#"
@@ -11257,13 +11258,18 @@
(define_insn "cmpunsf_i1"
[(set (reg:SI T_REG)
- (unordered:SI (match_operand:SF 0 "arith_reg_operand" "r,r")
- (match_operand:SF 1 "arith_reg_operand" "r,r")))
- (use (match_operand:SI 2 "arith_reg_operand" "r,r"))
- (clobber (match_scratch:SI 3 "=0,&r"))]
+ (unordered:SI (match_operand:SF 0 "arith_reg_operand" "r")
+ (match_operand:SF 1 "arith_reg_operand" "r")))
+ (use (match_operand:SI 2 "arith_reg_operand" "r"))
+ (clobber (match_scratch:SI 3 "=&r"))]
"TARGET_SH1 && ! TARGET_SH2E"
- "not\t%0,%3\;tst\t%2,%3\;not\t%1,%3\;bt\t0f\;tst\t%2,%3\;0:"
- [(set_attr "length" "10")])
+ "not\t%0,%3\;tst\t%2,%3\;bt.s\t0f
+\tnot\t%1,%3\;tst\t%2,%3\;bt.s\t0f
+\tmov\t#96,%3\;shll16\t%3\;xor\t%3,%2
+\tnot\t%0,%3\;tst\t%2,%3\;bt.s\t0f
+\tnot\t%1,%3\;tst\t%2,%3
+0:"
+ [(set_attr "length" "28")])
;; ??? This is a lot of code with a lot of branches; a library function
;; might be better.
@@ -11967,6 +11973,7 @@
(clobber (reg:SI T_REG))
(clobber (reg:SI PR_REG))
(clobber (reg:SI R1_REG))
+ (clobber (reg:SI R2_REG))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
"TARGET_SH1_SOFTFP"
"jsr @%1%#"
@@ -12008,13 +12015,18 @@
(define_insn "cmpundf_i1"
[(set (reg:SI T_REG)
- (unordered:SI (match_operand:DF 0 "arith_reg_operand" "r,r")
- (match_operand:DF 1 "arith_reg_operand" "r,r")))
- (use (match_operand:SI 2 "arith_reg_operand" "r,r"))
- (clobber (match_scratch:SI 3 "=0,&r"))]
+ (unordered:SI (match_operand:DF 0 "arith_reg_operand" "r")
+ (match_operand:DF 1 "arith_reg_operand" "r")))
+ (use (match_operand:SI 2 "arith_reg_operand" "r"))
+ (clobber (match_scratch:SI 3 "=&r"))]
"TARGET_SH1 && ! TARGET_SH2E"
- "not\t%S0,%3\;tst\t%2,%3\;not\t%S1,%3\;bt\t0f\;tst\t%2,%3\;0:"
- [(set_attr "length" "10")])
+ "not\t%S0,%3\;tst\t%2,%3\;bt.s\t0f
+ \tnot\t%S1,%3\;tst\t%2,%3\;bt.s\t0f
+ \tmov\t#12,%3\;shll16\t%3\;xor\t%3,%2
+ \tnot\t%S0,%3\;tst\t%2,%3\;bt.s\t0f
+ \tnot\t%S1,%3\;tst\t%2,%3
+0:"
+ [(set_attr "length" "28")])
;; ??? This is a lot of code with a lot of branches; a library function
;; might be better.
/* { dg-do run } */
/* { dg-options "-mieee" { target sh*-*-* } } */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
static int lisnan(double v)
{
return (v != v);
}
static int lisnanf(float v)
{
return (v != v);
}
int main(void)
{
double d;
float f;
/* double */
d = __builtin_nans("");
if (! lisnan(d))
abort();
if (! __builtin_isnan(d))
abort();
d = __builtin_nan("");
if (! lisnan(d))
abort();
if (! __builtin_isnan(d))
abort();
/* float */
f = __builtin_nansf("");
if (! lisnanf(f))
abort();
if (! __builtin_isnanf(f))
abort();
f = __builtin_nanf("");
if (! lisnanf(f))
abort();
if (! __builtin_isnanf(f))
abort();
exit (0);
}