diff options
author | sayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-02-01 14:59:15 +0000 |
---|---|---|
committer | sayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-02-01 14:59:15 +0000 |
commit | 27f261ef4818d094a7aac1d249a64fc96d9a9ca5 (patch) | |
tree | 5685a3fc60b869436c4a4d9ec1766345aa482fd1 /gcc/builtins.c | |
parent | 53fddb7b4c0ef09c304899ab28441d0289226753 (diff) | |
download | gcc-27f261ef4818d094a7aac1d249a64fc96d9a9ca5.tar.gz |
* builtins.def (BUILT_IN_SIGNBIT, BUILT_IN_SIGNBITF,
BUILT_IN_SIGNBITL): New GCC builtins.
* builtins.c (expand_builtin_signbit): New function to RTL expand
calls to signbit, signbitf and signbitl as inline intrinsics.
(expand_builtin): Call expand_builtin_signbit for BUILT_IN_SIGNBIT*.
(fold_builtin_signbit): New function to perform constant folding
of signbit, signbitf and signbitl.
(fold_builtin): Call fold_builtin_signbit for BUILT_IN_SIGNBIT*.
* doc/extend.texi: Document new signbit{,f,l} builtins.
* gcc.dg/builtins-1.c: Also test for __builtin_signbit{,f,l}.
* gcc.dg/builtins-31.c: New testcase.
* gcc.dg/builtins-32.c: New testcase.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@77070 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 2dfc0e8a89e..8b15e7c18d8 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -152,6 +152,7 @@ static tree fold_trunc_transparent_mathfn (tree); static bool readonly_data_expr (tree); static rtx expand_builtin_fabs (tree, rtx, rtx); static rtx expand_builtin_cabs (tree, rtx); +static rtx expand_builtin_signbit (tree, rtx); static tree fold_builtin_cabs (tree, tree, tree); static tree fold_builtin_trunc (tree); static tree fold_builtin_floor (tree); @@ -166,6 +167,7 @@ static tree fold_builtin_strncpy (tree); static tree fold_builtin_memcmp (tree); static tree fold_builtin_strcmp (tree); static tree fold_builtin_strncmp (tree); +static tree fold_builtin_signbit (tree); /* Return the alignment in bits of EXP, a pointer valued expression. But don't return more than MAX_ALIGN no matter what. @@ -4920,6 +4922,97 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) return 0; } + +/* Expand a call to the built-in signbit, signbitf or signbitl function. + Return NULL_RTX if a normal call should be emitted rather than expanding + the function in-line. EXP is the expression that is a call to the builtin + function; if convenient, the result should be placed in TARGET. */ + +static rtx +expand_builtin_signbit (tree exp, rtx target) +{ + const struct real_format *fmt; + enum machine_mode fmode, imode, rmode; + HOST_WIDE_INT hi, lo; + tree arg, arglist; + int bitpos; + rtx temp; + + arglist = TREE_OPERAND (exp, 1); + if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return 0; + + arg = TREE_VALUE (arglist); + fmode = TYPE_MODE (TREE_TYPE (arg)); + rmode = TYPE_MODE (TREE_TYPE (exp)); + fmt = REAL_MODE_FORMAT (fmode); + + /* For floating point formats without a sign bit, implement signbit + as "ARG < 0.0". */ + if (fmt->signbit < 0) + { + /* But we can't do this if the format supports signed zero. */ + if (fmt->has_signed_zero && HONOR_SIGNED_ZEROS (fmode)) + return 0; + + arg = fold (build (LT_EXPR, TREE_TYPE (exp), arg, + build_real (TREE_TYPE (arg), dconst0))); + return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL); + } + + imode = int_mode_for_mode (fmode); + if (imode == BLKmode) + return 0; + + bitpos = fmt->signbit; + /* Handle targets with different FP word orders. */ + if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN) + { + int nwords = GET_MODE_BITSIZE (fmode) / BITS_PER_WORD; + int word = nwords - (bitpos / BITS_PER_WORD) - 1; + bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD; + } + + /* If the sign bit is not in the lowpart and the floating point format + is wider than an integer, check that is twice the size of an integer + so that we can use gen_highpart below. */ + if (bitpos >= GET_MODE_BITSIZE (rmode) + && GET_MODE_BITSIZE (imode) != 2 * GET_MODE_BITSIZE (rmode)) + return 0; + + temp = expand_expr (arg, NULL_RTX, VOIDmode, 0); + temp = gen_lowpart (imode, temp); + + if (GET_MODE_BITSIZE (imode) < GET_MODE_BITSIZE (rmode)) + temp = gen_lowpart (rmode, temp); + else if (GET_MODE_BITSIZE (imode) > GET_MODE_BITSIZE (rmode)) + { + if (bitpos > GET_MODE_BITSIZE (rmode)) + { + temp = gen_highpart (rmode, temp); + bitpos %= GET_MODE_BITSIZE (rmode); + } + else + temp = gen_lowpart (rmode, temp); + } + + if (bitpos < HOST_BITS_PER_WIDE_INT) + { + hi = 0; + lo = (HOST_WIDE_INT) 1 << bitpos; + } + else + { + hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT); + lo = 0; + } + + temp = force_reg (rmode, temp); + temp = expand_binop (rmode, and_optab, temp, + immed_double_const (lo, hi, rmode), + target, 1, OPTAB_LIB_WIDEN); + return temp; +} /* Expand an expression EXP that calls a built-in function, with result going to TARGET if that's convenient @@ -5411,6 +5504,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; + case BUILT_IN_SIGNBIT: + case BUILT_IN_SIGNBITF: + case BUILT_IN_SIGNBITL: + target = expand_builtin_signbit (exp, target); + if (target) + return target; + break; + /* Various hooks for the DWARF 2 __throw routine. */ case BUILT_IN_UNWIND_INIT: expand_builtin_unwind_init (); @@ -6528,6 +6629,44 @@ fold_builtin_strncmp (tree exp) return 0; } +/* Fold function call to builtin signbit, signbitf or signbitl. Return + NULL_TREE if no simplification can be made. */ + +static tree +fold_builtin_signbit (tree exp) +{ + tree arglist = TREE_OPERAND (exp, 1); + tree arg, temp; + + if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return NULL_TREE; + + arg = TREE_VALUE (arglist); + + /* If ARG is a compile-time constant, determine the result. */ + if (TREE_CODE (arg) == REAL_CST + && !TREE_CONSTANT_OVERFLOW (arg)) + { + REAL_VALUE_TYPE c; + + c = TREE_REAL_CST (arg); + temp = REAL_VALUE_NEGATIVE (c) ? integer_one_node : integer_zero_node; + return convert (TREE_TYPE (exp), temp); + } + + /* If ARG is non-negative, the result is always zero. */ + if (tree_expr_nonnegative_p (arg)) + return omit_one_operand (TREE_TYPE (exp), integer_zero_node, arg); + + /* If ARG's format doesn't have signed zeros, return "arg < 0.0". */ + if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg)))) + return fold (build (LT_EXPR, TREE_TYPE (exp), arg, + build_real (TREE_TYPE (arg), dconst0))); + + return NULL_TREE; +} + + /* Used by constant folding to eliminate some builtin calls early. EXP is the CALL_EXPR of a call to a builtin function. */ @@ -6949,6 +7088,11 @@ fold_builtin (tree exp) case BUILT_IN_STRNCMP: return fold_builtin_strncmp (exp); + case BUILT_IN_SIGNBIT: + case BUILT_IN_SIGNBITF: + case BUILT_IN_SIGNBITL: + return fold_builtin_signbit (exp); + default: break; } |