diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 95d49ac3020..74b905f131c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2006-11-01 Kaveh R. Ghazi + + PR middle-end/29335 + * builtins.c (do_mpfr_sincos): New. + (fold_builtin_1): Use it to fold builtin sincos. + 2006-11-01 Roger Sayle * config/darwin.h (CPP_SPEC): Handle -pthread, transforming diff --git a/gcc/builtins.c b/gcc/builtins.c index 7bbd632c222..64bb52b28bb 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -207,6 +207,7 @@ static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t), const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, bool); static tree do_mpfr_arg2 (tree, tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t)); +static tree do_mpfr_sincos (tree, tree, tree); /* Return true if NODE should be considered for inline expansion regardless of the optimization level. This means whenever a function is invoked with @@ -9184,6 +9185,12 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) CASE_FLT_FN (BUILT_IN_TAN): return fold_builtin_tan (arglist, type); + CASE_FLT_FN (BUILT_IN_SINCOS): + if (validate_arglist (arglist, REAL_TYPE, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return do_mpfr_sincos (TREE_VALUE (arglist), TREE_VALUE (TREE_CHAIN (arglist)), + TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)))); + break; + CASE_FLT_FN (BUILT_IN_SINH): if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_sinh, @@ -11594,3 +11601,58 @@ do_mpfr_arg2 (tree arg1, tree arg2, tree type, return result; } + +/* If argument ARG is a REAL_CST, call mpfr_sin_cos() on it and set + the pointers *(ARG_SINP) and *(ARG_COSP) to the resulting values. + The type is taken from the type of ARG and is used for setting the + precision of the calculation and results. */ + +static tree +do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp) +{ + tree result = NULL_TREE; + + STRIP_NOPS (arg); + + if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg)) + { + const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg); + + if (!real_isnan (ra) && !real_isinf (ra)) + { + tree const type = TREE_TYPE (arg); + const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p; + tree result_s, result_c; + int inexact; + mpfr_t m, ms, mc; + + mpfr_inits2 (prec, m, ms, mc, NULL); + mpfr_from_real (m, ra); + mpfr_clear_flags(); + inexact = mpfr_sin_cos (ms, mc, m, GMP_RNDN); + result_s = do_mpfr_ckconv (ms, type, inexact); + result_c = do_mpfr_ckconv (mc, type, inexact); + mpfr_clears (m, ms, mc, NULL); + if (result_s && result_c) + { + /* Dereference the sin/cos pointer arguments. */ + arg_sinp = build_fold_indirect_ref (arg_sinp); + arg_cosp = build_fold_indirect_ref (arg_cosp); + /* Proceed if valid pointer type were passed in. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (arg_sinp)) == TYPE_MAIN_VARIANT (type) + && TYPE_MAIN_VARIANT (TREE_TYPE (arg_cosp)) == TYPE_MAIN_VARIANT (type)) + { + /* Set the values. */ + result_s = fold_build2 (MODIFY_EXPR, type, arg_sinp, result_s); + TREE_SIDE_EFFECTS (result_s) = 1; + result_c = fold_build2 (MODIFY_EXPR, type, arg_cosp, result_c); + TREE_SIDE_EFFECTS (result_c) = 1; + /* Combine the assignments into a compound expr. */ + result = non_lvalue (fold_build2 (COMPOUND_EXPR, type, + result_s, result_c)); + } + } + } + } + return result; +} diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 39225777248..3c332b7179e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-11-01 Kaveh R. Ghazi + + * gcc.dg/torture/builtin-math-3.c: Fix semicolons. + (TESTIT_2P, TESTIT_2P_R): New macros. Test sincos. + 2006-11-01 Adam Nemet * gcc.dg/fold-mod-1.c: Match the leading 0x for the diff --git a/gcc/testsuite/gcc.dg/torture/builtin-math-3.c b/gcc/testsuite/gcc.dg/torture/builtin-math-3.c index 34e02720eff..afa78dc1580 100644 --- a/gcc/testsuite/gcc.dg/torture/builtin-math-3.c +++ b/gcc/testsuite/gcc.dg/torture/builtin-math-3.c @@ -21,7 +21,7 @@ extern void link_error(int); link_error(__LINE__); \ if (__builtin_##FUNC##l(ARG##L) != RES##L) \ link_error(__LINE__); \ - } while (0); + } while (0) /* Range test, check that (LOW) < FUNC(ARG) < (HI). */ #define TESTIT_R(FUNC,ARG,LOW,HI) do { \ @@ -31,7 +31,7 @@ extern void link_error(int); link_error(__LINE__); \ if (__builtin_##FUNC##l(ARG) <= (LOW) || __builtin_##FUNC##l(ARG) >= (HI)) \ link_error(__LINE__); \ - } while (0); + } while (0) /* Test that FUNC(ARG1, ARG2) == (RES). */ #define TESTIT2(FUNC,ARG1,ARG2,RES) do { \ @@ -41,7 +41,7 @@ extern void link_error(int); link_error(__LINE__); \ if (__builtin_##FUNC##l(ARG1##L, ARG2##L) != RES##L) \ link_error(__LINE__); \ - } while (0); + } while (0) /* Range test, check that (LOW) < FUNC(ARG1,ARG2) < (HI). */ #define TESTIT2_R(FUNC,ARG1,ARG2,LOW,HI) do { \ @@ -54,10 +54,47 @@ extern void link_error(int); if (__builtin_##FUNC##l(ARG1, ARG2) <= (LOW) \ || __builtin_##FUNC##l(ARG1, ARG2) >= (HI)) \ link_error(__LINE__); \ - } while (0); + } while (0) + +/* Test that for FUNC(ARG, &ARG_S, &ARG_C); + assert (ARG_S == RES_S && ARG_C == RES_C);. */ +#define TESTIT_2P(FUNC,ARG,ARG_S,ARG_C,RES_S,RES_C) do { \ + __builtin_##FUNC##f(ARG##F, &ARG_S##f, &ARG_C##f); \ + if (ARG_S##f != (RES_S##F) || ARG_C##f != (RES_C##F)) \ + link_error(__LINE__); \ + __builtin_##FUNC(ARG, &ARG_S, &ARG_C); \ + if (ARG_S != (RES_S) || ARG_C != (RES_C)) \ + link_error(__LINE__); \ + __builtin_##FUNC##l(ARG##L, &ARG_S##l, &ARG_C##l); \ + if (ARG_S##l != (RES_S##L) || ARG_C##l != (RES_C##L)) \ + link_error(__LINE__); \ + } while (0) + +/* Test that for FUNC(ARG, &ARG_S, &ARG_C); + assert (LOW_S < ARG_S < HI_S && LOW_C < ARG_C < HI_C);. */ +#define TESTIT_2P_R(FUNC,ARG,ARG_S,ARG_C,LOW_S,HI_S,LOW_C,HI_C) do { \ + __builtin_##FUNC##f(ARG##F, &ARG_S##f, &ARG_C##f); \ + if (ARG_S##f <= (LOW_S##F) || ARG_S##f >= (HI_S##F) \ + || ARG_C##f <= (LOW_C##F) || ARG_C##f >= (HI_C##F)) \ + link_error(__LINE__); \ + __builtin_##FUNC(ARG, &ARG_S, &ARG_C); \ + if (ARG_S <= (LOW_S) || ARG_S >= (HI_S) \ + || ARG_C <= (LOW_C) || ARG_C >= (HI_C)) \ + link_error(__LINE__); \ + __builtin_##FUNC##l(ARG##L, &ARG_S##l, &ARG_C##l); \ + if (ARG_S##l <= (LOW_S##L) || ARG_S##l >= (HI_S##L) \ + || ARG_C##l <= (LOW_C##L) || ARG_C##l >= (HI_C##L)) \ + link_error(__LINE__); \ + } while (0) int main (void) { +#ifdef __OPTIMIZE__ + float sf, cf; + double s, c; + long double sl, cl; +#endif + TESTIT_R (asin, -1.0, -3.15/2.0, -3.14/2.0); /* asin(-1) == -pi/2 */ TESTIT (asin, 0.0, 0.0); /* asin(0) == 0 */ TESTIT (asin, -0.0, -0.0); /* asin(-0) == -0 */ @@ -101,6 +138,15 @@ int main (void) TESTIT (tan, -0.0, -0.0); /* tan(-0) == -0 */ TESTIT_R (tan, 1.0, 1.55, 1.56); /* tan(1) == 1.557... */ +#ifdef __OPTIMIZE__ + /* These tests rely on propagating the variables s and c, which + happens only when optimization is turned on. */ + TESTIT_2P_R (sincos, -1.0, s, c, -0.85, -0.84, 0.54, 0.55); /* (s==-0.841..., c==0.5403...) */ + TESTIT_2P (sincos, 0.0, s, c, 0.0, 1.0); /* (s==0, c==1) */ + TESTIT_2P (sincos, -0.0, s, c, -0.0, 1.0); /* (s==-0, c==1) */ + TESTIT_2P_R (sincos, 1.0, s, c, 0.84, 0.85, 0.54, 0.55); /* (s==0.841..., c==0.5403...) */ +#endif + TESTIT_R (sinh, -1.0, -1.18, -1.17); /* sinh(-1) == -1.175... */ TESTIT (sinh, 0.0, 0.0); /* sinh(0) == 0 */ TESTIT (sinh, -0.0, -0.0); /* sinh(-0) == -0 */ @@ -207,16 +253,16 @@ int main (void) TESTIT2 (hypot, -3.0, -4.0, 5.0); /* hypot(-3,-4) == 5 */ TESTIT2_R (hypot, 4.0, 5.0, 6.40, 6.41); /* hypot(4,5) == 6.403... */ - TESTIT2 (atan2, 0.0, 0.0, 0.0) /* atan2(0,0) == 0 */ - TESTIT2 (atan2, -0.0, 0.0, -0.0) /* atan2(-0,0) == -0 */ - TESTIT2_R (atan2, 0.0, -0.0, 3.14, 3.15) /* atan2(0,-0) == pi */ - TESTIT2_R (atan2, -0.0, -0.0, -3.15, -3.14) /* atan2(-0,-0) == -pi */ - TESTIT2_R (atan2, 0.0, -1.0, 3.14, 3.15) /* atan2(0,-1) == pi */ - TESTIT2_R (atan2, -0.0, -1.0, -3.15, -3.14) /* atan2(-0,-1) == -pi */ - TESTIT2 (atan2, 0.0, 1.0, 0.0) /* atan2(0,1) == 0 */ - TESTIT2 (atan2, -0.0, 1.0, -0.0) /* atan2(-0,1) == -0 */ - TESTIT2_R (atan2, -1.0, 0.0, -1.58, -1.57) /* atan2(-1,0) == -pi/2 */ - TESTIT2_R (atan2, 1.0, 0.0, 1.57, 1.58) /* atan2(1,0) == pi/2 */ + TESTIT2 (atan2, 0.0, 0.0, 0.0); /* atan2(0,0) == 0 */ + TESTIT2 (atan2, -0.0, 0.0, -0.0); /* atan2(-0,0) == -0 */ + TESTIT2_R (atan2, 0.0, -0.0, 3.14, 3.15); /* atan2(0,-0) == pi */ + TESTIT2_R (atan2, -0.0, -0.0, -3.15, -3.14); /* atan2(-0,-0) == -pi */ + TESTIT2_R (atan2, 0.0, -1.0, 3.14, 3.15); /* atan2(0,-1) == pi */ + TESTIT2_R (atan2, -0.0, -1.0, -3.15, -3.14); /* atan2(-0,-1) == -pi */ + TESTIT2 (atan2, 0.0, 1.0, 0.0); /* atan2(0,1) == 0 */ + TESTIT2 (atan2, -0.0, 1.0, -0.0); /* atan2(-0,1) == -0 */ + TESTIT2_R (atan2, -1.0, 0.0, -1.58, -1.57); /* atan2(-1,0) == -pi/2 */ + TESTIT2_R (atan2, 1.0, 0.0, 1.57, 1.58); /* atan2(1,0) == pi/2 */ return 0; }