diff options
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/builtins.c | 87 | ||||
-rw-r--r-- | gcc/fold-const.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/builtin-logb-1.c | 177 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/builtin-math-2.c | 26 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/builtin-nonneg-1.c | 1 |
8 files changed, 308 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 90a2abc2ac0..c0fcb118c42 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2007-02-23 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> + + * builtins.c (fold_builtin_logb, fold_builtin_significand): New. + (fold_builtin_1): Use them. + * fold-const.c (tree_expr_nonnegative_warnv_p): Handle + BUILT_IN_SIGNIFICAND. + 2007-02-23 H.J. Lu <hongjiu.lu@intel.com> * config/i386/i386.c (bdesc_1arg): Initialize diff --git a/gcc/builtins.c b/gcc/builtins.c index 5c6dd4d930c..d7074ed3ebb 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -9017,6 +9017,86 @@ fold_builtin_carg (tree arg, tree type) return NULL_TREE; } +/* Fold a call to builtin logb/ilogb. */ + +static tree +fold_builtin_logb (tree arg, tree rettype) +{ + if (! validate_arg (arg, REAL_TYPE)) + return NULL_TREE; + + STRIP_NOPS (arg); + + if (TREE_CODE (arg) == REAL_CST && ! TREE_OVERFLOW (arg)) + { + const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg); + + switch (value->cl) + { + case rvc_nan: + case rvc_inf: + /* If arg is Inf or NaN and we're logb, return it. */ + if (TREE_CODE (rettype) == REAL_TYPE) + return fold_convert (rettype, arg); + /* Fall through... */ + case rvc_zero: + /* Zero may set errno and/or raise an exception for logb, also + for ilogb we don't know FP_ILOGB0. */ + return NULL_TREE; + case rvc_normal: + /* For normal numbers, proceed iff radix == 2. In GCC, + normalized significands are in the range [0.5, 1.0). We + want the exponent as if they were [1.0, 2.0) so get the + exponent and subtract 1. */ + if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg)))->b == 2) + return fold_convert (rettype, build_int_cst (NULL_TREE, + REAL_EXP (value)-1)); + break; + } + } + + return NULL_TREE; +} + +/* Fold a call to builtin significand, if radix == 2. */ + +static tree +fold_builtin_significand (tree arg, tree rettype) +{ + if (! validate_arg (arg, REAL_TYPE)) + return NULL_TREE; + + STRIP_NOPS (arg); + + if (TREE_CODE (arg) == REAL_CST && ! TREE_OVERFLOW (arg)) + { + const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg); + + switch (value->cl) + { + case rvc_zero: + case rvc_nan: + case rvc_inf: + /* If arg is +-0, +-Inf or +-NaN, then return it. */ + return fold_convert (rettype, arg); + case rvc_normal: + /* For normal numbers, proceed iff radix == 2. */ + if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg)))->b == 2) + { + REAL_VALUE_TYPE result = *value; + /* In GCC, normalized significands are in the range [0.5, + 1.0). We want them to be [1.0, 2.0) so set the + exponent to 1. */ + SET_REAL_EXP (&result, 1); + return build_real (rettype, result); + } + break; + } + } + + return NULL_TREE; +} + /* Fold a call to builtin frexp, we can assume the base is 2. */ static tree @@ -9526,6 +9606,13 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore) CASE_FLT_FN (BUILT_IN_SIGNBIT): return fold_builtin_signbit (arg0, type); + CASE_FLT_FN (BUILT_IN_SIGNIFICAND): + return fold_builtin_significand (arg0, type); + + CASE_FLT_FN (BUILT_IN_ILOGB): + CASE_FLT_FN (BUILT_IN_LOGB): + return fold_builtin_logb (arg0, type); + case BUILT_IN_ISASCII: return fold_builtin_isascii (arg0); diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 1e623003d18..ffd63cf5e7e 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -13356,6 +13356,7 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p) CASE_FLT_FN (BUILT_IN_SCALBLN): CASE_FLT_FN (BUILT_IN_SCALBN): CASE_FLT_FN (BUILT_IN_SIGNBIT): + CASE_FLT_FN (BUILT_IN_SIGNIFICAND): CASE_FLT_FN (BUILT_IN_SINH): CASE_FLT_FN (BUILT_IN_TANH): CASE_FLT_FN (BUILT_IN_TRUNC): diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 550665f1cda..cce1dd9897a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2007-02-23 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> + + * gcc.dg/torture/builtin-logb-1.c: New test. + * gcc.dg/torture/builtin-math-2.c: Test logb/ilogb. + * gcc.dg/torture/builtin-nonneg-1.c: Test significand. + * gcc.dg/torture/builtin-frexp-1.c: Use -fno-finite-math-only on + sh* targets. + 2007-02-23 Richard Guenther <rguenther@suse.de> * g++.dg/warn/changes-meaning.C: New testcase. diff --git a/gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c b/gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c index d0662d77444..5a8e90f64e1 100644 --- a/gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c +++ b/gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c @@ -6,6 +6,7 @@ Origin: Kaveh R. Ghazi, February 21, 2007. */ /* { dg-do link } */ +/* { dg-options "-fno-finite-math-only" { target sh*-*-* } } */ extern void link_error(int); diff --git a/gcc/testsuite/gcc.dg/torture/builtin-logb-1.c b/gcc/testsuite/gcc.dg/torture/builtin-logb-1.c new file mode 100644 index 00000000000..6abf8a76567 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-logb-1.c @@ -0,0 +1,177 @@ +/* Copyright (C) 2007 Free Software Foundation. + + Verify that built-in folding of logb, ilogb and significand is + correctly performed by the compiler. + + Origin: Kaveh R. Ghazi, February 22, 2007. */ + +/* { dg-do link } */ +/* { dg-options "-fno-finite-math-only" { target sh*-*-* } } */ + +extern void link_error(int); + +/* Return TRUE if the sign of X != sign of Y. This is important when + comparing signed zeros. */ +#define CKSGN_F(X,Y) \ + (__builtin_copysignf(1.0F,(X)) != __builtin_copysignf(1.0F,(Y))) +#define CKSGN(X,Y) \ + (__builtin_copysign(1.0,(X)) != __builtin_copysign(1.0,(Y))) +#define CKSGN_L(X,Y) \ + (__builtin_copysignl(1.0L,(X)) != __builtin_copysignl(1.0L,(Y))) + +/* Test that FUNC(ARG) == RES. Check the sign in case we get -0.0. */ +#define TESTIT(FUNC,ARG,RES) do { \ + if (__builtin_##FUNC##f(ARG##f) != RES##f \ + || CKSGN_F(__builtin_##FUNC##f(ARG##f),RES##f)) \ + link_error(__LINE__); \ + if (__builtin_##FUNC(ARG) != RES \ + || CKSGN(__builtin_##FUNC(ARG),RES)) \ + link_error(__LINE__); \ + if (__builtin_##FUNC##l(ARG##l) != RES##l \ + || CKSGN_L(__builtin_##FUNC##l(ARG##l),RES##l)) \ + link_error(__LINE__); \ + } while (0) + +/* Test that FUNC(ARG) == RES. RES is an int so it can't be -0.0. */ +#define TESTIT2(FUNC,ARG,RES) do { \ + if (__builtin_##FUNC##f(ARG##f) != RES) \ + link_error(__LINE__); \ + if (__builtin_##FUNC(ARG) != RES) \ + link_error(__LINE__); \ + if (__builtin_##FUNC##l(ARG##l) != RES) \ + link_error(__LINE__); \ + } while (0) + +/* Test if FUNCRES(FUNC(NEG FUNCARG(ARGARG))) is false. Check the + sign as well. */ +#define TESTIT3(FUNC,NEG,FUNCARG,ARGARG,FUNCRES) do { \ + if (!__builtin_##FUNCRES##f(__builtin_##FUNC(NEG __builtin_##FUNCARG##f(ARGARG))) \ + || CKSGN_F(__builtin_##FUNC##f(NEG __builtin_##FUNCARG##f(ARGARG)), NEG __builtin_##FUNCARG##f(ARGARG))) \ + link_error(__LINE__); \ + if (!__builtin_##FUNCRES(__builtin_##FUNC(NEG __builtin_##FUNCARG(ARGARG))) \ + || CKSGN(__builtin_##FUNC(NEG __builtin_##FUNCARG(ARGARG)), NEG __builtin_##FUNCARG(ARGARG))) \ + link_error(__LINE__); \ + if (!__builtin_##FUNCRES##l(__builtin_##FUNC##l(NEG __builtin_##FUNCARG##l(ARGARG))) \ + || CKSGN_L(__builtin_##FUNC##l(NEG __builtin_##FUNCARG##l(ARGARG)), NEG __builtin_##FUNCARG##l(ARGARG))) \ + link_error(__LINE__); \ + } while (0) + +void __attribute__ ((__noinline__)) +foo(void) +{ + /* If radix == 2, test that logb(ARG2) -> ARG3. */ +#if __FLT_RADIX__ == 2 + TESTIT (logb, -0x1p40, 40.0); + TESTIT (logb, -0x1p30, 30.0); + TESTIT (logb, -0x1p20, 20.0); + TESTIT (logb, -0x1p10, 10.0); + TESTIT (logb, -0x1p5, 5.0); + TESTIT (logb, -100/3.0, 5.0); + TESTIT (logb, -2.0, 1.0); + TESTIT (logb, -1.5, 0.0); + TESTIT (logb, -1.0, 0.0); + TESTIT (logb, -1/3.0, -2.0); + TESTIT (logb, -1/9.0, -4.0); + TESTIT (logb, -0x1p-5, -5.0); + TESTIT (logb, -0x1p-10, -10.0); + TESTIT (logb, -0x1p-20, -20.0); + TESTIT (logb, -0x1p-30, -30.0); + TESTIT (logb, -0x1p-40, -40.0); + + TESTIT (logb, 0x1p-40, -40.0); + TESTIT (logb, 0x1p-30, -30.0); + TESTIT (logb, 0x1p-20, -20.0); + TESTIT (logb, 0x1p-10, -10.0); + TESTIT (logb, 0x1p-5, -5.0); + TESTIT (logb, 1/9.0, -4.0); + TESTIT (logb, 1/3.0, -2.0); + TESTIT (logb, 1.0, 0.0); + TESTIT (logb, 1.5, 0.0); + TESTIT (logb, 2.0, 1.0); + TESTIT (logb, 100/3.0, 5.0); + TESTIT (logb, 0x1p5, 5.0); + TESTIT (logb, 0x1p10, 10.0); + TESTIT (logb, 0x1p20, 20.0); + TESTIT (logb, 0x1p30, 30.0); + TESTIT (logb, 0x1p40, 40.0); +#endif + + /* If radix == 2, test that ilogb(ARG2) -> ARG3. */ +#if __FLT_RADIX__ == 2 + TESTIT2 (ilogb, -0x1p40, 40); + TESTIT2 (ilogb, -0x1p30, 30); + TESTIT2 (ilogb, -0x1p20, 20); + TESTIT2 (ilogb, -0x1p10, 10); + TESTIT2 (ilogb, -0x1p5, 5); + TESTIT2 (ilogb, -100/3.0, 5); + TESTIT2 (ilogb, -2.0, 1); + TESTIT2 (ilogb, -1.5, 0); + TESTIT2 (ilogb, -1.0, 0); + TESTIT2 (ilogb, -1/3.0, -2); + TESTIT2 (ilogb, -1/9.0, -4); + TESTIT2 (ilogb, -0x1p-5, -5); + TESTIT2 (ilogb, -0x1p-10, -10); + TESTIT2 (ilogb, -0x1p-20, -20); + TESTIT2 (ilogb, -0x1p-30, -30); + TESTIT2 (ilogb, -0x1p-40, -40); + + TESTIT2 (ilogb, 0x1p-40, -40); + TESTIT2 (ilogb, 0x1p-30, -30); + TESTIT2 (ilogb, 0x1p-20, -20); + TESTIT2 (ilogb, 0x1p-10, -10); + TESTIT2 (ilogb, 0x1p-5, -5); + TESTIT2 (ilogb, 1/9.0, -4); + TESTIT2 (ilogb, 1/3.0, -2); + TESTIT2 (ilogb, 1.0, 0); + TESTIT2 (ilogb, 1.5, 0); + TESTIT2 (ilogb, 2.0, 1); + TESTIT2 (ilogb, 100/3.0, 5); + TESTIT2 (ilogb, 0x1p5, 5); + TESTIT2 (ilogb, 0x1p10, 10); + TESTIT2 (ilogb, 0x1p20, 20); + TESTIT2 (ilogb, 0x1p30, 30); + TESTIT2 (ilogb, 0x1p40, 40); +#endif + + /* If radix == 2, test that significand(ARG2) -> ARG3. Zero always + folds regardless of the radix. */ + TESTIT (significand, -0.0, -0.0); + TESTIT (significand, 0.0, 0.0); + +#if __FLT_RADIX__ == 2 + TESTIT (significand, -0x1p5, -1.0); + TESTIT (significand, -100/3.0, -100/96.0); + TESTIT (significand, -1.5, -1.5); + TESTIT (significand, -1.0, -1.0); + TESTIT (significand, -1/3.0, -4/3.0); + TESTIT (significand, -1/9.0, -16/9.0); + TESTIT (significand, -0x1p-5, -1.0); + + TESTIT (significand, 0x1p-5, 1.0); + TESTIT (significand, 1/9.0, 16/9.0); + TESTIT (significand, 1/3.0, 4/3.0); + TESTIT (significand, 1.0, 1.0); + TESTIT (significand, 1.5, 1.5); + TESTIT (significand, 100/3.0, 100/96.0); + TESTIT (significand, 0x1p5, 1.0); +#endif + + /* Test for f(+-Inf) -> +-Inf and f(+-NaN) -> +-NaN, regardless of + the radix. */ + TESTIT3 (logb, ,inf, , isinf); + TESTIT3 (logb, - ,inf, , isinf); + TESTIT3 (logb, ,nan, "", isnan); + TESTIT3 (logb, - ,nan, "", isnan); + + TESTIT3 (significand, ,inf, , isinf); + TESTIT3 (significand, - ,inf, , isinf); + TESTIT3 (significand, ,nan, "", isnan); + TESTIT3 (significand, - ,nan, "", isnan); +} + +int main() +{ + foo (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/builtin-math-2.c b/gcc/testsuite/gcc.dg/torture/builtin-math-2.c index 7c6fad0d628..5153ae49214 100644 --- a/gcc/testsuite/gcc.dg/torture/builtin-math-2.c +++ b/gcc/testsuite/gcc.dg/torture/builtin-math-2.c @@ -208,6 +208,26 @@ void bar() __DBL_MIN_EXP__, __LDBL_MIN__, __LDBL_MIN_EXP__); TESTIT2_I2ALL (scalbln, __FLT_MAX__, __FLT_MAX_EXP__, __DBL_MAX__, __DBL_MAX_EXP__, __LDBL_MAX__, __LDBL_MAX_EXP__); + + TESTIT (logb, 0.0); + TESTIT (logb, -0.0); + + TESTIT (ilogb, 0.0); + TESTIT (ilogb, -0.0); + + foof (__builtin_ilogbf (__builtin_inff())); + foo (__builtin_ilogb (__builtin_inf())); + fool (__builtin_ilogbl (__builtin_infl())); + foof (__builtin_ilogbf (-__builtin_inff())); + foo (__builtin_ilogb (-__builtin_inf())); + fool (__builtin_ilogbl (-__builtin_infl())); + + foof (__builtin_ilogbf (__builtin_nanf(""))); + foo (__builtin_ilogb (__builtin_nan(""))); + fool (__builtin_ilogbl (__builtin_nanl(""))); + foof (__builtin_ilogbf (-__builtin_nanf(""))); + foo (__builtin_ilogb (-__builtin_nan(""))); + fool (__builtin_ilogbl (-__builtin_nanl(""))); } /* { dg-final { scan-tree-dump-times "exp2 " 9 "original" } } */ @@ -258,4 +278,10 @@ void bar() /* { dg-final { scan-tree-dump-times "scalbln " 8 "original" } } */ /* { dg-final { scan-tree-dump-times "scalblnf" 8 "original" } } */ /* { dg-final { scan-tree-dump-times "scalblnl" 8 "original" } } */ +/* { dg-final { scan-tree-dump-times "_logb " 2 "original" } } */ +/* { dg-final { scan-tree-dump-times "_logbf" 2 "original" } } */ +/* { dg-final { scan-tree-dump-times "_logbl" 2 "original" } } */ +/* { dg-final { scan-tree-dump-times "ilogb " 6 "original" } } */ +/* { dg-final { scan-tree-dump-times "ilogbf" 6 "original" } } */ +/* { dg-final { scan-tree-dump-times "ilogbl" 6 "original" } } */ /* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/gcc.dg/torture/builtin-nonneg-1.c b/gcc/testsuite/gcc.dg/torture/builtin-nonneg-1.c index 1047881333b..54e628c5dc4 100644 --- a/gcc/testsuite/gcc.dg/torture/builtin-nonneg-1.c +++ b/gcc/testsuite/gcc.dg/torture/builtin-nonneg-1.c @@ -159,6 +159,7 @@ void test(double d1, double d2, float f1, float f2, ARG1TEST2_A2INT (scalbln, long); ARG1TEST2_A2INT (scalbn, int); ARG1TEST1_RTYPE (signbit, int); + ARG1TEST1 (significand); ARG1TEST1 (sinh); ARG1TEST1 (tanh); ARG1TEST1 (trunc); |