aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>2007-02-23 04:49:21 +0000
committerKaveh Ghazi <ghazi@gcc.gnu.org>2007-02-23 04:49:21 +0000
commit7a2a25ab4f30cc831c27f6f5cf22fc4be858d0a5 (patch)
tree9706519ce079df42783b918a0128eb2ee24cb68c /gcc/builtins.c
parent03d12b648e5fe9cafe390deac7918e22b032322f (diff)
downloadgcc-7a2a25ab4f30cc831c27f6f5cf22fc4be858d0a5.zip
gcc-7a2a25ab4f30cc831c27f6f5cf22fc4be858d0a5.tar.gz
gcc-7a2a25ab4f30cc831c27f6f5cf22fc4be858d0a5.tar.bz2
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
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index e1c2dee..5c6dd4d 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);