Commit 7a2a25ab by Kaveh R. Ghazi Committed by Kaveh Ghazi

builtins.c (fold_builtin_frexp): New.

	* builtins.c (fold_builtin_frexp): New.
	(fold_builtin_2): Use it.

testsuite:
	* gcc.dg/torture/builtin-frexp-1.c: New test.

From-SVN: r122249
parent 03d12b64
2007-02-22 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* builtins.c (fold_builtin_frexp): New.
(fold_builtin_2): Use it.
2007-02-22 Mark Mitchell <mark@codesourcery.com> 2007-02-22 Mark Mitchell <mark@codesourcery.com>
* doc/invoke.texi (Spec Files): Document getenv spec function. * doc/invoke.texi (Spec Files): Document getenv spec function.
......
...@@ -9017,6 +9017,62 @@ fold_builtin_carg (tree arg, tree type) ...@@ -9017,6 +9017,62 @@ fold_builtin_carg (tree arg, tree type)
return NULL_TREE; 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 /* 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 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. */ 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) ...@@ -9544,6 +9600,9 @@ fold_builtin_2 (tree fndecl, tree arg0, tree arg1, bool ignore)
CASE_FLT_FN (BUILT_IN_SCALBLN): CASE_FLT_FN (BUILT_IN_SCALBLN):
return fold_builtin_load_exponent (arg0, arg1, type, /*ldexp=*/false); 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: case BUILT_IN_BZERO:
return fold_builtin_bzero (arg0, arg1, ignore); return fold_builtin_bzero (arg0, arg1, ignore);
......
2007-02-22 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gcc.dg/torture/builtin-frexp-1.c: New test.
2007-02-22 Mark Mitchell <mark@codesourcery.com> 2007-02-22 Mark Mitchell <mark@codesourcery.com>
* g++.dg/opt/switch4.C: Pass -fshort-enums -w. * g++.dg/opt/switch4.C: Pass -fshort-enums -w.
/* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment