re PR middle-end/57748 (ICE when expanding assignment to unaligned zero-sized array)

2014-01-08  Bernd Edlinger  <bernd.edlinger@hotmail.de>

        PR middle-end/57748
        * expr.h (expand_expr_real, expand_expr_real_1): Add new parameter
        inner_reference_p.
        (expand_expr, expand_normal): Adjust.
        * expr.c (expand_expr_real, expand_expr_real_1): Add new parameter
        inner_reference_p. Use inner_reference_p to expand inner references.
        (store_expr): Adjust.
        * cfgexpand.c (expand_call_stmt): Adjust.

testsuite:
2014-01-08  Bernd Edlinger  <bernd.edlinger@hotmail.de>

        PR middle-end/57748
        * gcc.dg/torture/pr57748-3.c: New test.
        * gcc.dg/torture/pr57748-4.c: New test.

From-SVN: r206437
This commit is contained in:
Bernd Edlinger 2014-01-08 17:25:38 +00:00 committed by Bernd Edlinger
parent 40d6b7535c
commit 4c437f02c2
7 changed files with 188 additions and 70 deletions

View File

@ -1,3 +1,14 @@
2014-01-08 Bernd Edlinger <bernd.edlinger@hotmail.de>
PR middle-end/57748
* expr.h (expand_expr_real, expand_expr_real_1): Add new parameter
inner_reference_p.
(expand_expr, expand_normal): Adjust.
* expr.c (expand_expr_real, expand_expr_real_1): Add new parameter
inner_reference_p. Use inner_reference_p to expand inner references.
(store_expr): Adjust.
* cfgexpand.c (expand_call_stmt): Adjust.
2014-01-08 Rong Xu <xur@google.com>
* gcov-io.c (gcov_var): Move from gcov-io.h.

View File

@ -2253,7 +2253,7 @@ expand_call_stmt (gimple stmt)
if (lhs)
expand_assignment (lhs, exp, false);
else
expand_expr_real_1 (exp, const0_rtx, VOIDmode, EXPAND_NORMAL, NULL);
expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
mark_transaction_restart_calls (stmt);
}

View File

@ -5325,7 +5325,7 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
temp = expand_expr_real (exp, tmp_target, GET_MODE (target),
(call_param_p
? EXPAND_STACK_PARM : EXPAND_NORMAL),
&alt_rtl);
&alt_rtl, false);
}
/* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
@ -7911,11 +7911,21 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
address, and ALT_RTL is non-NULL, then *ALT_RTL is set to the
DECL_RTL of the VAR_DECL. *ALT_RTL is also set if EXP is a
COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on
recursively. */
recursively.
If INNER_REFERENCE_P is true, we are expanding an inner reference.
In this case, we don't adjust a returned MEM rtx that wouldn't be
sufficiently aligned for its mode; instead, it's up to the caller
to deal with it afterwards. This is used to make sure that unaligned
base objects for which out-of-bounds accesses are supported, for
example record types with trailing arrays, aren't realigned behind
the back of the caller.
The normal operating mode is to pass FALSE for this parameter. */
rtx
expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
enum expand_modifier modifier, rtx *alt_rtl)
enum expand_modifier modifier, rtx *alt_rtl,
bool inner_reference_p)
{
rtx ret;
@ -7927,7 +7937,8 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
return ret ? ret : const0_rtx;
}
ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl,
inner_reference_p);
return ret;
}
@ -9232,7 +9243,8 @@ stmt_is_replaceable_p (gimple stmt)
rtx
expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
enum expand_modifier modifier, rtx *alt_rtl)
enum expand_modifier modifier, rtx *alt_rtl,
bool inner_reference_p)
{
rtx op0, op1, temp, decl_rtl;
tree type;
@ -9378,7 +9390,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
set_curr_insn_location (gimple_location (g));
r = expand_expr_real (gimple_assign_rhs_to_tree (g), target,
tmode, modifier, NULL);
tmode, modifier, NULL, inner_reference_p);
set_curr_insn_location (saved_loc);
if (REG_P (r) && !REG_EXPR (r))
set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (exp), r);
@ -9597,7 +9609,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
case SAVE_EXPR:
{
tree val = treeop0;
rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl,
inner_reference_p);
if (!SAVE_EXPR_RESOLVED_P (exp))
{
@ -9735,6 +9748,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
MEM_VOLATILE_P (temp) = 1;
if (modifier != EXPAND_WRITE
&& modifier != EXPAND_MEMORY
&& !inner_reference_p
&& mode != BLKmode
&& align < GET_MODE_ALIGNMENT (mode))
{
@ -9960,15 +9974,16 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
computation, since it will need a temporary and TARGET is known
to have to do. This occurs in unchecked conversion in Ada. */
orig_op0 = op0
= expand_expr (tem,
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
&& COMPLETE_TYPE_P (TREE_TYPE (tem))
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
!= INTEGER_CST)
&& modifier != EXPAND_STACK_PARM
? target : NULL_RTX),
VOIDmode,
modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
= expand_expr_real (tem,
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
&& COMPLETE_TYPE_P (TREE_TYPE (tem))
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
!= INTEGER_CST)
&& modifier != EXPAND_STACK_PARM
? target : NULL_RTX),
VOIDmode,
modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier,
NULL, true);
/* If the field has a mode, we want to access it in the
field's mode, not the computed mode.
@ -10325,14 +10340,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
{
/* See the normal_inner_ref case for the rationale. */
orig_op0
= expand_expr (tem,
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
!= INTEGER_CST)
&& modifier != EXPAND_STACK_PARM
? target : NULL_RTX),
VOIDmode,
modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
= expand_expr_real (tem,
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
!= INTEGER_CST)
&& modifier != EXPAND_STACK_PARM
? target : NULL_RTX),
VOIDmode,
modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier,
NULL, true);
if (MEM_P (orig_op0))
{
@ -10359,7 +10375,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
}
if (!op0)
op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier);
op0 = expand_expr_real (treeop0, NULL_RTX, VOIDmode, modifier,
NULL, inner_reference_p);
/* If the input and output modes are both the same, we are done. */
if (mode == GET_MODE (op0))
@ -10426,50 +10443,53 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
op0 = copy_rtx (op0);
set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
}
else if (mode != BLKmode
&& MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode)
/* If the target does have special handling for unaligned
loads of mode then use them. */
&& ((icode = optab_handler (movmisalign_optab, mode))
!= CODE_FOR_nothing))
{
rtx reg, insn;
op0 = adjust_address (op0, mode, 0);
/* We've already validated the memory, and we're creating a
new pseudo destination. The predicates really can't
fail. */
reg = gen_reg_rtx (mode);
/* Nor can the insn generator. */
insn = GEN_FCN (icode) (reg, op0);
emit_insn (insn);
return reg;
}
else if (STRICT_ALIGNMENT
else if (modifier != EXPAND_WRITE
&& modifier != EXPAND_MEMORY
&& !inner_reference_p
&& mode != BLKmode
&& MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode))
{
tree inner_type = TREE_TYPE (treeop0);
HOST_WIDE_INT temp_size
= MAX (int_size_in_bytes (inner_type),
(HOST_WIDE_INT) GET_MODE_SIZE (mode));
rtx new_rtx
= assign_stack_temp_for_type (mode, temp_size, type);
rtx new_with_op0_mode
= adjust_address (new_rtx, GET_MODE (op0), 0);
/* If the target does have special handling for unaligned
loads of mode then use them. */
if ((icode = optab_handler (movmisalign_optab, mode))
!= CODE_FOR_nothing)
{
rtx reg, insn;
gcc_assert (!TREE_ADDRESSABLE (exp));
op0 = adjust_address (op0, mode, 0);
/* We've already validated the memory, and we're creating a
new pseudo destination. The predicates really can't
fail. */
reg = gen_reg_rtx (mode);
if (GET_MODE (op0) == BLKmode)
emit_block_move (new_with_op0_mode, op0,
GEN_INT (GET_MODE_SIZE (mode)),
(modifier == EXPAND_STACK_PARM
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
else
emit_move_insn (new_with_op0_mode, op0);
/* Nor can the insn generator. */
insn = GEN_FCN (icode) (reg, op0);
emit_insn (insn);
return reg;
}
else if (STRICT_ALIGNMENT)
{
tree inner_type = TREE_TYPE (treeop0);
HOST_WIDE_INT temp_size
= MAX (int_size_in_bytes (inner_type),
(HOST_WIDE_INT) GET_MODE_SIZE (mode));
rtx new_rtx
= assign_stack_temp_for_type (mode, temp_size, type);
rtx new_with_op0_mode
= adjust_address (new_rtx, GET_MODE (op0), 0);
op0 = new_rtx;
gcc_assert (!TREE_ADDRESSABLE (exp));
if (GET_MODE (op0) == BLKmode)
emit_block_move (new_with_op0_mode, op0,
GEN_INT (GET_MODE_SIZE (mode)),
(modifier == EXPAND_STACK_PARM
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
else
emit_move_insn (new_with_op0_mode, op0);
op0 = new_rtx;
}
}
op0 = adjust_address (op0, mode, 0);
@ -10569,7 +10589,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
/* WITH_SIZE_EXPR expands to its first argument. The caller should
have pulled out the size to use in whatever context it needed. */
return expand_expr_real (treeop0, original_target, tmode,
modifier, alt_rtl);
modifier, alt_rtl, inner_reference_p);
default:
return expand_expr_real_2 (&ops, target, tmode, modifier);

View File

@ -41,7 +41,8 @@ along with GCC; see the file COPYING3. If not see
is a constant that is not a legitimate address.
EXPAND_WRITE means we are only going to write to the resulting rtx.
EXPAND_MEMORY means we are interested in a memory result, even if
the memory is constant and we could have propagated a constant value. */
the memory is constant and we could have propagated a constant value,
or the memory is unaligned on a STRICT_ALIGNMENT target. */
enum expand_modifier {EXPAND_NORMAL = 0, EXPAND_STACK_PARM, EXPAND_SUM,
EXPAND_CONST_ADDRESS, EXPAND_INITIALIZER, EXPAND_WRITE,
EXPAND_MEMORY};
@ -437,9 +438,9 @@ extern rtx force_operand (rtx, rtx);
/* Work horses for expand_expr. */
extern rtx expand_expr_real (tree, rtx, enum machine_mode,
enum expand_modifier, rtx *);
enum expand_modifier, rtx *, bool);
extern rtx expand_expr_real_1 (tree, rtx, enum machine_mode,
enum expand_modifier, rtx *);
enum expand_modifier, rtx *, bool);
extern rtx expand_expr_real_2 (sepops, rtx, enum machine_mode,
enum expand_modifier);
@ -450,13 +451,13 @@ static inline rtx
expand_expr (tree exp, rtx target, enum machine_mode mode,
enum expand_modifier modifier)
{
return expand_expr_real (exp, target, mode, modifier, NULL);
return expand_expr_real (exp, target, mode, modifier, NULL, false);
}
static inline rtx
expand_normal (tree exp)
{
return expand_expr_real (exp, NULL_RTX, VOIDmode, EXPAND_NORMAL, NULL);
return expand_expr_real (exp, NULL_RTX, VOIDmode, EXPAND_NORMAL, NULL, false);
}
/* At the start of a function, record that we have no previously-pushed

View File

@ -1,3 +1,9 @@
2014-01-08 Bernd Edlinger <bernd.edlinger@hotmail.de>
PR middle-end/57748
* gcc.dg/torture/pr57748-3.c: New test.
* gcc.dg/torture/pr57748-4.c: New test.
2014-01-08 Marek Polacek <polacek@redhat.com>
PR middle-end/59669

View File

@ -0,0 +1,40 @@
/* PR middle-end/57748 */
/* { dg-do run } */
/* wrong code in expand_expr_real_1. */
#include <stdlib.h>
extern void abort (void);
typedef long long V
__attribute__ ((vector_size (2 * sizeof (long long)), may_alias));
typedef struct S { V a; V b[0]; } P __attribute__((aligned (1)));
struct __attribute__((packed)) T { char c; P s; };
void __attribute__((noinline, noclone))
check (P *p)
{
if (p->b[0][0] != 3 || p->b[0][1] != 4)
abort ();
}
void __attribute__((noinline, noclone))
foo (struct T *t)
{
V a = { 3, 4 };
t->s.b[0] = a;
}
int
main ()
{
struct T *t = (struct T *) calloc (128, 1);
foo (t);
check (&t->s);
free (t);
return 0;
}

View File

@ -0,0 +1,40 @@
/* PR middle-end/57748 */
/* { dg-do run } */
/* wrong code in expand_expr_real_1. */
#include <stdlib.h>
extern void abort (void);
typedef long long V
__attribute__ ((vector_size (2 * sizeof (long long)), may_alias));
typedef struct S { V b[1]; } P __attribute__((aligned (1)));
struct __attribute__((packed)) T { char c; P s; };
void __attribute__((noinline, noclone))
check (P *p)
{
if (p->b[1][0] != 3 || p->b[1][1] != 4)
abort ();
}
void __attribute__((noinline, noclone))
foo (struct T *t)
{
V a = { 3, 4 };
t->s.b[1] = a;
}
int
main ()
{
struct T *t = (struct T *) calloc (128, 1);
foo (t);
check (&t->s);
free (t);
return 0;
}