summaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2005-08-26 22:02:44 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2005-08-26 22:02:44 +0000
commitd8ae1baae3e99dfbcbe2e7da2361de13a86d0395 (patch)
tree98ccbe9ec79be85a6d0adc7e6a8ae4dd1aafc086 /gcc/builtins.c
parent724912572b37ccd8531ff7dfeb33d19ed7742b4a (diff)
downloadgcc-d8ae1baae3e99dfbcbe2e7da2361de13a86d0395.tar.gz
PR rtl-optimization/23561
* builtins.c (get_memory_rtx): Add LEN argument. If MEM_EXPR is a COMPONENT_REF, remove all COMPONENT_REF from MEM_EXPR unless at most LEN bytes long memory fits into the field. (expand_builtin_memcpy, expand_builtin_mempcpy, expand_movstr, expand_builtin_strncpy, expand_builtin_memset, expand_builtin_memcmp, expand_builtin_strcmp, expand_builtin_strncmp): Adjust callers. * gcc.c-torture/execute/20050826-1.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@103541 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c119
1 files changed, 101 insertions, 18 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 9975b751ef2..43bbd2427cc 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -75,7 +75,7 @@ static int get_pointer_alignment (tree, unsigned 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 get_memory_rtx (tree);
+static rtx get_memory_rtx (tree, tree);
static tree build_string_literal (int, const char *);
static int apply_args_size (void);
static int apply_result_size (void);
@@ -1013,10 +1013,12 @@ expand_builtin_prefetch (tree arglist)
}
/* Get a MEM rtx for expression EXP which is the address of an operand
- to be used to be used in a string instruction (cmpstrsi, movmemsi, ..). */
+ to be used in a string instruction (cmpstrsi, movmemsi, ..). LEN is
+ the maximum length of the block of memory that might be accessed or
+ NULL if unknown. */
static rtx
-get_memory_rtx (tree exp)
+get_memory_rtx (tree exp, tree len)
{
rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_NORMAL);
rtx mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
@@ -1042,6 +1044,87 @@ get_memory_rtx (tree exp)
if (exp)
{
set_mem_attributes (mem, exp, 0);
+
+ /* Allow the string and memory builtins to overflow from one
+ field into another, see http://gcc.gnu.org/PR23561.
+ Thus avoid COMPONENT_REFs in MEM_EXPR unless we know the whole
+ memory accessed by the string or memory builtin will fit
+ within the field. */
+ if (MEM_EXPR (mem) && TREE_CODE (MEM_EXPR (mem)) == COMPONENT_REF)
+ {
+ tree mem_expr = MEM_EXPR (mem);
+ HOST_WIDE_INT offset = -1, length = -1;
+ tree inner = exp;
+
+ while (TREE_CODE (inner) == ARRAY_REF
+ || TREE_CODE (inner) == NOP_EXPR
+ || TREE_CODE (inner) == CONVERT_EXPR
+ || TREE_CODE (inner) == NON_LVALUE_EXPR
+ || TREE_CODE (inner) == VIEW_CONVERT_EXPR
+ || TREE_CODE (inner) == SAVE_EXPR)
+ inner = TREE_OPERAND (inner, 0);
+
+ gcc_assert (TREE_CODE (inner) == COMPONENT_REF);
+
+ if (MEM_OFFSET (mem)
+ && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
+ offset = INTVAL (MEM_OFFSET (mem));
+
+ if (offset >= 0 && len && host_integerp (len, 0))
+ length = tree_low_cst (len, 0);
+
+ while (TREE_CODE (inner) == COMPONENT_REF)
+ {
+ tree field = TREE_OPERAND (inner, 1);
+ gcc_assert (! DECL_BIT_FIELD (field));
+ gcc_assert (TREE_CODE (mem_expr) == COMPONENT_REF);
+ gcc_assert (field == TREE_OPERAND (mem_expr, 1));
+
+ if (length >= 0
+ && TYPE_SIZE_UNIT (TREE_TYPE (inner))
+ && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0))
+ {
+ HOST_WIDE_INT size
+ = tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0);
+ /* If we can prove the memory starting at XEXP (mem, 0)
+ and ending at XEXP (mem, 0) + LENGTH will fit into
+ this field, we can keep that COMPONENT_REF in MEM_EXPR. */
+ if (offset <= size
+ && length <= size
+ && offset + length <= size)
+ break;
+ }
+
+ if (offset >= 0
+ && host_integerp (DECL_FIELD_OFFSET (field), 0))
+ offset += tree_low_cst (DECL_FIELD_OFFSET (field), 0)
+ + tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+ / BITS_PER_UNIT;
+ else
+ {
+ offset = -1;
+ length = -1;
+ }
+
+ mem_expr = TREE_OPERAND (mem_expr, 0);
+ inner = TREE_OPERAND (inner, 0);
+
+ while (TREE_CODE (inner) == NOP_EXPR
+ || TREE_CODE (inner) == CONVERT_EXPR
+ || TREE_CODE (inner) == NON_LVALUE_EXPR
+ || TREE_CODE (inner) == VIEW_CONVERT_EXPR
+ || TREE_CODE (inner) == SAVE_EXPR)
+ inner = TREE_OPERAND (inner, 0);
+ }
+
+ if (mem_expr == NULL)
+ offset = -1;
+ if (mem_expr != MEM_EXPR (mem))
+ {
+ set_mem_expr (mem, mem_expr);
+ set_mem_offset (mem, offset >= 0 ? GEN_INT (offset) : NULL_RTX);
+ }
+ }
set_mem_alias_set (mem, 0);
set_mem_size (mem, NULL_RTX);
}
@@ -2808,7 +2891,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
if (src_align == 0)
return 0;
- dest_mem = get_memory_rtx (dest);
+ dest_mem = get_memory_rtx (dest, len);
set_mem_align (dest_mem, dest_align);
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
src_str = c_getstr (src);
@@ -2830,7 +2913,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
return dest_mem;
}
- src_mem = get_memory_rtx (src);
+ src_mem = get_memory_rtx (src, len);
set_mem_align (src_mem, src_align);
/* Copy word part most expediently. */
@@ -2909,7 +2992,7 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
(void *) src_str, dest_align))
{
- dest_mem = get_memory_rtx (dest);
+ dest_mem = get_memory_rtx (dest, len);
set_mem_align (dest_mem, dest_align);
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
@@ -2923,9 +3006,9 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m
&& can_move_by_pieces (INTVAL (len_rtx),
MIN (dest_align, src_align)))
{
- dest_mem = get_memory_rtx (dest);
+ dest_mem = get_memory_rtx (dest, len);
set_mem_align (dest_mem, dest_align);
- src_mem = get_memory_rtx (src);
+ src_mem = get_memory_rtx (src, len);
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);
@@ -3053,8 +3136,8 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
if (!HAVE_movstr)
return 0;
- dest_mem = get_memory_rtx (dest);
- src_mem = get_memory_rtx (src);
+ dest_mem = get_memory_rtx (dest, NULL);
+ src_mem = get_memory_rtx (src, NULL);
if (!endp)
{
target = force_reg (Pmode, XEXP (dest_mem, 0));
@@ -3260,7 +3343,7 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
(void *) p, dest_align))
return 0;
- dest_mem = get_memory_rtx (dest);
+ dest_mem = get_memory_rtx (dest, len);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
builtin_strncpy_read_str,
(void *) p, dest_align, 0);
@@ -3351,7 +3434,7 @@ expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode,
}
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
- dest_mem = get_memory_rtx (dest);
+ dest_mem = get_memory_rtx (dest, len);
if (TREE_CODE (val) != INTEGER_CST)
{
@@ -3502,8 +3585,8 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
- arg1_rtx = get_memory_rtx (arg1);
- arg2_rtx = get_memory_rtx (arg2);
+ arg1_rtx = get_memory_rtx (arg1, len);
+ arg2_rtx = get_memory_rtx (arg2, len);
arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
/* Set MEM_SIZE as appropriate. */
@@ -3596,8 +3679,8 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
arg1 = builtin_save_expr (arg1);
arg2 = builtin_save_expr (arg2);
- arg1_rtx = get_memory_rtx (arg1);
- arg2_rtx = get_memory_rtx (arg2);
+ arg1_rtx = get_memory_rtx (arg1, NULL);
+ arg2_rtx = get_memory_rtx (arg2, NULL);
#ifdef HAVE_cmpstrsi
/* Try to call cmpstrsi. */
@@ -3801,8 +3884,8 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
arg2 = builtin_save_expr (arg2);
len = builtin_save_expr (len);
- arg1_rtx = get_memory_rtx (arg1);
- arg2_rtx = get_memory_rtx (arg2);
+ arg1_rtx = get_memory_rtx (arg1, len);
+ arg2_rtx = get_memory_rtx (arg2, len);
arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
GEN_INT (MIN (arg1_align, arg2_align)));