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 <christian.br...@st.com> * gcc.dg/builtins-nan.c: New test. 2010-04-20 Christian Bruel <christian.br...@st.com> * 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 <christian.br...@st.com> * gcc.dg/builtins-nan.c: New test. 2010-04-20 Christian Bruel <christian.br...@st.com> * 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); }