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);
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.
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;
+}
\f
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
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 ();
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. */
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;
}