required to implement the function call in all cases. */
tree implicit_built_in_decls[(int) END_BUILTINS];
-static int get_pointer_alignment PARAMS ((tree, unsigned int));
-static tree c_strlen PARAMS ((tree));
-static const char *c_getstr PARAMS ((tree));
-static rtx c_readstr PARAMS ((const char *,
- enum machine_mode));
-static int target_char_cast PARAMS ((tree, char *));
-static rtx get_memory_rtx PARAMS ((tree));
-static int apply_args_size PARAMS ((void));
-static int apply_result_size PARAMS ((void));
+/* Trigonometric and mathematical constants used in builtin folding. */
+static bool builtin_dconsts_init = 0;
+static REAL_VALUE_TYPE dconstpi;
+static REAL_VALUE_TYPE dconste;
+
+static int get_pointer_alignment (tree, unsigned int);
+static tree c_strlen (tree);
+static const char *c_getstr (tree);
+static rtx c_readstr (const char *, enum machine_mode);
+static int target_char_cast (tree, char *);
+static rtx get_memory_rtx (tree);
+static int apply_args_size (void);
+static int apply_result_size (void);
#if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
-static rtx result_vector PARAMS ((int, rtx));
+static rtx result_vector (int, rtx);
#endif
-static rtx expand_builtin_setjmp PARAMS ((tree, rtx));
-static void expand_builtin_prefetch PARAMS ((tree));
-static rtx expand_builtin_apply_args PARAMS ((void));
-static rtx expand_builtin_apply_args_1 PARAMS ((void));
-static rtx expand_builtin_apply PARAMS ((rtx, rtx, rtx));
-static void expand_builtin_return PARAMS ((rtx));
-static enum type_class type_to_class PARAMS ((tree));
-static rtx expand_builtin_classify_type PARAMS ((tree));
-static void expand_errno_check PARAMS ((tree, rtx));
-static rtx expand_builtin_mathfn PARAMS ((tree, rtx, rtx));
-static rtx expand_builtin_mathfn_2 PARAMS ((tree, rtx, rtx));
-static rtx expand_builtin_constant_p PARAMS ((tree));
-static rtx expand_builtin_args_info PARAMS ((tree));
-static rtx expand_builtin_next_arg PARAMS ((tree));
-static rtx expand_builtin_va_start PARAMS ((tree));
-static rtx expand_builtin_va_end PARAMS ((tree));
-static rtx expand_builtin_va_copy PARAMS ((tree));
-static rtx expand_builtin_memcmp PARAMS ((tree, tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_strcmp PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_strncmp PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx builtin_memcpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
- enum machine_mode));
-static rtx expand_builtin_strcat PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_strncat PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_strspn PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_strcspn PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_memcpy PARAMS ((tree, rtx,
- enum machine_mode, int));
-static rtx expand_builtin_strcpy PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_stpcpy PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx builtin_strncpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
- enum machine_mode));
-static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx builtin_memset_read_str PARAMS ((PTR, HOST_WIDE_INT,
- enum machine_mode));
-static rtx builtin_memset_gen_str PARAMS ((PTR, HOST_WIDE_INT,
- enum machine_mode));
-static rtx expand_builtin_memset PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_bzero PARAMS ((tree));
-static rtx expand_builtin_strlen PARAMS ((tree, rtx));
-static rtx expand_builtin_strstr PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_strpbrk PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_strchr PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_strrchr PARAMS ((tree, rtx,
- enum machine_mode));
-static rtx expand_builtin_alloca PARAMS ((tree, rtx));
-static rtx expand_builtin_unop PARAMS ((enum machine_mode,
- tree, rtx, rtx, optab));
-static rtx expand_builtin_frame_address PARAMS ((tree));
-static rtx expand_builtin_fputs PARAMS ((tree, int, int));
-static tree stabilize_va_list PARAMS ((tree, int));
-static rtx expand_builtin_expect PARAMS ((tree, rtx));
-static tree fold_builtin_constant_p PARAMS ((tree));
-static tree fold_builtin_classify_type PARAMS ((tree));
-static tree fold_builtin_inf PARAMS ((tree, int));
-static tree fold_builtin_nan PARAMS ((tree, tree, int));
-static int validate_arglist PARAMS ((tree, ...));
-static tree fold_trunc_transparent_mathfn PARAMS ((tree));
+static rtx expand_builtin_setjmp (tree, rtx);
+static void expand_builtin_prefetch (tree);
+static rtx expand_builtin_apply_args (void);
+static rtx expand_builtin_apply_args_1 (void);
+static rtx expand_builtin_apply (rtx, rtx, rtx);
+static void expand_builtin_return (rtx);
+static enum type_class type_to_class (tree);
+static rtx expand_builtin_classify_type (tree);
+static void expand_errno_check (tree, rtx);
+static rtx expand_builtin_mathfn (tree, rtx, rtx);
+static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
+static rtx expand_builtin_constant_p (tree, enum machine_mode);
+static rtx expand_builtin_args_info (tree);
+static rtx expand_builtin_next_arg (tree);
+static rtx expand_builtin_va_start (tree);
+static rtx expand_builtin_va_end (tree);
+static rtx expand_builtin_va_copy (tree);
+static rtx expand_builtin_memcmp (tree, tree, rtx, enum machine_mode);
+static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
+static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
+static rtx expand_builtin_strcat (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strncat (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strspn (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
+static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
+static rtx expand_builtin_mempcpy (tree, rtx, enum machine_mode, int);
+static rtx expand_builtin_memmove (tree, rtx, enum machine_mode);
+static rtx expand_builtin_bcopy (tree);
+static rtx expand_builtin_strcpy (tree, rtx, enum machine_mode);
+static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
+static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
+static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
+static rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode);
+static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
+static rtx expand_builtin_memset (tree, rtx, enum machine_mode);
+static rtx expand_builtin_bzero (tree);
+static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strstr (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strpbrk (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strchr (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strrchr (tree, rtx, enum machine_mode);
+static rtx expand_builtin_alloca (tree, rtx);
+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 tree stabilize_va_list (tree, int);
+static rtx expand_builtin_expect (tree, rtx);
+static tree fold_builtin_constant_p (tree);
+static tree fold_builtin_classify_type (tree);
+static tree fold_builtin_inf (tree, int);
+static tree fold_builtin_nan (tree, tree, int);
+static int validate_arglist (tree, ...);
+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 void init_builtin_dconsts (void);
+static tree fold_builtin_cabs (tree, tree, tree);
+
+/* Initialize mathematical constants for constant folding builtins.
+ These constants need to be given to at least 160 bits precision. */
+
+static void
+init_builtin_dconsts (void)
+{
+ real_from_string (&dconstpi,
+ "3.1415926535897932384626433832795028841971693993751058209749445923078");
+ real_from_string (&dconste,
+ "2.7182818284590452353602874713526624977572470936999595749669676277241");
+
+ builtin_dconsts_init = true;
+}
/* Return the alignment in bits of EXP, a pointer valued expression.
But don't return more than MAX_ALIGN no matter what.
expression is actually pointing at an object whose alignment is tighter. */
static int
-get_pointer_alignment (exp, max_align)
- tree exp;
- unsigned int max_align;
+get_pointer_alignment (tree exp, unsigned int max_align)
{
unsigned int align, inner;
arrays with initializers, so neither can we do so here. */
static tree
-c_strlen (src)
- tree src;
+c_strlen (tree src)
{
tree offset_node;
HOST_WIDE_INT offset;
or sum of string constant and integer constant. */
static const char *
-c_getstr (src)
- tree src;
+c_getstr (tree src)
{
tree offset_node;
GET_MODE_BITSIZE (MODE) bits from string constant STR. */
static rtx
-c_readstr (str, mode)
- const char *str;
- enum machine_mode mode;
+c_readstr (const char *str, enum machine_mode mode)
{
HOST_WIDE_INT c[2];
HOST_WIDE_INT ch;
P. */
static int
-target_char_cast (cst, p)
- tree cst;
- char *p;
+target_char_cast (tree cst, char *p)
{
unsigned HOST_WIDE_INT val, hostval;
address located within it (depending on FNDECL_CODE). */
rtx
-expand_builtin_return_addr (fndecl_code, count, tem)
- enum built_in_function fndecl_code;
- int count;
- rtx tem;
+expand_builtin_return_addr (enum built_in_function fndecl_code, int count,
+ rtx tem)
{
int i;
handling code. */
void
-expand_builtin_setjmp_setup (buf_addr, receiver_label)
- rtx buf_addr;
- rtx receiver_label;
+expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
{
enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
rtx stack_save;
This is used directly by sjlj exception handling code. */
void
-expand_builtin_setjmp_receiver (receiver_label)
- rtx receiver_label ATTRIBUTE_UNUSED;
+expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
{
/* Clobber the FP when we get here, so we have to make sure it's
marked as used by this function. */
them. */
static rtx
-expand_builtin_setjmp (arglist, target)
- tree arglist;
- rtx target;
+expand_builtin_setjmp (tree arglist, rtx target)
{
rtx buf_addr, next_lab, cont_lab;
them. */
void
-expand_builtin_longjmp (buf_addr, value)
- rtx buf_addr, value;
+expand_builtin_longjmp (rtx buf_addr, rtx value)
{
rtx fp, lab, stack, insn, last;
enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
effects. */
static void
-expand_builtin_prefetch (arglist)
- tree arglist;
+expand_builtin_prefetch (tree arglist)
{
tree arg0, arg1, arg2;
rtx op0, op1, op2;
to be used to be used in a string instruction (cmpstrsi, movstrsi, ..). */
static rtx
-get_memory_rtx (exp)
- tree exp;
+get_memory_rtx (tree exp)
{
rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_SUM);
rtx mem;
needed in objc-act.c. */
int
-apply_args_register_offset (regno)
- int regno;
+apply_args_register_offset (int regno)
{
apply_args_size ();
and initialize apply_args_mode. */
static int
-apply_args_size ()
+apply_args_size (void)
{
static int size = -1;
int align;
and initialize apply_result_mode. */
static int
-apply_result_size ()
+apply_result_size (void)
{
static int size = -1;
int align, regno;
restore the values. */
static rtx
-result_vector (savep, result)
- int savep;
- rtx result;
+result_vector (int savep, rtx result)
{
int regno, size, align, nelts;
enum machine_mode mode;
arguments as were passed to the current function. */
static rtx
-expand_builtin_apply_args_1 ()
+expand_builtin_apply_args_1 (void)
{
rtx registers;
int size, align, regno;
saved. */
static rtx
-expand_builtin_apply_args ()
+expand_builtin_apply_args (void)
{
/* Don't do __builtin_apply_args more than once in a function.
Save the result of the first call and reuse it. */
untyped return of whatever value was returned by the given function. */
static rtx
-expand_builtin_apply (function, arguments, argsize)
- rtx function, arguments, argsize;
+expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
{
int size, align, regno;
enum machine_mode mode;
#endif
abort ();
- /* Find the CALL insn we just emitted. */
- for (call_insn = get_last_insn ();
- call_insn && GET_CODE (call_insn) != CALL_INSN;
- call_insn = PREV_INSN (call_insn))
- ;
-
- if (! call_insn)
- abort ();
-
- /* Put the register usage information on the CALL. If there is already
- some usage information, put ours at the end. */
- if (CALL_INSN_FUNCTION_USAGE (call_insn))
- {
- rtx link;
-
- for (link = CALL_INSN_FUNCTION_USAGE (call_insn); XEXP (link, 1) != 0;
- link = XEXP (link, 1))
- ;
-
- XEXP (link, 1) = call_fusage;
- }
- else
- CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
+ /* Find the CALL insn we just emitted, and attach the register usage
+ information. */
+ call_insn = last_call_insn ();
+ add_function_usage_to (call_insn, call_fusage);
/* Restore the stack. */
#ifdef HAVE_save_stack_nonlocal
/* Perform an untyped return. */
static void
-expand_builtin_return (result)
- rtx result;
+expand_builtin_return (rtx result)
{
int size, align, regno;
enum machine_mode mode;
/* Used by expand_builtin_classify_type and fold_builtin_classify_type. */
static enum type_class
-type_to_class (type)
- tree type;
+type_to_class (tree type)
{
switch (TREE_CODE (type))
{
ARGLIST. */
static rtx
-expand_builtin_classify_type (arglist)
- tree arglist;
+expand_builtin_classify_type (tree arglist)
{
if (arglist != 0)
return GEN_INT (type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
/* Expand expression EXP, which is a call to __builtin_constant_p. */
static rtx
-expand_builtin_constant_p (exp)
- tree exp;
+expand_builtin_constant_p (tree arglist, enum machine_mode target_mode)
{
- tree arglist = TREE_OPERAND (exp, 1);
- enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
rtx tmp;
if (arglist == 0)
current_function_calls_constant_p = 1;
tmp = expand_expr (arglist, NULL_RTX, VOIDmode, 0);
- tmp = gen_rtx_CONSTANT_P_RTX (value_mode, tmp);
+ tmp = gen_rtx_CONSTANT_P_RTX (target_mode, tmp);
return tmp;
}
/* Return mathematic function equivalent to FN but operating directly on TYPE,
if available. */
tree
-mathfn_built_in (type, fn)
- tree type;
- enum built_in_function fn;
+mathfn_built_in (tree type, enum built_in_function fn)
{
enum built_in_function fcode = NOT_BUILT_IN;
if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
case BUILT_IN_LOGL:
fcode = BUILT_IN_LOG;
break;
+ case BUILT_IN_TAN:
+ case BUILT_IN_TANF:
+ case BUILT_IN_TANL:
+ fcode = BUILT_IN_TAN;
+ break;
+ case BUILT_IN_ATAN:
+ case BUILT_IN_ATANF:
+ case BUILT_IN_ATANL:
+ fcode = BUILT_IN_ATAN;
+ break;
case BUILT_IN_FLOOR:
case BUILT_IN_FLOORF:
case BUILT_IN_FLOORL:
case BUILT_IN_LOGL:
fcode = BUILT_IN_LOGF;
break;
+ case BUILT_IN_TAN:
+ case BUILT_IN_TANF:
+ case BUILT_IN_TANL:
+ fcode = BUILT_IN_TANF;
+ break;
+ case BUILT_IN_ATAN:
+ case BUILT_IN_ATANF:
+ case BUILT_IN_ATANL:
+ fcode = BUILT_IN_ATANF;
+ break;
case BUILT_IN_FLOOR:
case BUILT_IN_FLOORF:
case BUILT_IN_FLOORL:
case BUILT_IN_LOGL:
fcode = BUILT_IN_LOGL;
break;
+ case BUILT_IN_TAN:
+ case BUILT_IN_TANF:
+ case BUILT_IN_TANL:
+ fcode = BUILT_IN_TANL;
+ break;
+ case BUILT_IN_ATAN:
+ case BUILT_IN_ATANF:
+ case BUILT_IN_ATANL:
+ fcode = BUILT_IN_ATANL;
+ break;
case BUILT_IN_FLOOR:
case BUILT_IN_FLOORF:
case BUILT_IN_FLOORL:
errno to EDOM. */
static void
-expand_errno_check (exp, target)
- tree exp;
- rtx target;
+expand_errno_check (tree exp, rtx target)
{
rtx lab;
SUBTARGET may be used as the target for computing one of EXP's operands. */
static rtx
-expand_builtin_mathfn (exp, target, subtarget)
- tree exp;
- rtx target, subtarget;
+expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
{
optab builtin_optab;
rtx op0, insns;
operands. */
static rtx
-expand_builtin_mathfn_2 (exp, target, subtarget)
- tree exp;
- rtx target, subtarget;
+expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
{
optab builtin_optab;
rtx op0, op1, insns;
try to get the result in TARGET, if convenient. */
static rtx
-expand_builtin_strlen (exp, target)
- tree exp;
- rtx target;
+expand_builtin_strlen (tree arglist, rtx target,
+ enum machine_mode target_mode)
{
- tree arglist = TREE_OPERAND (exp, 1);
- enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
-
if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
return 0;
else
{
rtx pat;
- tree src = TREE_VALUE (arglist);
-
- int align
- = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-
+ tree len, src = TREE_VALUE (arglist);
rtx result, src_reg, char_rtx, before_strlen;
- enum machine_mode insn_mode = value_mode, char_mode;
+ enum machine_mode insn_mode = target_mode, char_mode;
enum insn_code icode = CODE_FOR_nothing;
+ int align;
+
+ /* If the length can be computed at compile-time, return it. */
+ len = c_strlen (src);
+ if (len)
+ 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. */
if (align == 0)
emit_insn_before (pat, get_insns ());
/* Return the value in the proper mode for this function. */
- if (GET_MODE (result) == value_mode)
+ if (GET_MODE (result) == target_mode)
target = result;
else if (target != 0)
convert_move (target, result, 0);
else
- target = convert_to_mode (value_mode, result, 0);
+ target = convert_to_mode (target_mode, result, 0);
return target;
}
in TARGET, if convenient (and in mode MODE if that's convenient). */
static rtx
-expand_builtin_strstr (arglist, target, mode)
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strstr (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
in TARGET, if convenient (and in mode MODE if that's convenient). */
static rtx
-expand_builtin_strchr (arglist, target, mode)
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strchr (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
return 0;
in TARGET, if convenient (and in mode MODE if that's convenient). */
static rtx
-expand_builtin_strrchr (arglist, target, mode)
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strrchr (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
return 0;
in TARGET, if convenient (and in mode MODE if that's convenient). */
static rtx
-expand_builtin_strpbrk (arglist, target, mode)
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strpbrk (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
constant. */
static rtx
-builtin_memcpy_read_str (data, offset, mode)
- PTR data;
- HOST_WIDE_INT offset;
- enum machine_mode mode;
+builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset,
+ enum machine_mode mode)
{
const char *str = (const char *) data;
/* Expand a call to the memcpy builtin, with arguments in ARGLIST.
Return 0 if we failed, the caller should emit a normal call,
otherwise try to get the result in TARGET, if convenient (and in
- mode MODE if that's convenient). If ENDP is 0 return the
- destination pointer, if ENDP is 1 return the end pointer ala
- mempcpy, and if ENDP is 2 return the end pointer minus one ala
- stpcpy. */
+ mode MODE if that's convenient). */
static rtx
-expand_builtin_memcpy (arglist, target, mode, endp)
- tree arglist;
- rtx target;
- enum machine_mode mode;
- int endp;
+expand_builtin_memcpy (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
tree src = TREE_VALUE (TREE_CHAIN (arglist));
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
const char *src_str;
-
unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
unsigned int dest_align
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
(PTR) src_str, dest_align))
{
- store_by_pieces (dest_mem, INTVAL (len_rtx),
- builtin_memcpy_read_str,
- (PTR) src_str, dest_align);
+ dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
+ builtin_memcpy_read_str,
+ (PTR) 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)
dest_mem = convert_memory_address (ptr_mode, dest_mem);
#endif
- if (endp)
- {
- rtx result = gen_rtx_PLUS (GET_MODE (dest_mem), dest_mem, len_rtx);
- if (endp == 2)
- result = simplify_gen_binary (MINUS, GET_MODE (result), result, const1_rtx);
- return result;
- }
- else
- return dest_mem;
+ return dest_mem;
}
src_mem = get_memory_rtx (src);
dest_addr = convert_memory_address (ptr_mode, dest_addr);
#endif
}
+ return dest_addr;
+ }
+}
- if (endp)
- {
- rtx result = gen_rtx_PLUS (GET_MODE (dest_addr), dest_addr, len_rtx);
- if (endp == 2)
- result = simplify_gen_binary (MINUS, GET_MODE (result), result, const1_rtx);
- return result;
+/* Expand a call to the mempcpy builtin, with arguments in ARGLIST.
+ Return 0 if we failed the caller should emit a normal call,
+ otherwise try to get the result in TARGET, if convenient (and in
+ mode MODE if that's convenient). If ENDP is 0 return the
+ destination pointer, if ENDP is 1 return the end pointer ala
+ mempcpy, and if ENDP is 2 return the end pointer minus one ala
+ stpcpy. */
+
+static rtx
+expand_builtin_mempcpy (tree arglist, rtx target, enum machine_mode mode,
+ int endp)
+{
+ if (!validate_arglist (arglist,
+ POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ return 0;
+ /* If return value is ignored, transform mempcpy into memcpy. */
+ else if (target == const0_rtx)
+ {
+ tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+
+ if (!fn)
+ return 0;
+
+ return expand_expr (build_function_call_expr (fn, arglist),
+ target, mode, EXPAND_NORMAL);
+ }
+ else
+ {
+ tree dest = TREE_VALUE (arglist);
+ tree src = TREE_VALUE (TREE_CHAIN (arglist));
+ tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ const char *src_str;
+ unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+ unsigned int dest_align
+ = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+ rtx dest_mem, src_mem, len_rtx;
+
+ /* If DEST is not a pointer type or LEN is not constant,
+ call the normal function. */
+ if (dest_align == 0 || !host_integerp (len, 1))
+ return 0;
+
+ /* If the LEN parameter is zero, return DEST. */
+ if (tree_low_cst (len, 1) == 0)
+ {
+ /* Evaluate and ignore SRC in case it has side-effects. */
+ expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ return expand_expr (dest, target, mode, EXPAND_NORMAL);
}
- else
- return dest_addr;
+
+ /* If either SRC is not a pointer type, don't do this
+ operation in-line. */
+ if (src_align == 0)
+ return 0;
+
+ len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+ src_str = c_getstr (src);
+
+ /* If SRC is a string constant and block move would be done
+ by pieces, we can avoid loading the string from memory
+ and only stored the computed constants. */
+ if (src_str
+ && 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))
+ {
+ 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);
+ dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+ if (GET_MODE (dest_mem) != ptr_mode)
+ dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+ return dest_mem;
+ }
+
+ if (GET_CODE (len_rtx) == CONST_INT
+ && can_move_by_pieces (INTVAL (len_rtx),
+ MIN (dest_align, src_align)))
+ {
+ dest_mem = get_memory_rtx (dest);
+ set_mem_align (dest_mem, dest_align);
+ src_mem = get_memory_rtx (src);
+ set_mem_align (src_mem, src_align);
+ dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx),
+ MIN (dest_align, src_align), endp);
+ dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+ if (GET_MODE (dest_mem) != ptr_mode)
+ dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+ return dest_mem;
+ }
+
+ return 0;
}
}
+/* Expand expression EXP, which is a call to the memmove builtin. Return 0
+ if we failed the caller should emit a normal call. */
+
+static rtx
+expand_builtin_memmove (tree arglist, rtx target, enum machine_mode mode)
+{
+ if (!validate_arglist (arglist,
+ POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ return 0;
+ else
+ {
+ tree dest = TREE_VALUE (arglist);
+ tree src = TREE_VALUE (TREE_CHAIN (arglist));
+ tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+ unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+ unsigned int dest_align
+ = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+
+ /* If DEST is not a pointer type, call the normal function. */
+ if (dest_align == 0)
+ return 0;
+
+ /* If the LEN parameter is zero, return DEST. */
+ if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
+ {
+ /* Evaluate and ignore SRC in case it has side-effects. */
+ expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ return expand_expr (dest, target, mode, EXPAND_NORMAL);
+ }
+
+ /* If either SRC is not a pointer type, don't do this
+ operation in-line. */
+ if (src_align == 0)
+ return 0;
+
+ /* If src is categorized for a readonly section we can use
+ normal memcpy. */
+ if (readonly_data_expr (src))
+ {
+ tree const fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ if (!fn)
+ return 0;
+ return expand_expr (build_function_call_expr (fn, arglist),
+ target, mode, EXPAND_NORMAL);
+ }
+
+ /* Otherwise, call the normal function. */
+ return 0;
+ }
+}
+
+/* Expand expression EXP, which is a call to the bcopy builtin. Return 0
+ if we failed the caller should emit a normal call. */
+
+static rtx
+expand_builtin_bcopy (tree arglist)
+{
+ tree src, dest, size, newarglist;
+
+ if (!validate_arglist (arglist,
+ POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ src = TREE_VALUE (arglist);
+ dest = TREE_VALUE (TREE_CHAIN (arglist));
+ size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+ /* New argument list transforming bcopy(ptr x, ptr y, int z) to
+ memmove(ptr y, ptr x, size_t z). This is done this way
+ so that if it isn't expanded inline, we fallback to
+ calling bcopy instead of memmove. */
+
+ newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
+ newarglist = tree_cons (NULL_TREE, src, newarglist);
+ newarglist = tree_cons (NULL_TREE, dest, newarglist);
+
+ return expand_builtin_memmove (newarglist, const0_rtx, VOIDmode);
+}
+
/* Expand expression EXP, which is a call to the strcpy builtin. Return 0
if we failed the caller should emit a normal call, otherwise try to get
the result in TARGET, if convenient (and in mode MODE if that's
convenient). */
static rtx
-expand_builtin_strcpy (exp, target, mode)
- tree exp;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode)
{
- tree arglist = TREE_OPERAND (exp, 1);
tree fn, len;
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
mode MODE if that's convenient). */
static rtx
-expand_builtin_stpcpy (arglist, target, mode)
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
else
{
- tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
- if (len == 0)
+ tree newarglist;
+ tree src, len;
+
+ /* If return value is ignored, transform stpcpy into strcpy. */
+ if (target == const0_rtx)
+ {
+ tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+ if (!fn)
+ return 0;
+
+ return expand_expr (build_function_call_expr (fn, arglist),
+ target, mode, EXPAND_NORMAL);
+ }
+
+ /* Ensure we get an actual string whose length can be evaluated at
+ compile-time, not an expression containing a string. This is
+ 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)))
return 0;
len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
- chainon (arglist, build_tree_list (NULL_TREE, len));
- return expand_builtin_memcpy (arglist, target, mode, /*endp=*/2);
+ newarglist = copy_list (arglist);
+ chainon (newarglist, build_tree_list (NULL_TREE, len));
+ return expand_builtin_mempcpy (newarglist, target, mode, /*endp=*/2);
}
}
constant. */
static rtx
-builtin_strncpy_read_str (data, offset, mode)
- PTR data;
- HOST_WIDE_INT offset;
- enum machine_mode mode;
+builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset,
+ enum machine_mode mode)
{
const char *str = (const char *) data;
if we failed the caller should emit a normal call. */
static rtx
-expand_builtin_strncpy (arglist, target, mode)
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strncpy (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
dest_mem = get_memory_rtx (dest);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
builtin_strncpy_read_str,
- (PTR) p, dest_align);
+ (PTR) 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)
constant. */
static rtx
-builtin_memset_read_str (data, offset, mode)
- PTR data;
- HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
- enum machine_mode mode;
+builtin_memset_read_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
{
const char *c = (const char *) data;
char *p = alloca (GET_MODE_SIZE (mode));
4 bytes wide, return the RTL for 0x01010101*data. */
static rtx
-builtin_memset_gen_str (data, offset, mode)
- PTR data;
- HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
- enum machine_mode mode;
+builtin_memset_gen_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
{
rtx target, coeff;
size_t size;
convenient). */
static rtx
-expand_builtin_memset (exp, target, mode)
- tree exp;
- rtx target;
- enum machine_mode mode;
+expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode)
{
- tree arglist = TREE_OPERAND (exp, 1);
-
if (!validate_arglist (arglist,
POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
return 0;
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);
+ (PTR) 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)
dest_mem = get_memory_rtx (dest);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
builtin_memset_read_str,
- (PTR) &c, dest_align);
+ (PTR) &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)
if we failed the caller should emit a normal call. */
static rtx
-expand_builtin_bzero (exp)
- tree exp;
+expand_builtin_bzero (tree arglist)
{
- tree arglist = TREE_OPERAND (exp, 1);
tree dest, size, newarglist;
- rtx result;
if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
return NULL_RTX;
newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
newarglist = tree_cons (NULL_TREE, dest, newarglist);
- TREE_OPERAND (exp, 1) = newarglist;
- result = expand_builtin_memset (exp, const0_rtx, VOIDmode);
-
- /* Always restore the original arguments. */
- TREE_OPERAND (exp, 1) = arglist;
-
- return result;
+ return expand_builtin_memset (newarglist, const0_rtx, VOIDmode);
}
-/* Expand expression EXP, which is a call to the memcmp or the strcmp builtin.
+/* Expand expression EXP, which is a call to the memcmp built-in function.
ARGLIST is the argument list for this call. Return 0 if we failed and the
caller should emit a normal call, otherwise try to get the result in
TARGET, if convenient (and in mode MODE, if that's convenient). */
static rtx
-expand_builtin_memcmp (exp, arglist, target, mode)
- tree exp ATTRIBUTE_UNUSED;
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
+ enum machine_mode mode)
{
tree arg1, arg2, len;
const char *p1, *p2;
the result in TARGET, if convenient. */
static rtx
-expand_builtin_strcmp (exp, target, mode)
- tree exp;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
{
tree arglist = TREE_OPERAND (exp, 1);
- tree arg1, arg2, len, len2, fn;
+ tree arg1, arg2;
const char *p1, *p2;
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
- len = c_strlen (arg1);
- len2 = c_strlen (arg2);
+#ifdef HAVE_cmpstrsi
+ if (HAVE_cmpstrsi)
+ {
+ tree len, len1, len2;
+ rtx arg1_rtx, arg2_rtx, arg3_rtx;
+ rtx result, insn;
- if (len)
- len = size_binop (PLUS_EXPR, ssize_int (1), len);
+ int arg1_align
+ = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+ int arg2_align
+ = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+ enum machine_mode insn_mode
+ = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
- if (len2)
- len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
+ len1 = c_strlen (arg1);
+ len2 = c_strlen (arg2);
+
+ if (len1)
+ len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
+ if (len2)
+ len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
+
+ /* If we don't have a constant length for the first, use the length
+ of the second, if we know it. We don't require a constant for
+ this case; some cost analysis could be done if both are available
+ but neither is constant. For now, assume they're equally cheap,
+ unless one has side effects. If both strings have constant lengths,
+ use the smaller. */
+
+ if (!len1)
+ len = len2;
+ else if (!len2)
+ len = len1;
+ else if (TREE_SIDE_EFFECTS (len1))
+ len = len2;
+ else if (TREE_SIDE_EFFECTS (len2))
+ len = len1;
+ else if (TREE_CODE (len1) != INTEGER_CST)
+ len = len2;
+ else if (TREE_CODE (len2) != INTEGER_CST)
+ len = len1;
+ else if (tree_int_cst_lt (len1, len2))
+ len = len1;
+ else
+ len = len2;
- /* If we don't have a constant length for the first, use the length
- of the second, if we know it. We don't require a constant for
- this case; some cost analysis could be done if both are available
- but neither is constant. For now, assume they're equally cheap
- unless one has side effects.
+ /* If both arguments have side effects, we cannot optimize. */
+ if (!len || TREE_SIDE_EFFECTS (len))
+ return 0;
- If both strings have constant lengths, use the smaller. This
- could arise if optimization results in strcpy being called with
- two fixed strings, or if the code was machine-generated. We should
- add some code to the `memcmp' handler below to deal with such
- situations, someday. */
+ /* If we don't have POINTER_TYPE, call the function. */
+ if (arg1_align == 0 || arg2_align == 0)
+ return 0;
- if (!len || TREE_CODE (len) != INTEGER_CST)
- {
- if (len2 && !TREE_SIDE_EFFECTS (len2))
- len = len2;
- else if (len == 0)
- return 0;
- }
- else if (len2 && TREE_CODE (len2) == INTEGER_CST
- && tree_int_cst_lt (len2, len))
- len = len2;
+ /* Make a place to write the result of the instruction. */
+ result = target;
+ if (! (result != 0
+ && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
+ && REGNO (result) >= FIRST_PSEUDO_REGISTER))
+ result = gen_reg_rtx (insn_mode);
- /* If both arguments have side effects, we cannot optimize. */
- if (TREE_SIDE_EFFECTS (len))
- return 0;
+ arg1_rtx = get_memory_rtx (arg1);
+ arg2_rtx = get_memory_rtx (arg2);
+ arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+ insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
+ GEN_INT (MIN (arg1_align, arg2_align)));
+ if (!insn)
+ return 0;
- fn = implicit_built_in_decls[BUILT_IN_MEMCMP];
- if (!fn)
- return 0;
+ emit_insn (insn);
- chainon (arglist, build_tree_list (NULL_TREE, len));
- return expand_expr (build_function_call_expr (fn, arglist),
- target, mode, EXPAND_NORMAL);
+ /* Return the value in the proper mode for this function. */
+ mode = TYPE_MODE (TREE_TYPE (exp));
+ if (GET_MODE (result) == mode)
+ return result;
+ if (target == 0)
+ return convert_to_mode (mode, result, 0);
+ convert_move (target, result, 0);
+ return target;
+ }
+#endif
+ return 0;
}
/* Expand expression EXP, which is a call to the strncmp builtin. Return 0
the result in TARGET, if convenient. */
static rtx
-expand_builtin_strncmp (exp, target, mode)
- tree exp;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
{
tree arglist = TREE_OPERAND (exp, 1);
- tree fn, newarglist, len = 0;
tree arg1, arg2, arg3;
const char *p1, *p2;
}
/* If c_strlen can determine an expression for one of the string
- lengths, and it doesn't have side effects, then call
- expand_builtin_memcmp() using length MIN(strlen(string)+1, arg3). */
-
- /* Perhaps one of the strings is really constant, if so prefer
- that constant length over the other string's length. */
- if (p1)
- len = c_strlen (arg1);
- else if (p2)
- len = c_strlen (arg2);
-
- /* If we still don't have a len, try either string arg as long
- as they don't have side effects. */
- if (!len && !TREE_SIDE_EFFECTS (arg1))
- len = c_strlen (arg1);
- if (!len && !TREE_SIDE_EFFECTS (arg2))
- len = c_strlen (arg2);
- /* If we still don't have a length, punt. */
- if (!len)
- return 0;
+ lengths, and it doesn't have side effects, then emit cmpstrsi
+ using length MIN(strlen(string)+1, arg3). */
+#ifdef HAVE_cmpstrsi
+ if (HAVE_cmpstrsi)
+ {
+ tree len, len1, len2;
+ rtx arg1_rtx, arg2_rtx, arg3_rtx;
+ rtx result, insn;
- fn = implicit_built_in_decls[BUILT_IN_MEMCMP];
- if (!fn)
- return 0;
+ int arg1_align
+ = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+ int arg2_align
+ = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+ enum machine_mode insn_mode
+ = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
- /* Add one to the string length. */
- len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
+ len1 = c_strlen (arg1);
+ len2 = c_strlen (arg2);
+
+ if (len1)
+ len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
+ if (len2)
+ len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
+
+ /* If we don't have a constant length for the first, use the length
+ of the second, if we know it. We don't require a constant for
+ this case; some cost analysis could be done if both are available
+ but neither is constant. For now, assume they're equally cheap,
+ unless one has side effects. If both strings have constant lengths,
+ use the smaller. */
+
+ if (!len1)
+ len = len2;
+ else if (!len2)
+ len = len1;
+ else if (TREE_SIDE_EFFECTS (len1))
+ len = len2;
+ else if (TREE_SIDE_EFFECTS (len2))
+ len = len1;
+ else if (TREE_CODE (len1) != INTEGER_CST)
+ len = len2;
+ else if (TREE_CODE (len2) != INTEGER_CST)
+ len = len1;
+ else if (tree_int_cst_lt (len1, len2))
+ len = len1;
+ else
+ len = len2;
- /* The actual new length parameter is MIN(len,arg3). */
- len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
+ /* If both arguments have side effects, we cannot optimize. */
+ if (!len || TREE_SIDE_EFFECTS (len))
+ return 0;
- newarglist = build_tree_list (NULL_TREE, len);
- newarglist = tree_cons (NULL_TREE, arg2, newarglist);
- newarglist = tree_cons (NULL_TREE, arg1, newarglist);
- return expand_expr (build_function_call_expr (fn, newarglist),
- target, mode, EXPAND_NORMAL);
+ /* The actual new length parameter is MIN(len,arg3). */
+ len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
+
+ /* If we don't have POINTER_TYPE, call the function. */
+ if (arg1_align == 0 || arg2_align == 0)
+ return 0;
+
+ /* Make a place to write the result of the instruction. */
+ result = target;
+ if (! (result != 0
+ && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
+ && REGNO (result) >= FIRST_PSEUDO_REGISTER))
+ result = gen_reg_rtx (insn_mode);
+
+ arg1_rtx = get_memory_rtx (arg1);
+ arg2_rtx = get_memory_rtx (arg2);
+ arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+ insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
+ GEN_INT (MIN (arg1_align, arg2_align)));
+ if (!insn)
+ return 0;
+
+ emit_insn (insn);
+
+ /* Return the value in the proper mode for this function. */
+ mode = TYPE_MODE (TREE_TYPE (exp));
+ if (GET_MODE (result) == mode)
+ return result;
+ if (target == 0)
+ return convert_to_mode (mode, result, 0);
+ convert_move (target, result, 0);
+ return target;
+ }
+#endif
+ return 0;
}
/* Expand expression EXP, which is a call to the strcat builtin.
otherwise try to get the result in TARGET, if convenient. */
static rtx
-expand_builtin_strcat (arglist, target, mode)
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strcat (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
otherwise try to get the result in TARGET, if convenient. */
static rtx
-expand_builtin_strncat (arglist, target, mode)
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strncat (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
otherwise try to get the result in TARGET, if convenient. */
static rtx
-expand_builtin_strspn (arglist, target, mode)
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strspn (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
otherwise try to get the result in TARGET, if convenient. */
static rtx
-expand_builtin_strcspn (arglist, target, mode)
- tree arglist;
- rtx target;
- enum machine_mode mode;
+expand_builtin_strcspn (tree arglist, rtx target, enum machine_mode mode)
{
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
if that's convenient. */
rtx
-expand_builtin_saveregs ()
+expand_builtin_saveregs (void)
{
rtx val, seq;
is controlled by the definition of CUMULATIVE_ARGS. */
static rtx
-expand_builtin_args_info (exp)
- tree exp;
+expand_builtin_args_info (tree arglist)
{
- tree arglist = TREE_OPERAND (exp, 1);
int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
int *word_ptr = (int *) ¤t_function_args_info;
/* Expand ARGLIST, from a call to __builtin_next_arg. */
static rtx
-expand_builtin_next_arg (arglist)
- tree arglist;
+expand_builtin_next_arg (tree arglist)
{
tree fntype = TREE_TYPE (current_function_decl);
from multiple evaluations. */
static tree
-stabilize_va_list (valist, needs_lvalue)
- tree valist;
- int needs_lvalue;
+stabilize_va_list (tree valist, int needs_lvalue)
{
if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
{
the variable. */
void
-std_expand_builtin_va_start (valist, nextarg)
- tree valist;
- rtx nextarg;
+std_expand_builtin_va_start (tree valist, rtx nextarg)
{
tree t;
/* Expand ARGLIST, from a call to __builtin_va_start. */
static rtx
-expand_builtin_va_start (arglist)
- tree arglist;
+expand_builtin_va_start (tree arglist)
{
rtx nextarg;
tree chain, valist;
current (padded) address and increment by the (padded) size. */
rtx
-std_expand_builtin_va_arg (valist, type)
- tree valist, type;
+std_expand_builtin_va_arg (tree valist, tree type)
{
tree addr_tree, t, type_size = NULL;
tree align, alignm1;
a very special sort of operator. */
rtx
-expand_builtin_va_arg (valist, type)
- tree valist, type;
+expand_builtin_va_arg (tree valist, tree type)
{
rtx addr, result;
tree promoted_type, want_va_type, have_va_type;
/* Expand ARGLIST, from a call to __builtin_va_end. */
static rtx
-expand_builtin_va_end (arglist)
- tree arglist;
+expand_builtin_va_end (tree arglist)
{
tree valist = TREE_VALUE (arglist);
nastiness of array-type va_list types. */
static rtx
-expand_builtin_va_copy (arglist)
- tree arglist;
+expand_builtin_va_copy (tree arglist)
{
tree dst, src, t;
__builtin_return_address. */
static rtx
-expand_builtin_frame_address (exp)
- tree exp;
+expand_builtin_frame_address (tree fndecl, tree arglist)
{
- tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
- tree arglist = TREE_OPERAND (exp, 1);
-
/* The argument must be a nonnegative integer constant.
It counts the number of frames to scan up the stack.
The value is the return address saved in that frame. */
the result in TARGET, if convenient. */
static rtx
-expand_builtin_alloca (arglist, target)
- tree arglist;
- rtx target;
+expand_builtin_alloca (tree arglist, rtx target)
{
rtx op0;
rtx result;
SUBTARGET may be used as the target for computing one of EXP's operands. */
static rtx
-expand_builtin_unop (target_mode, arglist, target, subtarget, op_optab)
- enum machine_mode target_mode;
- tree arglist;
- rtx target, subtarget;
- optab op_optab;
+expand_builtin_unop (enum machine_mode target_mode, tree arglist, rtx target,
+ rtx subtarget, optab op_optab)
{
rtx op0;
if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
long, we attempt to transform this call into __builtin_fputc(). */
static rtx
-expand_builtin_fputs (arglist, ignore, unlocked)
- tree arglist;
- int ignore;
- int unlocked;
+expand_builtin_fputs (tree arglist, int ignore, int unlocked)
{
tree len, fn;
tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
a non-jump context. */
static rtx
-expand_builtin_expect (arglist, target)
- tree arglist;
- rtx target;
+expand_builtin_expect (tree arglist, rtx target)
{
tree exp, c;
rtx note, rtx_c;
based on the test being 0/1. */
rtx
-expand_builtin_expect_jump (exp, if_false_label, if_true_label)
- tree exp;
- rtx if_false_label;
- rtx if_true_label;
+expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label)
{
tree arglist = TREE_OPERAND (exp, 1);
tree arg0 = TREE_VALUE (arglist);
while (insn != NULL_RTX)
{
rtx next = NEXT_INSN (insn);
- rtx pattern;
- if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)
- && (pattern = pc_set (insn)) != NULL_RTX)
+ if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn))
{
- rtx ifelse = SET_SRC (pattern);
+ rtx ifelse = SET_SRC (pc_set (insn));
rtx label;
int taken;
- if (GET_CODE (ifelse) != IF_THEN_ELSE)
- goto do_next_insn;
-
if (GET_CODE (XEXP (ifelse, 1)) == LABEL_REF)
{
taken = 1;
}
void
-expand_builtin_trap ()
+expand_builtin_trap (void)
{
#ifdef HAVE_trap
if (HAVE_trap)
emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
emit_barrier ();
}
+
+/* Expand a call to fabs, fabsf or fabsl with arguments 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. SUBTARGET may be used as the target for computing
+ the operand. */
+
+static rtx
+expand_builtin_fabs (tree arglist, rtx target, rtx subtarget)
+{
+ enum machine_mode mode;
+ tree arg;
+ rtx op0;
+
+ if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ return 0;
+
+ arg = TREE_VALUE (arglist);
+ mode = TYPE_MODE (TREE_TYPE (arg));
+ op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+ return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
+}
+
+/* Expand a call to cabs, cabsf or cabsl with arguments 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. */
+
+static rtx
+expand_builtin_cabs (tree arglist, rtx target)
+{
+ enum machine_mode mode;
+ tree arg;
+ rtx op0;
+
+ if (arglist == 0 || TREE_CHAIN (arglist))
+ return 0;
+ arg = TREE_VALUE (arglist);
+ if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
+ || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
+ return 0;
+
+ mode = TYPE_MODE (TREE_TYPE (arg));
+ op0 = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+ return expand_complex_abs (mode, op0, target, 0);
+}
+
\f
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
IGNORE is nonzero if the value is to be ignored. */
rtx
-expand_builtin (exp, target, subtarget, mode, ignore)
- tree exp;
- rtx target;
- rtx subtarget;
- enum machine_mode mode;
- int ignore;
+expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
+ int ignore)
{
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
case BUILT_IN_LOG:
case BUILT_IN_LOGF:
case BUILT_IN_LOGL:
+ case BUILT_IN_TAN:
+ case BUILT_IN_TANF:
+ case BUILT_IN_TANL:
+ case BUILT_IN_ATAN:
+ case BUILT_IN_ATANF:
+ case BUILT_IN_ATANL:
case BUILT_IN_POW:
case BUILT_IN_POWF:
case BUILT_IN_POWL:
case BUILT_IN_MEMCPY:
case BUILT_IN_MEMCMP:
case BUILT_IN_MEMPCPY:
+ case BUILT_IN_MEMMOVE:
case BUILT_IN_BCMP:
case BUILT_IN_BZERO:
+ case BUILT_IN_BCOPY:
case BUILT_IN_INDEX:
case BUILT_IN_RINDEX:
case BUILT_IN_STPCPY:
break;
}
+ /* The built-in function expanders test for target == const0_rtx
+ to determine whether the function's result will be ignored. */
+ if (ignore)
+ target = const0_rtx;
+
+ /* If the result of a pure or const built-in function is ignored, and
+ none of its arguments are volatile, we can avoid expanding the
+ built-in call and just evaluate the arguments for side-effects. */
+ if (target == const0_rtx
+ && (DECL_IS_PURE (fndecl) || TREE_READONLY (fndecl)))
+ {
+ bool volatilep = false;
+ tree arg;
+
+ for (arg = arglist; arg; arg = TREE_CHAIN (arg))
+ if (TREE_THIS_VOLATILE (TREE_VALUE (arg)))
+ {
+ volatilep = true;
+ break;
+ }
+
+ if (! volatilep)
+ {
+ for (arg = arglist; arg; arg = TREE_CHAIN (arg))
+ expand_expr (TREE_VALUE (arg), const0_rtx,
+ VOIDmode, EXPAND_NORMAL);
+ return const0_rtx;
+ }
+ }
+
switch (fcode)
{
case BUILT_IN_ABS:
case BUILT_IN_LABS:
case BUILT_IN_LLABS:
case BUILT_IN_IMAXABS:
+ /* build_function_call changes these into ABS_EXPR. */
+ abort ();
+
case BUILT_IN_FABS:
case BUILT_IN_FABSF:
case BUILT_IN_FABSL:
- /* build_function_call changes these into ABS_EXPR. */
- abort ();
+ target = expand_builtin_fabs (arglist, target, subtarget);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_CABS:
+ case BUILT_IN_CABSF:
+ case BUILT_IN_CABSL:
+ if (flag_unsafe_math_optimizations)
+ {
+ target = expand_builtin_cabs (arglist, target);
+ if (target)
+ return target;
+ }
+ break;
case BUILT_IN_CONJ:
case BUILT_IN_CONJF:
return expand_builtin_saveregs ();
case BUILT_IN_ARGS_INFO:
- return expand_builtin_args_info (exp);
+ return expand_builtin_args_info (arglist);
/* Return the address of the first anonymous stack arg. */
case BUILT_IN_NEXT_ARG:
return expand_builtin_classify_type (arglist);
case BUILT_IN_CONSTANT_P:
- return expand_builtin_constant_p (exp);
+ return expand_builtin_constant_p (arglist, target_mode);
case BUILT_IN_FRAME_ADDRESS:
case BUILT_IN_RETURN_ADDRESS:
- return expand_builtin_frame_address (exp);
+ return expand_builtin_frame_address (fndecl, arglist);
/* Returns the address of the area where the structure is returned.
0 otherwise. */
break;
case BUILT_IN_STRLEN:
- target = expand_builtin_strlen (exp, target);
+ target = expand_builtin_strlen (arglist, target, target_mode);
if (target)
return target;
break;
case BUILT_IN_STRCPY:
- target = expand_builtin_strcpy (exp, target, mode);
+ target = expand_builtin_strcpy (arglist, target, mode);
if (target)
return target;
break;
break;
case BUILT_IN_MEMCPY:
- target = expand_builtin_memcpy (arglist, target, mode, /*endp=*/0);
+ target = expand_builtin_memcpy (arglist, target, mode);
if (target)
return target;
break;
case BUILT_IN_MEMPCPY:
- target = expand_builtin_memcpy (arglist, target, mode, /*endp=*/1);
+ target = expand_builtin_mempcpy (arglist, target, mode, /*endp=*/ 1);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_MEMMOVE:
+ target = expand_builtin_memmove (arglist, target, mode);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_BCOPY:
+ target = expand_builtin_bcopy (arglist);
if (target)
return target;
break;
case BUILT_IN_MEMSET:
- target = expand_builtin_memset (exp, target, mode);
+ target = expand_builtin_memset (arglist, target, mode);
if (target)
return target;
break;
case BUILT_IN_BZERO:
- target = expand_builtin_bzero (exp);
+ target = expand_builtin_bzero (arglist);
if (target)
return target;
break;
case BUILT_IN_DWARF_CFA:
return virtual_cfa_rtx;
#ifdef DWARF2_UNWIND_INFO
- case BUILT_IN_DWARF_FP_REGNUM:
- return expand_builtin_dwarf_fp_regnum ();
+ case BUILT_IN_DWARF_SP_COLUMN:
+ return expand_builtin_dwarf_sp_column ();
case BUILT_IN_INIT_DWARF_REG_SIZES:
expand_builtin_init_dwarf_reg_sizes (TREE_VALUE (arglist));
return const0_rtx;
taking a single real argument, then the return value is the
DECL_FUNCTION_CODE of the call, e.g. BUILT_IN_SQRT. Otherwise
the return value is END_BUILTINS. */
-
+
enum built_in_function
-builtin_mathfn_code (t)
- tree t;
+builtin_mathfn_code (tree t)
{
tree fndecl, arglist;
constant. ARGLIST is the argument list of the call. */
static tree
-fold_builtin_constant_p (arglist)
- tree arglist;
+fold_builtin_constant_p (tree arglist)
{
if (arglist == 0)
return 0;
/* Fold a call to __builtin_classify_type. */
static tree
-fold_builtin_classify_type (arglist)
- tree arglist;
+fold_builtin_classify_type (tree arglist)
{
if (arglist == 0)
return build_int_2 (no_type_class, 0);
/* Fold a call to __builtin_inf or __builtin_huge_val. */
static tree
-fold_builtin_inf (type, warn)
- tree type;
- int warn;
+fold_builtin_inf (tree type, int warn)
{
REAL_VALUE_TYPE real;
/* Fold a call to __builtin_nan or __builtin_nans. */
static tree
-fold_builtin_nan (arglist, type, quiet)
- tree arglist, type;
- int quiet;
+fold_builtin_nan (tree arglist, tree type, int quiet)
{
REAL_VALUE_TYPE real;
const char *str;
across (for instance floor((double)f) == (double)floorf (f).
Do the transformation. */
static tree
-fold_trunc_transparent_mathfn (exp)
- tree exp;
+fold_trunc_transparent_mathfn (tree exp)
{
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
return 0;
}
+/* Fold function call to builtin cabs, cabsf or cabsl. FNDECL is the
+ function's DECL, ARGLIST is the argument list and TYPE is the return
+ type. Return NULL_TREE if no simplification can be made. */
+
+static tree
+fold_builtin_cabs (tree fndecl, tree arglist, tree type)
+{
+ tree arg;
+
+ if (!arglist || TREE_CHAIN (arglist))
+ return NULL_TREE;
+
+ arg = TREE_VALUE (arglist);
+ if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
+ || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
+ return NULL_TREE;
+
+ /* Evaluate cabs of a constant at compile-time. */
+ if (flag_unsafe_math_optimizations
+ && TREE_CODE (arg) == COMPLEX_CST
+ && TREE_CODE (TREE_REALPART (arg)) == REAL_CST
+ && TREE_CODE (TREE_IMAGPART (arg)) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (TREE_REALPART (arg))
+ && ! TREE_CONSTANT_OVERFLOW (TREE_IMAGPART (arg)))
+ {
+ REAL_VALUE_TYPE r, i;
+
+ r = TREE_REAL_CST (TREE_REALPART (arg));
+ i = TREE_REAL_CST (TREE_IMAGPART (arg));
+
+ real_arithmetic (&r, MULT_EXPR, &r, &r);
+ real_arithmetic (&i, MULT_EXPR, &i, &i);
+ real_arithmetic (&r, PLUS_EXPR, &r, &i);
+ if (real_sqrt (&r, TYPE_MODE (type), &r)
+ || ! flag_trapping_math)
+ return build_real (type, r);
+ }
+
+ /* If either part is zero, cabs is fabs of the other. */
+ if (TREE_CODE (arg) == COMPLEX_EXPR
+ && real_zerop (TREE_OPERAND (arg, 0)))
+ return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 1)));
+ if (TREE_CODE (arg) == COMPLEX_EXPR
+ && real_zerop (TREE_OPERAND (arg, 1)))
+ return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0)));
+
+ if (flag_unsafe_math_optimizations)
+ {
+ enum built_in_function fcode;
+ tree sqrtfn;
+
+ fcode = DECL_FUNCTION_CODE (fndecl);
+ if (fcode == BUILT_IN_CABS)
+ sqrtfn = implicit_built_in_decls[BUILT_IN_SQRT];
+ else if (fcode == BUILT_IN_CABSF)
+ sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTF];
+ else if (fcode == BUILT_IN_CABSL)
+ sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTL];
+ else
+ sqrtfn = NULL_TREE;
+
+ if (sqrtfn != NULL_TREE)
+ {
+ tree rpart, ipart, result, arglist;
+
+ rpart = fold (build1 (REALPART_EXPR, type, arg));
+ ipart = fold (build1 (IMAGPART_EXPR, type, arg));
+
+ rpart = save_expr (rpart);
+ ipart = save_expr (ipart);
+
+ result = fold (build (PLUS_EXPR, type,
+ fold (build (MULT_EXPR, type,
+ rpart, rpart)),
+ fold (build (MULT_EXPR, type,
+ ipart, ipart))));
+
+ arglist = build_tree_list (NULL_TREE, result);
+ return build_function_call_expr (sqrtfn, arglist);
+ }
+ }
+
+ 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. */
tree
-fold_builtin (exp)
- tree exp;
+fold_builtin (tree exp)
{
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
}
break;
+ case BUILT_IN_FABS:
+ case BUILT_IN_FABSF:
+ case BUILT_IN_FABSL:
+ if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ return fold (build1 (ABS_EXPR, type, TREE_VALUE (arglist)));
+ break;
+
+ case BUILT_IN_CABS:
+ case BUILT_IN_CABSF:
+ case BUILT_IN_CABSL:
+ return fold_builtin_cabs (fndecl, arglist, type);
+
case BUILT_IN_SQRT:
case BUILT_IN_SQRTF:
case BUILT_IN_SQRTL:
if (TREE_CODE (arg) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg))
{
- enum machine_mode mode;
REAL_VALUE_TYPE r, x;
x = TREE_REAL_CST (arg);
- mode = TYPE_MODE (type);
- if (real_sqrt (&r, mode, &x)
+ if (real_sqrt (&r, TYPE_MODE (type), &x)
|| (!flag_trapping_math && !flag_errno_math))
return build_real (type, r);
}
/* Optimize sin(0.0) = 0.0. */
if (real_zerop (arg))
- return build_real (type, dconst0);
+ return arg;
}
break;
/* Optimize cos(0.0) = 1.0. */
if (real_zerop (arg))
return build_real (type, dconst1);
+
+ /* Optimize cos(-x) into cos(x). */
+ if (TREE_CODE (arg) == NEGATE_EXPR)
+ {
+ tree arglist = build_tree_list (NULL_TREE,
+ TREE_OPERAND (arg, 0));
+ return build_function_call_expr (fndecl, arglist);
+ }
}
break;
if (real_zerop (arg))
return build_real (type, dconst1);
+ /* Optimize exp(1.0) = e. */
+ if (real_onep (arg))
+ {
+ REAL_VALUE_TYPE cst;
+
+ if (! builtin_dconsts_init)
+ init_builtin_dconsts ();
+ real_convert (&cst, TYPE_MODE (type), &dconste);
+ return build_real (type, cst);
+ }
+
+ /* Attempt to evaluate exp at compile-time. */
+ if (flag_unsafe_math_optimizations
+ && TREE_CODE (arg) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (arg))
+ {
+ REAL_VALUE_TYPE cint;
+ REAL_VALUE_TYPE c;
+ HOST_WIDE_INT n;
+
+ c = TREE_REAL_CST (arg);
+ n = real_to_integer (&c);
+ real_from_integer (&cint, VOIDmode, n,
+ n < 0 ? -1 : 0, 0);
+ if (real_identical (&c, &cint))
+ {
+ REAL_VALUE_TYPE x;
+
+ if (! builtin_dconsts_init)
+ init_builtin_dconsts ();
+ real_powi (&x, TYPE_MODE (type), &dconste, n);
+ return build_real (type, x);
+ }
+ }
+
/* Optimize exp(log(x)) = x. */
fcode = builtin_mathfn_code (arg);
if (flag_unsafe_math_optimizations
}
break;
+ case BUILT_IN_TAN:
+ case BUILT_IN_TANF:
+ case BUILT_IN_TANL:
+ if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ {
+ enum built_in_function fcode;
+ tree arg = TREE_VALUE (arglist);
+
+ /* Optimize tan(0.0) = 0.0. */
+ if (real_zerop (arg))
+ return arg;
+
+ /* Optimize tan(atan(x)) = x. */
+ fcode = builtin_mathfn_code (arg);
+ if (flag_unsafe_math_optimizations
+ && (fcode == BUILT_IN_ATAN
+ || fcode == BUILT_IN_ATANF
+ || fcode == BUILT_IN_ATANL))
+ return TREE_VALUE (TREE_OPERAND (arg, 1));
+ }
+ break;
+
+ case BUILT_IN_ATAN:
+ case BUILT_IN_ATANF:
+ case BUILT_IN_ATANL:
+ if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ {
+ tree arg = TREE_VALUE (arglist);
+
+ /* Optimize atan(0.0) = 0.0. */
+ if (real_zerop (arg))
+ return arg;
+
+ /* Optimize atan(1.0) = pi/4. */
+ if (real_onep (arg))
+ {
+ REAL_VALUE_TYPE cst;
+
+ if (! builtin_dconsts_init)
+ init_builtin_dconsts ();
+ real_convert (&cst, TYPE_MODE (type), &dconstpi);
+ cst.exp -= 2;
+ return build_real (type, cst);
+ }
+ }
+ break;
+
case BUILT_IN_POW:
case BUILT_IN_POWF:
case BUILT_IN_POWL:
/* Optimize pow(x,2.0) = x*x. */
if (REAL_VALUES_EQUAL (c, dconst2)
&& (*lang_hooks.decls.global_bindings_p) () == 0
- && ! contains_placeholder_p (arg0))
+ && ! CONTAINS_PLACEHOLDER_P (arg0))
{
arg0 = save_expr (arg0);
return fold (build (MULT_EXPR, type, arg0, arg0));
if (flag_unsafe_math_optimizations
&& REAL_VALUES_EQUAL (c, dconstm2)
&& (*lang_hooks.decls.global_bindings_p) () == 0
- && ! contains_placeholder_p (arg0))
+ && ! CONTAINS_PLACEHOLDER_P (arg0))
{
arg0 = save_expr (arg0);
return fold (build (RDIV_EXPR, type,
return build_function_call_expr (sqrtfn, arglist);
}
}
+
+ /* Attempt to evaluate pow at compile-time. */
+ if (TREE_CODE (arg0) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (arg0))
+ {
+ REAL_VALUE_TYPE cint;
+ HOST_WIDE_INT n;
+
+ n = real_to_integer (&c);
+ real_from_integer (&cint, VOIDmode, n,
+ n < 0 ? -1 : 0, 0);
+ if (real_identical (&c, &cint))
+ {
+ REAL_VALUE_TYPE x;
+ bool inexact;
+
+ x = TREE_REAL_CST (arg0);
+ inexact = real_powi (&x, TYPE_MODE (type), &x, n);
+ if (flag_unsafe_math_optimizations || !inexact)
+ return build_real (type, x);
+ }
+ }
}
/* Optimize pow(exp(x),y) = exp(x*y). */
/* Conveniently construct a function call expression. */
tree
-build_function_call_expr (fn, arglist)
- tree fn, arglist;
+build_function_call_expr (tree fn, tree arglist)
{
tree call_expr;
ellipses, otherwise the last specifier must be a VOID_TYPE. */
static int
-validate_arglist VPARAMS ((tree arglist, ...))
+validate_arglist (tree arglist, ...)
{
enum tree_code code;
int res = 0;
+ va_list ap;
- VA_OPEN (ap, arglist);
- VA_FIXEDARG (ap, tree, arglist);
+ va_start (ap, arglist);
do
{
/* We need gotos here since we can only have one VA_CLOSE in a
function. */
end: ;
- VA_CLOSE (ap);
+ va_end (ap);
return res;
}
/* Default version of target-specific builtin setup that does nothing. */
void
-default_init_builtins ()
+default_init_builtins (void)
{
}
/* Default target-specific builtin expander that does nothing. */
rtx
-default_expand_builtin (exp, target, subtarget, mode, ignore)
- tree exp ATTRIBUTE_UNUSED;
- rtx target ATTRIBUTE_UNUSED;
- rtx subtarget ATTRIBUTE_UNUSED;
- enum machine_mode mode ATTRIBUTE_UNUSED;
- int ignore ATTRIBUTE_UNUSED;
+default_expand_builtin (tree exp ATTRIBUTE_UNUSED,
+ rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
{
return NULL_RTX;
}
/* Instantiate all remaining CONSTANT_P_RTX nodes. */
void
-purge_builtin_constant_p ()
+purge_builtin_constant_p (void)
{
rtx insn, set, arg, new, note;
}
}
+/* Returns true is EXP represents data that would potentially reside
+ in a readonly section. */
+
+static bool
+readonly_data_expr (tree exp)
+{
+ STRIP_NOPS (exp);
+
+ if (TREE_CODE (exp) == ADDR_EXPR)
+ return decl_readonly_section (TREE_OPERAND (exp, 0), 0);
+ else
+ return false;
+}