static REAL_VALUE_TYPE dconste;
static int get_pointer_alignment (tree, unsigned int);
-static tree c_strlen (tree);
+static tree c_strlen (tree, int);
static const char *c_getstr (tree);
static rtx c_readstr (const char *, enum machine_mode);
static int target_char_cast (tree, char *);
static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
static rtx expand_builtin_frame_address (tree, tree);
static rtx expand_builtin_fputs (tree, int, int);
+static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode);
static tree stabilize_va_list (tree, int);
static rtx expand_builtin_expect (tree, rtx);
static tree fold_builtin_constant_p (tree);
way, because it could contain a zero byte in the middle.
TREE_STRING_LENGTH is the size of the character array, not the string.
+ ONLY_VALUE should be nonzero if the result is not going to be emitted
+ into the instruction stream and zero if it is going to be expanded.
+ E.g. with i++ ? "foo" : "bar", if ONLY_VALUE is nonzero, constant 3
+ is returned, otherwise NULL, since
+ len = c_strlen (src, 1); if (len) expand_expr (len, ...); would not
+ evaluate the side-effects.
+
The value returned is of type `ssizetype'.
Unfortunately, string_constant can't access the values of const char
arrays with initializers, so neither can we do so here. */
static tree
-c_strlen (tree src)
+c_strlen (tree src, int only_value)
{
tree offset_node;
HOST_WIDE_INT offset;
int max;
const char *ptr;
+ STRIP_NOPS (src);
+ if (TREE_CODE (src) == COND_EXPR
+ && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
+ {
+ tree len1, len2;
+
+ len1 = c_strlen (TREE_OPERAND (src, 1), only_value);
+ len2 = c_strlen (TREE_OPERAND (src, 2), only_value);
+ if (tree_int_cst_equal (len1, len2))
+ return len1;
+ }
+
+ if (TREE_CODE (src) == COMPOUND_EXPR
+ && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
+ return c_strlen (TREE_OPERAND (src, 1), only_value);
+
src = string_constant (src, &offset_node);
if (src == 0)
return 0;
do_pending_stack_adjust ();
NO_DEFER_POP;
- /* Save the stack with nonlocal if available */
+ /* Save the stack with nonlocal if available. */
#ifdef HAVE_save_stack_nonlocal
if (HAVE_save_stack_nonlocal)
emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX);
static void
expand_errno_check (tree exp, rtx target)
{
- rtx lab;
-
- if (flag_errno_math && HONOR_NANS (GET_MODE (target)))
- {
- lab = gen_label_rtx ();
+ rtx lab = gen_label_rtx ();
- /* Test the result; if it is NaN, set errno=EDOM because
- the argument was not in the domain. */
- emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
- 0, lab);
+ /* Test the result; if it is NaN, set errno=EDOM because
+ the argument was not in the domain. */
+ emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
+ 0, lab);
#ifdef TARGET_EDOM
- {
+ /* If this built-in doesn't throw an exception, set errno directly. */
+ if (TREE_NOTHROW (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
+ {
#ifdef GEN_ERRNO_RTX
- rtx errno_rtx = GEN_ERRNO_RTX;
+ rtx errno_rtx = GEN_ERRNO_RTX;
#else
- rtx errno_rtx
+ rtx errno_rtx
= gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
#endif
-
- emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
- }
-#else
- /* We can't set errno=EDOM directly; let the library call do it.
- Pop the arguments right away in case the call gets deleted. */
- NO_DEFER_POP;
- expand_call (exp, target, 0);
- OK_DEFER_POP;
-#endif
-
+ emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
emit_label (lab);
+ return;
}
+#endif
+
+ /* We can't set errno=EDOM directly; let the library call do it.
+ Pop the arguments right away in case the call gets deleted. */
+ NO_DEFER_POP;
+ expand_call (exp, target, 0);
+ OK_DEFER_POP;
+ emit_label (lab);
}
rtx op0, insns;
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
- enum machine_mode argmode;
+ enum machine_mode mode;
bool errno_set = false;
+ tree arg, narg;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return 0;
- /* Stabilize and compute the argument. */
- if (TREE_CODE (TREE_VALUE (arglist)) != VAR_DECL
- && TREE_CODE (TREE_VALUE (arglist)) != PARM_DECL)
- {
- exp = copy_node (exp);
- TREE_OPERAND (exp, 1) = arglist;
- /* Wrap the computation of the argument in a SAVE_EXPR. That
- way, if we need to expand the argument again (as in the
- flag_errno_math case below where we cannot directly set
- errno), we will not perform side-effects more than once.
- Note that here we're mutating the original EXP as well as the
- copy; that's the right thing to do in case the original EXP
- is expanded later. */
- TREE_VALUE (arglist) = save_expr (TREE_VALUE (arglist));
- arglist = copy_node (arglist);
- }
- op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
-
- /* Make a suitable register to place result in. */
- target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
-
- emit_queue ();
- start_sequence ();
+ arg = TREE_VALUE (arglist);
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_SQRT:
case BUILT_IN_SQRTF:
case BUILT_IN_SQRTL:
- errno_set = true; builtin_optab = sqrt_optab; break;
+ errno_set = ! tree_expr_nonnegative_p (arg);
+ builtin_optab = sqrt_optab;
+ break;
case BUILT_IN_EXP:
case BUILT_IN_EXPF:
case BUILT_IN_EXPL:
abort ();
}
+ /* Make a suitable register to place result in. */
+ mode = TYPE_MODE (TREE_TYPE (exp));
+ target = gen_reg_rtx (mode);
+
+ if (! flag_errno_math || ! HONOR_NANS (mode))
+ errno_set = false;
+
+ /* Wrap the computation of the argument in a SAVE_EXPR, as we may
+ need to expand the argument again. This way, we will not perform
+ side-effects more the once. */
+ narg = save_expr (arg);
+ if (narg != arg)
+ {
+ arglist = build_tree_list (NULL_TREE, arg);
+ exp = build_function_call_expr (fndecl, arglist);
+ }
+
+ op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+
+ emit_queue ();
+ start_sequence ();
+
/* Compute into TARGET.
Set TARGET to wherever the result comes back. */
- argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
- target = expand_unop (argmode, builtin_optab, op0, target, 0);
+ target = expand_unop (mode, builtin_optab, op0, target, 0);
- /* If we were unable to expand via the builtin, stop the
- sequence (without outputting the insns) and return 0, causing
- a call to the library function. */
+ /* If we were unable to expand via the builtin, stop the sequence
+ (without outputting the insns) and call to the library function
+ with the stabilized argument list. */
if (target == 0)
{
end_sequence ();
- return 0;
+ return expand_call (exp, target, target == const0_rtx);
}
if (errno_set)
rtx op0, op1, insns;
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
- tree arg0, arg1;
- enum machine_mode argmode;
+ tree arg0, arg1, temp, narg;
+ enum machine_mode mode;
bool errno_set = true;
bool stable = true;
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- /* Stabilize the arguments. */
- if (TREE_CODE (arg0) != VAR_DECL && TREE_CODE (arg0) != PARM_DECL)
+ switch (DECL_FUNCTION_CODE (fndecl))
{
- arg0 = save_expr (arg0);
- TREE_VALUE (arglist) = arg0;
- stable = false;
+ case BUILT_IN_POW:
+ case BUILT_IN_POWF:
+ case BUILT_IN_POWL:
+ builtin_optab = pow_optab; break;
+ case BUILT_IN_ATAN2:
+ case BUILT_IN_ATAN2F:
+ case BUILT_IN_ATAN2L:
+ builtin_optab = atan2_optab; break;
+ default:
+ abort ();
}
- if (TREE_CODE (arg1) != VAR_DECL && TREE_CODE (arg1) != PARM_DECL)
+
+ /* Make a suitable register to place result in. */
+ mode = TYPE_MODE (TREE_TYPE (exp));
+ target = gen_reg_rtx (mode);
+
+ if (! flag_errno_math || ! HONOR_NANS (mode))
+ errno_set = false;
+
+ /* Alway stabilize the argument list. */
+ narg = save_expr (arg1);
+ if (narg != arg1)
{
- arg1 = save_expr (arg1);
- TREE_VALUE (TREE_CHAIN (arglist)) = arg1;
+ temp = build_tree_list (NULL_TREE, narg);
stable = false;
}
+ else
+ temp = TREE_CHAIN (arglist);
- if (! stable)
+ narg = save_expr (arg0);
+ if (narg != arg0)
{
- exp = copy_node (exp);
- arglist = tree_cons (NULL_TREE, arg0,
- build_tree_list (NULL_TREE, arg1));
- TREE_OPERAND (exp, 1) = arglist;
+ arglist = tree_cons (NULL_TREE, narg, temp);
+ stable = false;
}
+ else if (! stable)
+ arglist = tree_cons (NULL_TREE, arg0, temp);
+
+ if (! stable)
+ exp = build_function_call_expr (fndecl, arglist);
op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
op1 = expand_expr (arg1, 0, VOIDmode, 0);
- /* Make a suitable register to place result in. */
- target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
-
emit_queue ();
start_sequence ();
- switch (DECL_FUNCTION_CODE (fndecl))
- {
- case BUILT_IN_POW:
- case BUILT_IN_POWF:
- case BUILT_IN_POWL:
- builtin_optab = pow_optab; break;
- case BUILT_IN_ATAN2:
- case BUILT_IN_ATAN2F:
- case BUILT_IN_ATAN2L:
- builtin_optab = atan2_optab; break;
- default:
- abort ();
- }
-
/* Compute into TARGET.
Set TARGET to wherever the result comes back. */
- argmode = TYPE_MODE (TREE_TYPE (arg0));
- target = expand_binop (argmode, builtin_optab, op0, op1,
+ target = expand_binop (mode, builtin_optab, op0, op1,
target, 0, OPTAB_DIRECT);
- /* If we were unable to expand via the builtin, stop the
- sequence (without outputting the insns) and return 0, causing
- a call to the library function. */
+ /* If we were unable to expand via the builtin, stop the sequence
+ (without outputting the insns) and call to the library function
+ with the stabilized argument list. */
if (target == 0)
{
end_sequence ();
- return 0;
+ return expand_call (exp, target, target == const0_rtx);
}
if (errno_set)
return target;
}
+/* To evaluate powi(x,n), the floating point value x raised to the
+ constant integer exponent n, we use a hybrid algorithm that
+ combines the "window method" with look-up tables. For an
+ introduction to exponentiation algorithms and "addition chains",
+ see section 4.6.3, "Evaluation of Powers" of Donald E. Knuth,
+ "Seminumerical Algorithms", Vol. 2, "The Art of Computer Programming",
+ 3rd Edition, 1998, and Daniel M. Gordon, "A Survey of Fast Exponentiation
+ Methods", Journal of Algorithms, Vol. 27, pp. 129-146, 1998. */
+
+/* Provide a default value for POWI_MAX_MULTS, the maximum number of
+ multiplications to inline before calling the system library's pow
+ function. powi(x,n) requires at worst 2*bits(n)-2 multiplications,
+ so this default never requires calling pow, powf or powl. */
+
+#ifndef POWI_MAX_MULTS
+#define POWI_MAX_MULTS (2*HOST_BITS_PER_WIDE_INT-2)
+#endif
+
+/* The size of the "optimal power tree" lookup table. All
+ exponents less than this value are simply looked up in the
+ powi_table below. This threshold is also used to size the
+ cache of pseudo registers that hold intermediate results. */
+#define POWI_TABLE_SIZE 256
+
+/* The size, in bits of the window, used in the "window method"
+ exponentiation algorithm. This is equivalent to a radix of
+ (1<<POWI_WINDOW_SIZE) in the corresponding "m-ary method". */
+#define POWI_WINDOW_SIZE 3
+
+/* The following table is an efficient representation of an
+ "optimal power tree". For each value, i, the corresponding
+ value, j, in the table states than an optimal evaluation
+ sequence for calculating pow(x,i) can be found by evaluating
+ pow(x,j)*pow(x,i-j). An optimal power tree for the first
+ 100 integers is given in Knuth's "Seminumerical algorithms". */
+
+static const unsigned char powi_table[POWI_TABLE_SIZE] =
+ {
+ 0, 1, 1, 2, 2, 3, 3, 4, /* 0 - 7 */
+ 4, 6, 5, 6, 6, 10, 7, 9, /* 8 - 15 */
+ 8, 16, 9, 16, 10, 12, 11, 13, /* 16 - 23 */
+ 12, 17, 13, 18, 14, 24, 15, 26, /* 24 - 31 */
+ 16, 17, 17, 19, 18, 33, 19, 26, /* 32 - 39 */
+ 20, 25, 21, 40, 22, 27, 23, 44, /* 40 - 47 */
+ 24, 32, 25, 34, 26, 29, 27, 44, /* 48 - 55 */
+ 28, 31, 29, 34, 30, 60, 31, 36, /* 56 - 63 */
+ 32, 64, 33, 34, 34, 46, 35, 37, /* 64 - 71 */
+ 36, 65, 37, 50, 38, 48, 39, 69, /* 72 - 79 */
+ 40, 49, 41, 43, 42, 51, 43, 58, /* 80 - 87 */
+ 44, 64, 45, 47, 46, 59, 47, 76, /* 88 - 95 */
+ 48, 65, 49, 66, 50, 67, 51, 66, /* 96 - 103 */
+ 52, 70, 53, 74, 54, 104, 55, 74, /* 104 - 111 */
+ 56, 64, 57, 69, 58, 78, 59, 68, /* 112 - 119 */
+ 60, 61, 61, 80, 62, 75, 63, 68, /* 120 - 127 */
+ 64, 65, 65, 128, 66, 129, 67, 90, /* 128 - 135 */
+ 68, 73, 69, 131, 70, 94, 71, 88, /* 136 - 143 */
+ 72, 128, 73, 98, 74, 132, 75, 121, /* 144 - 151 */
+ 76, 102, 77, 124, 78, 132, 79, 106, /* 152 - 159 */
+ 80, 97, 81, 160, 82, 99, 83, 134, /* 160 - 167 */
+ 84, 86, 85, 95, 86, 160, 87, 100, /* 168 - 175 */
+ 88, 113, 89, 98, 90, 107, 91, 122, /* 176 - 183 */
+ 92, 111, 93, 102, 94, 126, 95, 150, /* 184 - 191 */
+ 96, 128, 97, 130, 98, 133, 99, 195, /* 192 - 199 */
+ 100, 128, 101, 123, 102, 164, 103, 138, /* 200 - 207 */
+ 104, 145, 105, 146, 106, 109, 107, 149, /* 208 - 215 */
+ 108, 200, 109, 146, 110, 170, 111, 157, /* 216 - 223 */
+ 112, 128, 113, 130, 114, 182, 115, 132, /* 224 - 231 */
+ 116, 200, 117, 132, 118, 158, 119, 206, /* 232 - 239 */
+ 120, 240, 121, 162, 122, 147, 123, 152, /* 240 - 247 */
+ 124, 166, 125, 214, 126, 138, 127, 153, /* 248 - 255 */
+ };
+
+
+/* Return the number of multiplications required to calculate
+ powi(x,n) where n is less than POWI_TABLE_SIZE. This is a
+ subroutine of powi_cost. CACHE is an array indicating
+ which exponents have already been calculated. */
+
+static int
+powi_lookup_cost (unsigned HOST_WIDE_INT n, bool *cache)
+{
+ /* If we've already calculated this exponent, then this evaluation
+ doesn't require any additional multiplications. */
+ if (cache[n])
+ return 0;
+
+ cache[n] = true;
+ return powi_lookup_cost (n - powi_table[n], cache)
+ + powi_lookup_cost (powi_table[n], cache) + 1;
+}
+
+/* Return the number of multiplications required to calculate
+ powi(x,n) for an arbitrary x, given the exponent N. This
+ function needs to be kept in sync with expand_powi below. */
+
+static int
+powi_cost (HOST_WIDE_INT n)
+{
+ bool cache[POWI_TABLE_SIZE];
+ unsigned HOST_WIDE_INT digit;
+ unsigned HOST_WIDE_INT val;
+ int result;
+
+ if (n == 0)
+ return 0;
+
+ /* Ignore the reciprocal when calculating the cost. */
+ val = (n < 0) ? -n : n;
+
+ /* Initialize the exponent cache. */
+ memset (cache, 0, POWI_TABLE_SIZE * sizeof (bool));
+ cache[1] = true;
+
+ result = 0;
+
+ while (val >= POWI_TABLE_SIZE)
+ {
+ if (val & 1)
+ {
+ digit = val & ((1 << POWI_WINDOW_SIZE) - 1);
+ result += powi_lookup_cost (digit, cache)
+ + POWI_WINDOW_SIZE + 1;
+ val >>= POWI_WINDOW_SIZE;
+ }
+ else
+ {
+ val >>= 1;
+ result++;
+ }
+ }
+
+ return result + powi_lookup_cost (val, cache);
+}
+
+/* Recursive subroutine of expand_powi. This function takes the array,
+ CACHE, of already calculated exponents and an exponent N and returns
+ an RTX that corresponds to CACHE[1]**N, as calculated in mode MODE. */
+
+static rtx
+expand_powi_1 (enum machine_mode mode, unsigned HOST_WIDE_INT n, rtx *cache)
+{
+ unsigned HOST_WIDE_INT digit;
+ rtx target, result;
+ rtx op0, op1;
+
+ if (n < POWI_TABLE_SIZE)
+ {
+ if (cache[n])
+ return cache[n];
+
+ target = gen_reg_rtx (mode);
+ cache[n] = target;
+
+ op0 = expand_powi_1 (mode, n - powi_table[n], cache);
+ op1 = expand_powi_1 (mode, powi_table[n], cache);
+ }
+ else if (n & 1)
+ {
+ target = gen_reg_rtx (mode);
+ digit = n & ((1 << POWI_WINDOW_SIZE) - 1);
+ op0 = expand_powi_1 (mode, n - digit, cache);
+ op1 = expand_powi_1 (mode, digit, cache);
+ }
+ else
+ {
+ target = gen_reg_rtx (mode);
+ op0 = expand_powi_1 (mode, n >> 1, cache);
+ op1 = op0;
+ }
+
+ result = expand_mult (mode, op0, op1, target, 0);
+ if (result != target)
+ emit_move_insn (target, result);
+ return target;
+}
+
+/* Expand the RTL to evaluate powi(x,n) in mode MODE. X is the
+ floating point operand in mode MODE, and N is the exponent. This
+ function needs to be kept in sync with powi_cost above. */
+
+static rtx
+expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
+{
+ unsigned HOST_WIDE_INT val;
+ rtx cache[POWI_TABLE_SIZE];
+ rtx result;
+
+ if (n == 0)
+ return CONST1_RTX (mode);
+
+ val = (n < 0) ? -n : n;
+
+ memset (cache, 0, sizeof(cache));
+ cache[1] = x;
+
+ result = expand_powi_1 (mode, (n < 0) ? -n : n, cache);
+
+ /* If the original exponent was negative, reciprocate the result. */
+ if (n < 0)
+ result = expand_binop (mode, sdiv_optab, CONST1_RTX (mode),
+ result, NULL_RTX, 0, OPTAB_LIB_WIDEN);
+
+ return result;
+}
+
+/* Expand a call to the pow built-in mathematical function. Return 0 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_pow (tree exp, rtx target, rtx subtarget)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ tree arg0, arg1;
+
+ if (! validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+ return 0;
+
+ arg0 = TREE_VALUE (arglist);
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+
+ if (flag_unsafe_math_optimizations
+ && ! flag_errno_math
+ && ! optimize_size
+ && TREE_CODE (arg1) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (arg1))
+ {
+ REAL_VALUE_TYPE cint;
+ REAL_VALUE_TYPE c;
+ HOST_WIDE_INT n;
+
+ c = TREE_REAL_CST (arg1);
+ n = real_to_integer (&c);
+ real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
+ if (real_identical (&c, &cint)
+ && powi_cost (n) <= POWI_MAX_MULTS)
+ {
+ enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
+ rtx op = expand_expr (arg0, subtarget, VOIDmode, 0);
+ op = force_reg (mode, op);
+ return expand_powi (op, mode, n);
+ }
+ }
+ return expand_builtin_mathfn_2 (exp, target, NULL_RTX);
+}
+
/* Expand expression EXP which is a call to the strlen builtin. Return 0
if we failed the caller should emit a normal call, otherwise
try to get the result in TARGET, if convenient. */
int align;
/* If the length can be computed at compile-time, return it. */
- len = c_strlen (src);
+ len = c_strlen (src, 0);
if (len)
return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+ /* If the length can be computed at compile-time and is constant
+ integer, but there are side-effects in src, evaluate
+ src for side-effects, then return len.
+ E.g. x = strlen (i++ ? "xfoo" + 1 : "bar");
+ can be optimized into: i++; x = 3; */
+ len = c_strlen (src, 1);
+ if (len && TREE_CODE (len) == INTEGER_CST)
+ {
+ expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+ }
+
align = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
/* If SRC is not a pointer type, don't do this operation inline. */
&& GET_CODE (len_rtx) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
- (PTR) src_str, dest_align))
+ (void *) src_str, dest_align))
{
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
- (PTR) src_str, dest_align, 0);
+ (void *) src_str, dest_align, 0);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (dest_mem) != ptr_mode)
&& GET_CODE (len_rtx) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
- (PTR) src_str, dest_align))
+ (void *) src_str, dest_align))
{
dest_mem = get_memory_rtx (dest);
set_mem_align (dest_mem, dest_align);
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
- (PTR) src_str, dest_align, endp);
+ (void *) src_str, dest_align, endp);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (dest_mem) != ptr_mode)
static rtx
expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode)
{
- tree fn, len;
+ tree fn, len, src, dst;
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
if (!fn)
return 0;
- len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
- if (len == 0)
+ src = TREE_VALUE (TREE_CHAIN (arglist));
+ len = c_strlen (src, 1);
+ if (len == 0 || TREE_SIDE_EFFECTS (len))
return 0;
+ dst = TREE_VALUE (arglist);
len = size_binop (PLUS_EXPR, len, ssize_int (1));
- chainon (arglist, build_tree_list (NULL_TREE, len));
+ arglist = build_tree_list (NULL_TREE, len);
+ arglist = tree_cons (NULL_TREE, src, arglist);
+ arglist = tree_cons (NULL_TREE, dst, arglist);
return expand_expr (build_function_call_expr (fn, arglist),
target, mode, EXPAND_NORMAL);
}
return 0;
else
{
- tree newarglist;
- tree src, len;
+ tree dst, src, len;
/* If return value is ignored, transform stpcpy into strcpy. */
if (target == const0_rtx)
because the latter will potentially produce pessimized code
when used to produce the return value. */
src = TREE_VALUE (TREE_CHAIN (arglist));
- if (! c_getstr (src) || ! (len = c_strlen (src)))
+ if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
return 0;
+ dst = TREE_VALUE (arglist);
len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
- newarglist = copy_list (arglist);
- chainon (newarglist, build_tree_list (NULL_TREE, len));
- return expand_builtin_mempcpy (newarglist, target, mode, /*endp=*/2);
+ arglist = build_tree_list (NULL_TREE, len);
+ arglist = tree_cons (NULL_TREE, src, arglist);
+ arglist = tree_cons (NULL_TREE, dst, arglist);
+ return expand_builtin_mempcpy (arglist, target, mode, /*endp=*/2);
}
}
return 0;
else
{
- tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
+ tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 1);
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
tree fn;
if (!p || dest_align == 0 || !host_integerp (len, 1)
|| !can_store_by_pieces (tree_low_cst (len, 1),
builtin_strncpy_read_str,
- (PTR) p, dest_align))
+ (void *) p, dest_align))
return 0;
dest_mem = get_memory_rtx (dest);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
builtin_strncpy_read_str,
- (PTR) p, dest_align, 0);
+ (void *) p, dest_align, 0);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (dest_mem) != ptr_mode)
c = 1;
if (!can_store_by_pieces (tree_low_cst (len, 1),
builtin_memset_read_str,
- (PTR) &c, dest_align))
+ &c, dest_align))
return 0;
val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val));
dest_mem = get_memory_rtx (dest);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
builtin_memset_gen_str,
- (PTR) val_rtx, dest_align, 0);
+ val_rtx, dest_align, 0);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (dest_mem) != ptr_mode)
if (!host_integerp (len, 1))
return 0;
if (!can_store_by_pieces (tree_low_cst (len, 1),
- builtin_memset_read_str, (PTR) &c,
+ builtin_memset_read_str, &c,
dest_align))
return 0;
dest_mem = get_memory_rtx (dest);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
builtin_memset_read_str,
- (PTR) &c, dest_align, 0);
+ &c, dest_align, 0);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (dest_mem) != ptr_mode)
enum machine_mode insn_mode
= insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
- len1 = c_strlen (arg1);
- len2 = c_strlen (arg2);
+ len1 = c_strlen (arg1, 1);
+ len2 = c_strlen (arg2, 1);
if (len1)
len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
enum machine_mode insn_mode
= insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
- len1 = c_strlen (arg1);
- len2 = c_strlen (arg2);
+ len1 = c_strlen (arg1, 1);
+ len2 = c_strlen (arg2, 1);
if (len1)
len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
/* Get the length of the string passed to fputs. If the length
can't be determined, punt. */
- if (!(len = c_strlen (TREE_VALUE (arglist)))
+ if (!(len = c_strlen (TREE_VALUE (arglist), 1))
|| TREE_CODE (len) != INTEGER_CST)
return 0;
{
tree string_arg;
- /* If optimizing for size keep fputs. */
+ /* If optimizing for size keep fputs. */
if (optimize_size)
return 0;
string_arg = TREE_VALUE (arglist);
rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
- note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
+ note = emit_note (NOTE_INSN_EXPECTED_VALUE);
NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, target, rtx_c);
}
return expand_complex_abs (mode, op0, target, 0);
}
+/* Expand a call to sprintf with argument list ARGLIST. Return 0 if
+ a normal call should be emitted rather than expanding the function
+ inline. If convenient, the result should be placed in TARGET with
+ mode MODE. */
+
+static rtx
+expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
+{
+ tree orig_arglist, dest, fmt;
+ const char *fmt_str;
+
+ orig_arglist = arglist;
+
+ /* Verify the required arguments in the original call. */
+ if (! arglist)
+ return 0;
+ dest = TREE_VALUE (arglist);
+ if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE)
+ return 0;
+ arglist = TREE_CHAIN (arglist);
+ if (! arglist)
+ return 0;
+ fmt = TREE_VALUE (arglist);
+ if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE)
+ return 0;
+ arglist = TREE_CHAIN (arglist);
+
+ /* Check whether the format is a literal string constant. */
+ fmt_str = c_getstr (fmt);
+ if (fmt_str == NULL)
+ return 0;
+
+ /* If the format doesn't contain % args or %%, use strcpy. */
+ if (strchr (fmt_str, '%') == 0)
+ {
+ tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+ tree exp;
+
+ if (arglist || ! fn)
+ return 0;
+ expand_expr (build_function_call_expr (fn, orig_arglist),
+ const0_rtx, VOIDmode, EXPAND_NORMAL);
+ if (target == const0_rtx)
+ return const0_rtx;
+ exp = build_int_2 (strlen (fmt_str), 0);
+ exp = fold (build1 (NOP_EXPR, integer_type_node, exp));
+ return expand_expr (exp, target, mode, EXPAND_NORMAL);
+ }
+ /* If the format is "%s", use strcpy if the result isn't used. */
+ else if (strcmp (fmt_str, "%s") == 0)
+ {
+ tree fn, arg, len;
+ fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+
+ if (! fn)
+ return 0;
+
+ if (! arglist || TREE_CHAIN (arglist))
+ return 0;
+ arg = TREE_VALUE (arglist);
+ if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
+ return 0;
+
+ if (target != const0_rtx)
+ {
+ len = c_strlen (arg, 1);
+ if (! len || TREE_CODE (len) != INTEGER_CST)
+ return 0;
+ }
+ else
+ len = NULL_TREE;
+
+ arglist = build_tree_list (NULL_TREE, arg);
+ arglist = tree_cons (NULL_TREE, dest, arglist);
+ expand_expr (build_function_call_expr (fn, arglist),
+ const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ if (target == const0_rtx)
+ return const0_rtx;
+ return expand_expr (len, target, mode, EXPAND_NORMAL);
+ }
+
+ return 0;
+}
\f
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
case BUILT_IN_BCOPY:
case BUILT_IN_INDEX:
case BUILT_IN_RINDEX:
+ case BUILT_IN_SPRINTF:
case BUILT_IN_STPCPY:
case BUILT_IN_STRCHR:
case BUILT_IN_STRRCHR:
case BUILT_IN_POW:
case BUILT_IN_POWF:
case BUILT_IN_POWL:
+ if (! flag_unsafe_math_optimizations)
+ break;
+ target = expand_builtin_pow (exp, target, subtarget);
+ if (target)
+ return target;
+ break;
+
case BUILT_IN_ATAN2:
case BUILT_IN_ATAN2F:
case BUILT_IN_ATAN2L:
return target;
break;
+ case BUILT_IN_SPRINTF:
+ target = expand_builtin_sprintf (arglist, target, mode);
+ if (target)
+ return target;
+ break;
+
/* Various hooks for the DWARF 2 __throw routine. */
case BUILT_IN_UNWIND_INIT:
expand_builtin_unwind_init ();
case BUILT_IN_STRLEN:
if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
{
- tree len = c_strlen (TREE_VALUE (arglist));
+ tree len = c_strlen (TREE_VALUE (arglist), 0);
if (len)
{
/* Convert from the internal "sizetype" type to "size_t". */