1  /* Copyright (C) 2007  Free Software Foundation.
       2  
       3     Verify that built-in folding of modf is correctly performed by the
       4     compiler.
       5  
       6     Origin: Kaveh R. Ghazi,  February 23, 2007.  */
       7  
       8  /* { dg-do link } */
       9  /* { dg-require-effective-target inf } */
      10  /* { dg-options "-fno-finite-math-only" { target sh*-*-* } } */
      11  /* { dg-options "-funsafe-math-optimizations -fsigned-zeros -fno-associative-math" { target powerpc-*-darwin* powerpc*-*-linux* } } */
      12  
      13  extern void link_error(int);
      14  
      15  /* Return TRUE if the sign of X != sign of Y.  This is important when
      16     comparing signed zeros.  */
      17  #define CKSGN_F(X,Y) \
      18    (__builtin_copysignf(1.0F,(X)) != __builtin_copysignf(1.0F,(Y)))
      19  #define CKSGN(X,Y) \
      20    (__builtin_copysign(1.0,(X)) != __builtin_copysign(1.0,(Y)))
      21  #define CKSGN_L(X,Y) \
      22    (__builtin_copysignl(1.0L,(X)) != __builtin_copysignl(1.0L,(Y)))
      23  
      24  /* We use these macros if we can only check these when optimizing.  In
      25     some cases we rely on other optimizations to propagate the value
      26     and fold away certain constructs.  Likewise for the sign testing.
      27     TRUE means an error occurred.  */
      28  #ifdef __OPTIMIZE__
      29  #define CKRES(X) (X)
      30  #define CKIPTR(X,Y) X != Y
      31  #define CKSGN_IPTR_F(X,Y) CKSGN_F(X,Y)
      32  #define CKSGN_IPTR(X,Y) CKSGN(X,Y)
      33  #define CKSGN_IPTR_L(X,Y) CKSGN_L(X,Y)
      34  #else
      35  #define CKRES(X) 0
      36  #define CKIPTR(X,Y) 0
      37  #define CKSGN_IPTR_F(X,Y) 0
      38  #define CKSGN_IPTR(X,Y) 0
      39  #define CKSGN_IPTR_L(X,Y) 0
      40  #endif
      41  
      42  /* Test that modf(ARG1,&iptr) == FRACRES && iptr == INTRES.  Check the
      43     sign in case we get -0.0.  */
      44  #define TESTIT_MODF(ARG,INTRES,FRACRES) do { \
      45    float iptrf = 0.5; double iptr = 0.5; long double iptrl = 0.5; \
      46    if (__builtin_modff(ARG##f,&iptrf) != FRACRES##f \
      47        || CKIPTR(iptrf,INTRES##f) \
      48        || CKSGN_F(__builtin_modff(ARG##f,&iptrf),FRACRES##f) \
      49        || CKSGN_IPTR_F(iptrf,INTRES##f)) \
      50      link_error(__LINE__); \
      51    if (__builtin_modf(ARG,&iptr) != FRACRES \
      52        || CKIPTR(iptr,INTRES) \
      53        || CKSGN(__builtin_modf(ARG,&iptr),FRACRES) \
      54        || CKSGN_IPTR(iptr,INTRES)) \
      55      link_error(__LINE__); \
      56    if (__builtin_modfl(ARG##l,&iptrl) != FRACRES##l \
      57        || CKIPTR(iptrl,INTRES##l) \
      58        || CKSGN_L(__builtin_modfl(ARG##l,&iptrl),FRACRES##l) \
      59        || CKSGN_IPTR_L(iptrl,INTRES##l)) \
      60      link_error(__LINE__); \
      61    } while (0)
      62  
      63  /* Test that modf(NEG FUNCARG(ARGARG, &iptr)) == FRACRES &&
      64     FUNCRES(iptr) is true.  Check the sign of both as well.  This is
      65     for checking an argument of Inf.  */
      66  #define TESTIT_MODF2(NEG,FUNCARG,ARGARG,FUNCRES,FRACRES) do { \
      67    float iptrf = 0.5; double iptr = 0.5; long double iptrl = 0.5; \
      68    if (__builtin_modff(NEG __builtin_##FUNCARG##f(ARGARG),&iptrf) != FRACRES##f \
      69        || CKSGN_F(__builtin_modff(NEG __builtin_##FUNCARG##f(ARGARG),&iptrf), FRACRES##f) \
      70        || CKIPTR(!__builtin_##FUNCRES##f(iptrf),0) \
      71        || CKSGN_IPTR_F(iptrf,FRACRES##f)) \
      72      link_error(__LINE__); \
      73    if (__builtin_modf(NEG __builtin_##FUNCARG(ARGARG),&iptr) != FRACRES \
      74        || CKSGN(__builtin_modf(NEG __builtin_##FUNCARG(ARGARG),&iptr), FRACRES) \
      75        || CKIPTR(!__builtin_##FUNCRES(iptr),0) \
      76        || CKSGN_IPTR(iptr,FRACRES)) \
      77      link_error(__LINE__); \
      78    if (__builtin_modfl(NEG __builtin_##FUNCARG##l(ARGARG),&iptrl) != FRACRES##l \
      79        || CKSGN_L(__builtin_modfl(NEG __builtin_##FUNCARG##l(ARGARG),&iptrl), FRACRES##l) \
      80        || CKIPTR(!__builtin_##FUNCRES##l(iptrl),0) \
      81        || CKSGN_IPTR_L(iptrl,FRACRES##l)) \
      82      link_error(__LINE__); \
      83    } while (0)
      84  
      85  /* Test that FUNCRES(modf(NEG FUNCARG(ARGARG, &iptr))) is true &&
      86     FUNCRES(iptr) is true.  Check the sign of both as well.  This is
      87     for checking an argument of NaN.  */
      88  #define TESTIT_MODF3(NEG,FUNCARG,ARGARG,FUNCRES) do { \
      89    float iptrf = 0.5; double iptr = 0.5; long double iptrl = 0.5; \
      90    if (CKRES(!__builtin_##FUNCRES##f(__builtin_modff(NEG __builtin_##FUNCARG##f(ARGARG),&iptrf))) \
      91        || CKSGN_F(__builtin_modff(NEG __builtin_##FUNCARG##f(ARGARG),&iptrf), NEG 1) \
      92        || CKIPTR(!__builtin_##FUNCRES##f(iptrf),0) \
      93        || CKSGN_IPTR_F(iptrf,NEG 1)) \
      94      link_error(__LINE__); \
      95    if (CKRES(!__builtin_##FUNCRES(__builtin_modf(NEG __builtin_##FUNCARG(ARGARG),&iptr))) \
      96        || CKSGN(__builtin_modf(NEG __builtin_##FUNCARG(ARGARG),&iptr), NEG 1) \
      97        || CKIPTR(!__builtin_##FUNCRES(iptr),0) \
      98        || CKSGN_IPTR(iptr,NEG 1)) \
      99      link_error(__LINE__); \
     100    if (CKRES(!__builtin_##FUNCRES##l(__builtin_modfl(NEG __builtin_##FUNCARG##l(ARGARG),&iptrl))) \
     101        || CKSGN_L(__builtin_modfl(NEG __builtin_##FUNCARG##l(ARGARG),&iptrl), NEG 1) \
     102        || CKIPTR(!__builtin_##FUNCRES##l(iptrl),0) \
     103        || CKSGN_IPTR_L(iptrl,NEG 1)) \
     104      link_error(__LINE__); \
     105    } while (0)
     106  
     107  void __attribute__ ((__noinline__))
     108  foo(void)
     109  {
     110    /* Test that modf(ARG1,&iptr) -> ARG3 && iptr == ARG2.  */
     111    TESTIT_MODF (0x1p10F+0.5, 0x1p10, 0.5);
     112    TESTIT_MODF (0x1p10F+0x1p-10, 0x1p10, 0x1p-10);
     113    TESTIT_MODF (12345678L/17.0, 726216.0, -726216L+12345678L/17.0);
     114    TESTIT_MODF (555.555, 555.0, -555+555.555);
     115    TESTIT_MODF (5000/11.0, 454.0, -454+5000/11.0);
     116    TESTIT_MODF (1000/7.0, 142.0, -142+1000/7.0);
     117    TESTIT_MODF (123/7.0, 17.0, -17+123/7.0);
     118    TESTIT_MODF (117/7.0, 16.0, -16+117/7.0);
     119    TESTIT_MODF (5.5, 5.0, 0.5);
     120    TESTIT_MODF (1.5, 1.0, 0.5);
     121    TESTIT_MODF (4/3.0, 1.0, -1+4/3.0);
     122    TESTIT_MODF (1.0, 1.0, 0.0);
     123    TESTIT_MODF (0.5, 0.0, 0.5);
     124    TESTIT_MODF (4/9.0, 0.0, 4/9.0);
     125    TESTIT_MODF (1/3.0, 0.0, 1/3.0);
     126    TESTIT_MODF (1/9.0, 0.0, 1/9.0);
     127    TESTIT_MODF (0.0, 0.0, 0.0);
     128  
     129    TESTIT_MODF (-0.0, -0.0, -0.0);
     130    TESTIT_MODF (-1/9.0, -0.0, -1/9.0);
     131    TESTIT_MODF (-1/3.0, -0.0, -1/3.0);
     132    TESTIT_MODF (-4/9.0, -0.0, -4/9.0);
     133    TESTIT_MODF (-0.5, -0.0, -0.5);
     134    TESTIT_MODF (-1.0, -1.0, -0.0);
     135    TESTIT_MODF (-4/3.0, -1.0, 1-4/3.0);
     136    TESTIT_MODF (-1.5, -1.0, -0.5);
     137    TESTIT_MODF (-5.5, -5.0, -0.5);
     138    TESTIT_MODF (-117/7.0, -16.0, 16-117/7.0);
     139    TESTIT_MODF (-123/7.0, -17.0, 17-123/7.0);
     140    TESTIT_MODF (-1000/7.0, -142.0, 142-1000/7.0);
     141    TESTIT_MODF (-5000/11.0, -454.0, 454-5000/11.0);
     142    TESTIT_MODF (-555.555, -555.0, 555-555.555);
     143    TESTIT_MODF (-12345678L/17.0, -726216.0, 726216L-12345678L/17.0);
     144    TESTIT_MODF (-0x1p10F-0x1p-10, -0x1p10, -0x1p-10);
     145    TESTIT_MODF (-0x1p10F-0.5, -0x1p10, -0.5);
     146  
     147    
     148    /* Test for modf(+-Inf,&i) -> (i=+-0.0, +-Inf).  */
     149    TESTIT_MODF2 ( ,inf, , isinf, 0.0);
     150    TESTIT_MODF2 (- ,inf, , isinf, -0.0);
     151  
     152    /* Test for and modf(+-NaN,&i) -> (i=+-NaN, +-NaN).  */
     153    TESTIT_MODF3 ( ,nan, "", isnan);
     154    TESTIT_MODF3 (- ,nan, "", isnan);
     155  }
     156  
     157  int main()
     158  {
     159    foo();
     160    
     161    return 0;
     162  }