mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-02-23 10:39:40 +08:00
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:
parent
40d6b7535c
commit
4c437f02c2
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
148
gcc/expr.c
148
gcc/expr.c
@ -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);
|
||||
|
11
gcc/expr.h
11
gcc/expr.h
@ -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
|
||||
|
@ -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
|
||||
|
40
gcc/testsuite/gcc.dg/torture/pr57748-3.c
Normal file
40
gcc/testsuite/gcc.dg/torture/pr57748-3.c
Normal 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;
|
||||
}
|
40
gcc/testsuite/gcc.dg/torture/pr57748-4.c
Normal file
40
gcc/testsuite/gcc.dg/torture/pr57748-4.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user