Commit 4c437f02 by Bernd Edlinger Committed by Bernd Edlinger

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
parent 40d6b753
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> 2014-01-08 Rong Xu <xur@google.com>
* gcov-io.c (gcov_var): Move from gcov-io.h. * gcov-io.c (gcov_var): Move from gcov-io.h.
......
...@@ -2253,7 +2253,7 @@ expand_call_stmt (gimple stmt) ...@@ -2253,7 +2253,7 @@ expand_call_stmt (gimple stmt)
if (lhs) if (lhs)
expand_assignment (lhs, exp, false); expand_assignment (lhs, exp, false);
else 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); mark_transaction_restart_calls (stmt);
} }
......
...@@ -5325,7 +5325,7 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) ...@@ -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), temp = expand_expr_real (exp, tmp_target, GET_MODE (target),
(call_param_p (call_param_p
? EXPAND_STACK_PARM : EXPAND_NORMAL), ? 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 /* 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, ...@@ -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 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 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 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 rtx
expand_expr_real (tree exp, rtx target, enum machine_mode tmode, 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; rtx ret;
...@@ -7927,7 +7937,8 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, ...@@ -7927,7 +7937,8 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
return ret ? ret : const0_rtx; 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; return ret;
} }
...@@ -9232,7 +9243,8 @@ stmt_is_replaceable_p (gimple stmt) ...@@ -9232,7 +9243,8 @@ stmt_is_replaceable_p (gimple stmt)
rtx rtx
expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, 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; rtx op0, op1, temp, decl_rtl;
tree type; tree type;
...@@ -9378,7 +9390,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, ...@@ -9378,7 +9390,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
set_curr_insn_location (gimple_location (g)); set_curr_insn_location (gimple_location (g));
r = expand_expr_real (gimple_assign_rhs_to_tree (g), target, 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); set_curr_insn_location (saved_loc);
if (REG_P (r) && !REG_EXPR (r)) if (REG_P (r) && !REG_EXPR (r))
set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (exp), 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, ...@@ -9597,7 +9609,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
case SAVE_EXPR: case SAVE_EXPR:
{ {
tree val = treeop0; 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)) if (!SAVE_EXPR_RESOLVED_P (exp))
{ {
...@@ -9735,6 +9748,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, ...@@ -9735,6 +9748,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
MEM_VOLATILE_P (temp) = 1; MEM_VOLATILE_P (temp) = 1;
if (modifier != EXPAND_WRITE if (modifier != EXPAND_WRITE
&& modifier != EXPAND_MEMORY && modifier != EXPAND_MEMORY
&& !inner_reference_p
&& mode != BLKmode && mode != BLKmode
&& align < GET_MODE_ALIGNMENT (mode)) && align < GET_MODE_ALIGNMENT (mode))
{ {
...@@ -9960,15 +9974,16 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, ...@@ -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 computation, since it will need a temporary and TARGET is known
to have to do. This occurs in unchecked conversion in Ada. */ to have to do. This occurs in unchecked conversion in Ada. */
orig_op0 = op0 orig_op0 = op0
= expand_expr (tem, = expand_expr_real (tem,
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
&& COMPLETE_TYPE_P (TREE_TYPE (tem)) && COMPLETE_TYPE_P (TREE_TYPE (tem))
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
!= INTEGER_CST) != INTEGER_CST)
&& modifier != EXPAND_STACK_PARM && modifier != EXPAND_STACK_PARM
? target : NULL_RTX), ? target : NULL_RTX),
VOIDmode, VOIDmode,
modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier); modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier,
NULL, true);
/* If the field has a mode, we want to access it in the /* If the field has a mode, we want to access it in the
field's mode, not the computed mode. field's mode, not the computed mode.
...@@ -10325,14 +10340,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, ...@@ -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. */ /* See the normal_inner_ref case for the rationale. */
orig_op0 orig_op0
= expand_expr (tem, = expand_expr_real (tem,
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
!= INTEGER_CST) != INTEGER_CST)
&& modifier != EXPAND_STACK_PARM && modifier != EXPAND_STACK_PARM
? target : NULL_RTX), ? target : NULL_RTX),
VOIDmode, VOIDmode,
modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier); modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier,
NULL, true);
if (MEM_P (orig_op0)) if (MEM_P (orig_op0))
{ {
...@@ -10359,7 +10375,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, ...@@ -10359,7 +10375,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
} }
if (!op0) 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 the input and output modes are both the same, we are done. */
if (mode == GET_MODE (op0)) if (mode == GET_MODE (op0))
...@@ -10426,50 +10443,53 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, ...@@ -10426,50 +10443,53 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
op0 = copy_rtx (op0); op0 = copy_rtx (op0);
set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type))); set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
} }
else if (mode != BLKmode else if (modifier != EXPAND_WRITE
&& MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode) && modifier != EXPAND_MEMORY
/* If the target does have special handling for unaligned && !inner_reference_p
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
&& mode != BLKmode && mode != BLKmode
&& MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode)) && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode))
{ {
tree inner_type = TREE_TYPE (treeop0); /* If the target does have special handling for unaligned
HOST_WIDE_INT temp_size loads of mode then use them. */
= MAX (int_size_in_bytes (inner_type), if ((icode = optab_handler (movmisalign_optab, mode))
(HOST_WIDE_INT) GET_MODE_SIZE (mode)); != CODE_FOR_nothing)
rtx new_rtx {
= assign_stack_temp_for_type (mode, temp_size, type); rtx reg, insn;
rtx new_with_op0_mode
= adjust_address (new_rtx, GET_MODE (op0), 0); op0 = adjust_address (op0, mode, 0);
/* We've already validated the memory, and we're creating a
gcc_assert (!TREE_ADDRESSABLE (exp)); new pseudo destination. The predicates really can't
fail. */
if (GET_MODE (op0) == BLKmode) reg = gen_reg_rtx (mode);
emit_block_move (new_with_op0_mode, op0,
GEN_INT (GET_MODE_SIZE (mode)), /* Nor can the insn generator. */
(modifier == EXPAND_STACK_PARM insn = GEN_FCN (icode) (reg, op0);
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); emit_insn (insn);
else return reg;
emit_move_insn (new_with_op0_mode, op0); }
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);
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 = new_rtx;
}
} }
op0 = adjust_address (op0, mode, 0); op0 = adjust_address (op0, mode, 0);
...@@ -10569,7 +10589,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, ...@@ -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 /* WITH_SIZE_EXPR expands to its first argument. The caller should
have pulled out the size to use in whatever context it needed. */ have pulled out the size to use in whatever context it needed. */
return expand_expr_real (treeop0, original_target, tmode, return expand_expr_real (treeop0, original_target, tmode,
modifier, alt_rtl); modifier, alt_rtl, inner_reference_p);
default: default:
return expand_expr_real_2 (&ops, target, tmode, modifier); return expand_expr_real_2 (&ops, target, tmode, modifier);
......
...@@ -41,7 +41,8 @@ along with GCC; see the file COPYING3. If not see ...@@ -41,7 +41,8 @@ along with GCC; see the file COPYING3. If not see
is a constant that is not a legitimate address. is a constant that is not a legitimate address.
EXPAND_WRITE means we are only going to write to the resulting rtx. 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 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, enum expand_modifier {EXPAND_NORMAL = 0, EXPAND_STACK_PARM, EXPAND_SUM,
EXPAND_CONST_ADDRESS, EXPAND_INITIALIZER, EXPAND_WRITE, EXPAND_CONST_ADDRESS, EXPAND_INITIALIZER, EXPAND_WRITE,
EXPAND_MEMORY}; EXPAND_MEMORY};
...@@ -437,9 +438,9 @@ extern rtx force_operand (rtx, rtx); ...@@ -437,9 +438,9 @@ extern rtx force_operand (rtx, rtx);
/* Work horses for expand_expr. */ /* Work horses for expand_expr. */
extern rtx expand_expr_real (tree, rtx, enum machine_mode, 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, 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, extern rtx expand_expr_real_2 (sepops, rtx, enum machine_mode,
enum expand_modifier); enum expand_modifier);
...@@ -450,13 +451,13 @@ static inline rtx ...@@ -450,13 +451,13 @@ static inline rtx
expand_expr (tree exp, rtx target, enum machine_mode mode, expand_expr (tree exp, rtx target, enum machine_mode mode,
enum expand_modifier modifier) 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 static inline rtx
expand_normal (tree exp) 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 /* At the start of a function, record that we have no previously-pushed
......
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> 2014-01-08 Marek Polacek <polacek@redhat.com>
PR middle-end/59669 PR middle-end/59669
......
/* 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;
}
/* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment