From: ghazi Date: Fri, 23 Feb 2007 04:49:21 +0000 (+0000) Subject: * builtins.c (fold_builtin_frexp): New. X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=commitdiff_plain;h=3838b9ae26869d5eebf8716293d27594c421c28a * builtins.c (fold_builtin_frexp): New. (fold_builtin_2): Use it. testsuite: * gcc.dg/torture/builtin-frexp-1.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@122249 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 641648d5e35..cd1e85d0881 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2007-02-22 Kaveh R. Ghazi + + * builtins.c (fold_builtin_frexp): New. + (fold_builtin_2): Use it. + 2007-02-22 Mark Mitchell * doc/invoke.texi (Spec Files): Document getenv spec function. diff --git a/gcc/builtins.c b/gcc/builtins.c index e1c2deef647..5c6dd4d930c 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -9017,6 +9017,62 @@ fold_builtin_carg (tree arg, tree type) return NULL_TREE; } +/* Fold a call to builtin frexp, we can assume the base is 2. */ + +static tree +fold_builtin_frexp (tree arg0, tree arg1, tree rettype) +{ + if (! validate_arg (arg0, REAL_TYPE) || ! validate_arg (arg1, POINTER_TYPE)) + return NULL_TREE; + + STRIP_NOPS (arg0); + + if (!(TREE_CODE (arg0) == REAL_CST && ! TREE_OVERFLOW (arg0))) + return NULL_TREE; + + arg1 = build_fold_indirect_ref (arg1); + + /* Proceed if a valid pointer type was passed in. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (arg1)) == integer_type_node) + { + const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg0); + tree frac, exp; + + switch (value->cl) + { + case rvc_zero: + /* For +-0, return (*exp = 0, +-0). */ + exp = integer_zero_node; + frac = arg0; + break; + case rvc_nan: + case rvc_inf: + /* For +-NaN or +-Inf, *exp is unspecified, return arg0. */ + return omit_one_operand (rettype, arg0, arg1); + case rvc_normal: + { + /* Since the frexp function always expects base 2, and in + GCC normalized significands are already in the range + [0.5, 1.0), we have exactly what frexp wants. */ + REAL_VALUE_TYPE frac_rvt = *value; + SET_REAL_EXP (&frac_rvt, 0); + frac = build_real (rettype, frac_rvt); + exp = build_int_cst (NULL_TREE, REAL_EXP (value)); + } + break; + default: + gcc_unreachable (); + } + + /* Create the COMPOUND_EXPR (*arg1 = trunc, frac). */ + arg1 = fold_build2 (MODIFY_EXPR, rettype, arg1, exp); + TREE_SIDE_EFFECTS (arg1) = 1; + return fold_build2 (COMPOUND_EXPR, rettype, arg1, frac); + } + + return NULL_TREE; +} + /* Fold a call to builtin ldexp or scalbn/scalbln. If LDEXP is true then we can assume the base is two. If it's false, then we have to check the mode of the TYPE parameter in certain cases. */ @@ -9544,6 +9600,9 @@ fold_builtin_2 (tree fndecl, tree arg0, tree arg1, bool ignore) CASE_FLT_FN (BUILT_IN_SCALBLN): return fold_builtin_load_exponent (arg0, arg1, type, /*ldexp=*/false); + CASE_FLT_FN (BUILT_IN_FREXP): + return fold_builtin_frexp (arg0, arg1, type); + case BUILT_IN_BZERO: return fold_builtin_bzero (arg0, arg1, ignore); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ad1b567669f..dd2deb419b4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2007-02-22 Kaveh R. Ghazi + + * gcc.dg/torture/builtin-frexp-1.c: New test. + 2007-02-22 Mark Mitchell * g++.dg/opt/switch4.C: Pass -fshort-enums -w. diff --git a/gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c b/gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c new file mode 100644 index 00000000000..d0662d77444 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2007 Free Software Foundation. + + Verify that built-in folding of frexp is correctly performed by the + compiler. + + Origin: Kaveh R. Ghazi, February 21, 2007. */ + +/* { dg-do link } */ + +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))) + +/* We can only check the exponent when optimizing since we rely on + other optimizations to propagate the value. TRUE means an error + occurred. */ +#ifdef __OPTIMIZE__ +#define CKEXP(X,Y) X != Y +#else +#define CKEXP(X,Y) 0 +#endif + +/* Test that frexp(ARG,&i) == RES && i == EXP. Check the sign in + case we get -0.0. */ +#define TESTIT_FREXP(ARG,RES,EXP) do { \ + int i = 123456; \ + if (__builtin_frexpf(ARG##f,&i) != RES##f \ + || CKEXP(i,EXP) \ + || CKSGN_F(__builtin_frexpf(ARG##f,&i),RES##f)) \ + link_error(__LINE__); \ + i = 123456; \ + if (__builtin_frexp(ARG,&i) != RES \ + || CKEXP(i,EXP) \ + || CKSGN(__builtin_frexp(ARG,&i),RES)) \ + link_error(__LINE__); \ + i = 123456; \ + if (__builtin_frexpl(ARG##l,&i) != RES##l \ + || CKEXP(i,EXP) \ + || CKSGN_L(__builtin_frexpl(ARG##l,&i),RES##l)) \ + link_error(__LINE__); \ + } while (0) + +/* Test that FUNCRES(frexp(NEG FUNCARG(ARGARG),&i)) is false. Check + the sign as well. Ensure side-effects are evaluated in i. */ +#define TESTIT_FREXP2(NEG,FUNCARG,ARGARG,FUNCRES) do { \ + int i=5; \ + if (!__builtin_##FUNCRES##f(__builtin_frexpf(NEG __builtin_##FUNCARG##f(ARGARG),&i)) \ + || CKSGN_F(__builtin_frexpf(NEG __builtin_##FUNCARG##f(ARGARG),(i++,&i)), NEG __builtin_##FUNCARG##f(ARGARG)) \ + || CKEXP(i,6)) \ + link_error(__LINE__); \ + if (!__builtin_##FUNCRES(__builtin_frexp(NEG __builtin_##FUNCARG(ARGARG),&i)) \ + || CKSGN(__builtin_frexp(NEG __builtin_##FUNCARG(ARGARG),(i++,&i)), NEG __builtin_##FUNCARG(ARGARG)) \ + || CKEXP(i,7)) \ + link_error(__LINE__); \ + if (!__builtin_##FUNCRES##l(__builtin_frexpl(NEG __builtin_##FUNCARG##l(ARGARG),&i)) \ + || CKSGN_L(__builtin_frexpl(NEG __builtin_##FUNCARG##l(ARGARG),(i++,&i)), NEG __builtin_##FUNCARG##l(ARGARG)) \ + || CKEXP(i,8)) \ + link_error(__LINE__); \ + } while (0) + +void __attribute__ ((__noinline__)) +foo(void) +{ + /* Test that frexp(ARG1,&i) -> ARG2 && i == ARG3. */ + TESTIT_FREXP (-0x1p40, -0.5, 41); + TESTIT_FREXP (-0x1p30, -0.5, 31); + TESTIT_FREXP (-0x1p20, -0.5, 21); + TESTIT_FREXP (-0x1p10, -0.5, 11); + TESTIT_FREXP (-0x1p5, -0.5, 6); + TESTIT_FREXP (-100/3.0, -100/192.0, 6); + TESTIT_FREXP (-1.5, -0.75, 1); + TESTIT_FREXP (-1.0, -0.5, 1); + TESTIT_FREXP (-1/3.0, -2/3.0, -1); + TESTIT_FREXP (-1/9.0, -8/9.0, -3); + TESTIT_FREXP (-0x1p-5, -0.5, -4); + TESTIT_FREXP (-0x1p-10, -0.5, -9); + TESTIT_FREXP (-0x1p-20, -0.5, -19); + TESTIT_FREXP (-0x1p-30, -0.5, -29); + TESTIT_FREXP (-0x1p-40, -0.5, -39); + TESTIT_FREXP (-0.0, -0.0, 0); + TESTIT_FREXP (0.0, 0.0, 0); + TESTIT_FREXP (0x1p-40, 0.5, -39); + TESTIT_FREXP (0x1p-30, 0.5, -29); + TESTIT_FREXP (0x1p-20, 0.5, -19); + TESTIT_FREXP (0x1p-10, 0.5, -9); + TESTIT_FREXP (0x1p-5, 0.5, -4); + TESTIT_FREXP (1/9.0, 8/9.0, -3); + TESTIT_FREXP (1/3.0, 2/3.0, -1); + TESTIT_FREXP (1.0, 0.5, 1); + TESTIT_FREXP (1.5, 0.75, 1); + TESTIT_FREXP (100/3.0, 100/192.0, 6); + TESTIT_FREXP (0x1p5, 0.5, 6); + TESTIT_FREXP (0x1p10, 0.5, 11); + TESTIT_FREXP (0x1p20, 0.5, 21); + TESTIT_FREXP (0x1p30, 0.5, 31); + TESTIT_FREXP (0x1p40, 0.5, 41); + + /* Test for frexp(+-Inf,&i) -> +-Inf and frexp(+-NaN,&i) -> +-NaN. + Exponent is left unspecified, but we test for side-effects. */ + TESTIT_FREXP2 ( ,inf, , isinf); + TESTIT_FREXP2 (- ,inf, , isinf); + TESTIT_FREXP2 ( ,nan, "", isnan); + TESTIT_FREXP2 (- ,nan, "", isnan); +} + +int main() +{ + foo (); + + return 0; +}