re PR middle-end/53688 (191.fma3d in SPEC CPU 2000 miscompiled)

PR middle-end/53688
	* builtins.c (get_memory_rtx): Always build an all-aliasing MEM_REF
	with correct size.

testsuite/
	* gcc.c-torture/execute/pr53688.c: New test.

From-SVN: r188852
This commit is contained in:
Michael Matz 2012-06-21 12:18:23 +00:00
parent ccd49f5a69
commit 625ed17217
4 changed files with 68 additions and 108 deletions

View File

@ -1,3 +1,9 @@
2012-06-21 Michael Matz <matz@suse.de>
PR middle-end/53688
* builtins.c (get_memory_rtx): Always build an all-aliasing MEM_REF
with correct size.
2012-06-21 Richard Guenther <rguenther@suse.de>
* tree-inline.c (estimate_num_insns): Estimate call cost for

View File

@ -1252,7 +1252,6 @@ get_memory_rtx (tree exp, tree len)
{
tree orig_exp = exp;
rtx addr, mem;
HOST_WIDE_INT off;
/* When EXP is not resolved SAVE_EXPR, MEM_ATTRS can be still derived
from its expression, for expr->a.b only <variable>.a.b is recorded. */
@ -1263,120 +1262,38 @@ get_memory_rtx (tree exp, tree len)
mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
/* Get an expression we can use to find the attributes to assign to MEM.
If it is an ADDR_EXPR, use the operand. Otherwise, dereference it if
we can. First remove any nops. */
First remove any nops. */
while (CONVERT_EXPR_P (exp)
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
exp = TREE_OPERAND (exp, 0);
off = 0;
if (TREE_CODE (exp) == POINTER_PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& host_integerp (TREE_OPERAND (exp, 1), 0)
&& (off = tree_low_cst (TREE_OPERAND (exp, 1), 0)) > 0)
exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
else if (TREE_CODE (exp) == ADDR_EXPR)
exp = TREE_OPERAND (exp, 0);
else if (POINTER_TYPE_P (TREE_TYPE (exp)))
exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp);
else
exp = NULL;
/* Build a MEM_REF representing the whole accessed area as a byte blob,
(as builtin stringops may alias with anything). */
exp = fold_build2 (MEM_REF,
build_array_type (char_type_node,
build_range_type (sizetype,
size_one_node, len)),
exp, build_int_cst (ptr_type_node, 0));
/* Honor attributes derived from exp, except for the alias set
(as builtin stringops may alias with anything) and the size
(as stringops may access multiple array elements). */
if (exp)
/* If the MEM_REF has no acceptable address, try to get the base object
from the original address we got, and build an all-aliasing
unknown-sized access to that one. */
if (is_gimple_mem_ref_addr (TREE_OPERAND (exp, 0)))
set_mem_attributes (mem, exp, 0);
else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& (exp = get_base_address (TREE_OPERAND (TREE_OPERAND (exp, 0),
0))))
{
exp = build_fold_addr_expr (exp);
exp = fold_build2 (MEM_REF,
build_array_type (char_type_node,
build_range_type (sizetype,
size_zero_node,
NULL)),
exp, build_int_cst (ptr_type_node, 0));
set_mem_attributes (mem, exp, 0);
if (off)
mem = adjust_automodify_address_nv (mem, BLKmode, NULL, off);
/* 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
|| CONVERT_EXPR_P (inner)
|| 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_KNOWN_P (mem))
offset = 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 (TREE_CODE (mem_expr) == COMPONENT_REF);
gcc_assert (field == TREE_OPERAND (mem_expr, 1));
/* Bitfields are generally not byte-addressable. */
gcc_assert (!DECL_BIT_FIELD (field)
|| ((tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
% BITS_PER_UNIT) == 0
&& host_integerp (DECL_SIZE (field), 0)
&& (TREE_INT_CST_LOW (DECL_SIZE (field))
% BITS_PER_UNIT) == 0));
/* If we can prove that the memory starting at XEXP (mem, 0) and
ending at XEXP (mem, 0) + LENGTH will fit into this field, we
can keep the COMPONENT_REF in MEM_EXPR. But be careful with
fields without DECL_SIZE_UNIT like flexible array members. */
if (length >= 0
&& DECL_SIZE_UNIT (field)
&& host_integerp (DECL_SIZE_UNIT (field), 0))
{
HOST_WIDE_INT size
= TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
if (offset <= size
&& length <= size
&& offset + length <= size)
break;
}
if (offset >= 0
&& host_integerp (DECL_FIELD_OFFSET (field), 0))
offset += TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field))
+ 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);
}
if (mem_expr == NULL)
offset = -1;
if (mem_expr != MEM_EXPR (mem))
{
set_mem_expr (mem, mem_expr);
if (offset >= 0)
set_mem_offset (mem, offset);
else
clear_mem_offset (mem);
}
}
set_mem_alias_set (mem, 0);
clear_mem_size (mem);
}
set_mem_alias_set (mem, 0);
return mem;
}

View File

@ -1,3 +1,8 @@
2012-06-21 Michael Matz <matz@suse.de>
PR middle-end/53688
* gcc.c-torture/execute/pr53688.c: New test.
2012-06-20 Richard Guenther <rguenther@suse.de>
PR tree-optimization/30318
@ -24,7 +29,7 @@
2012-06-16 Ville Voutilainen <ville.voutilainen@gmail.com>
* g++.dg/cpp0x/override4.C: New.
* g++.dg/cpp0x/override4.C: New.
2012-06-14 Jason Merrill <jason@redhat.com>

View File

@ -0,0 +1,32 @@
char headline[256];
struct hdr {
char part1[9];
char part2[8];
} p;
void __attribute__((noinline,noclone))
init()
{
__builtin_memcpy (p.part1, "FOOBARFOO", sizeof (p.part1));
__builtin_memcpy (p.part2, "SPEC CPU", sizeof (p.part2));
}
int main()
{
char *x;
int c;
init();
__builtin_memcpy (&headline[0], p.part1, 9);
c = 9;
x = &headline[0];
x = x + c;
__builtin_memset (x, ' ', 245);
__builtin_memcpy (&headline[10], p.part2, 8);
c = 18;
x = &headline[0];
x = x + c;
__builtin_memset (x, ' ', 238);
if (headline[10] != 'S')
__builtin_abort ();
return 0;
}