re PR rtl-optimization/23561 (nonoverlapping_memrefs_p returns true even for overlapping memory references)

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.

From-SVN: r103541
This commit is contained in:
Jakub Jelinek 2005-08-27 00:02:44 +02:00 committed by Jakub Jelinek
parent ff8afde0ea
commit 435bb2a125
4 changed files with 158 additions and 18 deletions

View File

@ -1,3 +1,13 @@
2005-08-26 Jakub Jelinek <jakub@redhat.com>
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.
2005-08-26 Richard Henderson <rth@redhat.com>
PR rtl-opt/23560

View File

@ -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)));

View File

@ -1,5 +1,8 @@
2005-08-26 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/23561
* gcc.c-torture/execute/20050826-1.c: New test.
PR rtl-opt/23560
* gcc.c-torture/execute/20050826-2.c: New test.

View File

@ -0,0 +1,44 @@
/* PR rtl-optimization/23561 */
struct A
{
char a1[1];
char a2[5];
char a3[1];
char a4[2048 - 7];
} a;
typedef __SIZE_TYPE__ size_t;
extern void *memset (void *, int, size_t);
extern void *memcpy (void *, const void *, size_t);
extern int memcmp (const void *, const void *, size_t);
extern void abort (void);
void
bar (struct A *x)
{
size_t i;
if (memcmp (x, "\1HELLO\1", sizeof "\1HELLO\1"))
abort ();
for (i = 0; i < sizeof (x->a4); i++)
if (x->a4[i])
abort ();
}
int
foo (void)
{
memset (&a, 0, sizeof (a));
a.a1[0] = 1;
memcpy (a.a2, "HELLO", sizeof "HELLO");
a.a3[0] = 1;
bar (&a);
return 0;
}
int
main (void)
{
foo ();
return 0;
}