Message ID | 21700.64719.307316.814539@gargle.gargle.HOWL |
---|---|
State | New |
Headers | show |
On Sun, Jan 25, 2015 at 3:25 PM, Mikael Pettersson <mikpelinux@gmail.com> wrote: > This backports the fixes for PR middle-end/57748, a wrong-code and ICE > regression, to the 4.8 branch. > > Tested extensively on x86_64, powerpc64, sparc64, ARMv{5,7}, and m68k. > > Ok for 4.8? Ok - I assume you have checked that all relevant patches in this area have been backported already? Thanks, Richard. > (I don't have commit rights.) > > /Mikael > > gcc/ > > 2015-01-25 Mikael Pettersson <mikpelinux@gmail.com> > > Backport from mainline > > 2013-09-20 Bernd Edlinger <bernd.edlinger@hotmail.de> > > PR middle-end/57748 > * expr.c (expand_assignment): Remove misalignp code path. > > 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. > > gcc/testsuite/ > > 2015-01-25 Mikael Pettersson <mikpelinux@gmail.com> > > Backport from mainline > > 2013-09-20 Bernd Edlinger <bernd.edlinger@hotmail.de> > > PR middle-end/57748 > * gcc.dg/torture/pr57748-1.c: New test. > * gcc.dg/torture/pr57748-2.c: New test. > > 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. > > diff -rupN gcc-4.8-20150122/gcc/cfgexpand.c gcc-4.8-20150122.pr57748/gcc/cfgexpand.c > --- gcc-4.8-20150122/gcc/cfgexpand.c 2014-01-07 17:49:22.000000000 +0100 > +++ gcc-4.8-20150122.pr57748/gcc/cfgexpand.c 2015-01-25 15:00:35.240949368 +0100 > @@ -2111,7 +2111,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); > } > diff -rupN gcc-4.8-20150122/gcc/expr.c gcc-4.8-20150122.pr57748/gcc/expr.c > --- gcc-4.8-20150122/gcc/expr.c 2014-11-28 18:06:23.000000000 +0100 > +++ gcc-4.8-20150122.pr57748/gcc/expr.c 2015-01-25 15:00:35.240949368 +0100 > @@ -4708,8 +4708,6 @@ expand_assignment (tree to, tree from, b > int unsignedp; > int volatilep = 0; > tree tem; > - bool misalignp; > - rtx mem = NULL_RTX; > > push_temp_slots (); > tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1, > @@ -4728,40 +4726,7 @@ expand_assignment (tree to, tree from, b > && DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1))) > get_bit_range (&bitregion_start, &bitregion_end, to, &bitpos, &offset); > > - /* If we are going to use store_bit_field and extract_bit_field, > - make sure to_rtx will be safe for multiple use. */ > - mode = TYPE_MODE (TREE_TYPE (tem)); > - if (TREE_CODE (tem) == MEM_REF > - && mode != BLKmode > - && ((align = get_object_alignment (tem)) > - < GET_MODE_ALIGNMENT (mode)) > - && ((icode = optab_handler (movmisalign_optab, mode)) > - != CODE_FOR_nothing)) > - { > - struct expand_operand ops[2]; > - > - misalignp = true; > - to_rtx = gen_reg_rtx (mode); > - mem = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); > - > - /* If the misaligned store doesn't overwrite all bits, perform > - rmw cycle on MEM. */ > - if (bitsize != GET_MODE_BITSIZE (mode)) > - { > - create_input_operand (&ops[0], to_rtx, mode); > - create_fixed_operand (&ops[1], mem); > - /* The movmisalign<mode> pattern cannot fail, else the assignment > - would silently be omitted. */ > - expand_insn (icode, 2, ops); > - > - mem = copy_rtx (mem); > - } > - } > - else > - { > - misalignp = false; > - to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); > - } > + to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); > > /* If the bitfield is volatile, we want to access it in the > field's mode, not the computed mode. > @@ -4900,17 +4865,6 @@ expand_assignment (tree to, tree from, b > get_alias_set (to), nontemporal); > } > > - if (misalignp) > - { > - struct expand_operand ops[2]; > - > - create_fixed_operand (&ops[0], mem); > - create_input_operand (&ops[1], to_rtx, mode); > - /* The movmisalign<mode> pattern cannot fail, else the assignment > - would silently be omitted. */ > - expand_insn (icode, 2, ops); > - } > - > if (result) > preserve_temp_slots (result); > pop_temp_slots (); > @@ -5262,7 +5216,7 @@ store_expr (tree exp, rtx target, int ca > 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 > @@ -7881,11 +7835,21 @@ expand_constructor (tree exp, rtx target > 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; > > @@ -7897,7 +7861,8 @@ expand_expr_real (tree exp, rtx target, > 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; > } > > @@ -9190,7 +9155,8 @@ expand_expr_real_2 (sepops ops, rtx targ > > 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; > @@ -9336,7 +9302,7 @@ expand_expr_real_1 (tree exp, rtx target > > 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); > @@ -9557,7 +9523,8 @@ expand_expr_real_1 (tree exp, rtx target > 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)) > { > @@ -9706,6 +9673,7 @@ expand_expr_real_1 (tree exp, rtx target > MEM_VOLATILE_P (temp) = 1; > if (modifier != EXPAND_WRITE > && modifier != EXPAND_MEMORY > + && !inner_reference_p > && mode != BLKmode > && align < GET_MODE_ALIGNMENT (mode)) > { > @@ -9940,18 +9908,19 @@ expand_expr_real_1 (tree exp, rtx target > 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_INITIALIZER > - || modifier == EXPAND_CONST_ADDRESS > - || modifier == EXPAND_STACK_PARM) > - ? modifier : EXPAND_NORMAL); > + = 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_INITIALIZER > + || modifier == EXPAND_CONST_ADDRESS > + || modifier == EXPAND_STACK_PARM) > + ? modifier : EXPAND_NORMAL, > + NULL, true); > > > /* If the bitfield is volatile, we want to access it in the > @@ -10302,17 +10271,18 @@ expand_expr_real_1 (tree exp, rtx target > { > /* 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_INITIALIZER > - || modifier == EXPAND_CONST_ADDRESS > - || modifier == EXPAND_STACK_PARM) > - ? modifier : EXPAND_NORMAL); > + = 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_INITIALIZER > + || modifier == EXPAND_CONST_ADDRESS > + || modifier == EXPAND_STACK_PARM) > + ? modifier : EXPAND_NORMAL, > + NULL, true); > > if (MEM_P (orig_op0)) > { > @@ -10339,8 +10309,8 @@ expand_expr_real_1 (tree exp, rtx target > } > > 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)) > @@ -10407,50 +10377,53 @@ expand_expr_real_1 (tree exp, rtx target > 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); > - > - 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); > + /* 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; > > - op0 = new_rtx; > + 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) > + { > + 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 = adjust_address (op0, mode, 0); > @@ -10550,7 +10523,7 @@ expand_expr_real_1 (tree exp, rtx target > /* 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); > diff -rupN gcc-4.8-20150122/gcc/expr.h gcc-4.8-20150122.pr57748/gcc/expr.h > --- gcc-4.8-20150122/gcc/expr.h 2014-04-04 16:09:23.000000000 +0200 > +++ gcc-4.8-20150122.pr57748/gcc/expr.h 2015-01-25 15:00:35.240949368 +0100 > @@ -41,7 +41,8 @@ along with GCC; see the file COPYING3. > 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}; > @@ -428,9 +429,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); > > @@ -441,13 +442,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 > diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-1.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-1.c > --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-1.c 1970-01-01 01:00:00.000000000 +0100 > +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-1.c 2015-01-25 15:00:32.660962074 +0100 > @@ -0,0 +1,49 @@ > +/* PR middle-end/57748 */ > +/* { dg-do run } */ > +/* ICE in expand_assignment: > + misalignp == true, !MEM_P (to_rtx), offset != 0, > + => gcc_assert (TREE_CODE (offset) == INTEGER_CST) */ > + > +#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 (struct T *t) > +{ > + if (t->s.b[0][0] != 3 || t->s.b[0][1] != 4) > + abort (); > +} > + > +int __attribute__((noinline, noclone)) > +get_i (void) > +{ > + return 0; > +} > + > +void __attribute__((noinline, noclone)) > +foo (P *p) > +{ > + V a = { 3, 4 }; > + int i = get_i (); > + p->b[i] = a; > +} > + > +int > +main () > +{ > + struct T *t = (struct T *) calloc (128, 1); > + > + foo (&t->s); > + check (t); > + > + free (t); > + return 0; > +} > diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-2.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-2.c > --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-2.c 1970-01-01 01:00:00.000000000 +0100 > +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-2.c 2015-01-25 15:00:32.660962074 +0100 > @@ -0,0 +1,43 @@ > +/* PR middle-end/57748 */ > +/* { dg-do run } */ > +/* wrong code in expand_assignment: > + misalignp == true, !MEM_P (to_rtx), > + offset == 0, bitpos >= GET_MODE_PRECISION, > + => result = NULL. */ > + > +#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 (struct T *t) > +{ > + if (t->s.b[0][0] != 3 || t->s.b[0][1] != 4) > + abort (); > +} > + > +void __attribute__((noinline, noclone)) > +foo (P *p) > +{ > + V a = { 3, 4 }; > + p->b[0] = a; > +} > + > +int > +main () > +{ > + struct T *t = (struct T *) calloc (128, 1); > + > + foo (&t->s); > + check (t); > + > + free (t); > + return 0; > +} > diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-3.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-3.c > --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-3.c 1970-01-01 01:00:00.000000000 +0100 > +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-3.c 2015-01-25 15:00:35.240949368 +0100 > @@ -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; > +} > diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-4.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-4.c > --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-4.c 1970-01-01 01:00:00.000000000 +0100 > +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-4.c 2015-01-25 15:00:35.240949368 +0100 > @@ -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; > +}
Richard Biener writes: > On Sun, Jan 25, 2015 at 3:25 PM, Mikael Pettersson <mikpelinux@gmail.com> wrote: > > This backports the fixes for PR middle-end/57748, a wrong-code and ICE > > regression, to the 4.8 branch. > > > > Tested extensively on x86_64, powerpc64, sparc64, ARMv{5,7}, and m68k. > > > > Ok for 4.8? > > Ok - I assume you have checked that all relevant patches in this area have > been backported already? I'm not aware of any dependencies for this PR to patches other than the two being backported here (r202778 and r206437). I've now re-tested 4.8 vanilla on x86_64 and ARM, and this combined patch is enough to fix this PR's test cases. Thanks, /Mikael > Thanks, > Richard. > > > (I don't have commit rights.) > > > > /Mikael > > > > gcc/ > > > > 2015-01-25 Mikael Pettersson <mikpelinux@gmail.com> > > > > Backport from mainline > > > > 2013-09-20 Bernd Edlinger <bernd.edlinger@hotmail.de> > > > > PR middle-end/57748 > > * expr.c (expand_assignment): Remove misalignp code path. > > > > 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. > > > > gcc/testsuite/ > > > > 2015-01-25 Mikael Pettersson <mikpelinux@gmail.com> > > > > Backport from mainline > > > > 2013-09-20 Bernd Edlinger <bernd.edlinger@hotmail.de> > > > > PR middle-end/57748 > > * gcc.dg/torture/pr57748-1.c: New test. > > * gcc.dg/torture/pr57748-2.c: New test. > > > > 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. > > > > diff -rupN gcc-4.8-20150122/gcc/cfgexpand.c gcc-4.8-20150122.pr57748/gcc/cfgexpand.c > > --- gcc-4.8-20150122/gcc/cfgexpand.c 2014-01-07 17:49:22.000000000 +0100 > > +++ gcc-4.8-20150122.pr57748/gcc/cfgexpand.c 2015-01-25 15:00:35.240949368 +0100 > > @@ -2111,7 +2111,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); > > } > > diff -rupN gcc-4.8-20150122/gcc/expr.c gcc-4.8-20150122.pr57748/gcc/expr.c > > --- gcc-4.8-20150122/gcc/expr.c 2014-11-28 18:06:23.000000000 +0100 > > +++ gcc-4.8-20150122.pr57748/gcc/expr.c 2015-01-25 15:00:35.240949368 +0100 > > @@ -4708,8 +4708,6 @@ expand_assignment (tree to, tree from, b > > int unsignedp; > > int volatilep = 0; > > tree tem; > > - bool misalignp; > > - rtx mem = NULL_RTX; > > > > push_temp_slots (); > > tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1, > > @@ -4728,40 +4726,7 @@ expand_assignment (tree to, tree from, b > > && DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1))) > > get_bit_range (&bitregion_start, &bitregion_end, to, &bitpos, &offset); > > > > - /* If we are going to use store_bit_field and extract_bit_field, > > - make sure to_rtx will be safe for multiple use. */ > > - mode = TYPE_MODE (TREE_TYPE (tem)); > > - if (TREE_CODE (tem) == MEM_REF > > - && mode != BLKmode > > - && ((align = get_object_alignment (tem)) > > - < GET_MODE_ALIGNMENT (mode)) > > - && ((icode = optab_handler (movmisalign_optab, mode)) > > - != CODE_FOR_nothing)) > > - { > > - struct expand_operand ops[2]; > > - > > - misalignp = true; > > - to_rtx = gen_reg_rtx (mode); > > - mem = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); > > - > > - /* If the misaligned store doesn't overwrite all bits, perform > > - rmw cycle on MEM. */ > > - if (bitsize != GET_MODE_BITSIZE (mode)) > > - { > > - create_input_operand (&ops[0], to_rtx, mode); > > - create_fixed_operand (&ops[1], mem); > > - /* The movmisalign<mode> pattern cannot fail, else the assignment > > - would silently be omitted. */ > > - expand_insn (icode, 2, ops); > > - > > - mem = copy_rtx (mem); > > - } > > - } > > - else > > - { > > - misalignp = false; > > - to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); > > - } > > + to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); > > > > /* If the bitfield is volatile, we want to access it in the > > field's mode, not the computed mode. > > @@ -4900,17 +4865,6 @@ expand_assignment (tree to, tree from, b > > get_alias_set (to), nontemporal); > > } > > > > - if (misalignp) > > - { > > - struct expand_operand ops[2]; > > - > > - create_fixed_operand (&ops[0], mem); > > - create_input_operand (&ops[1], to_rtx, mode); > > - /* The movmisalign<mode> pattern cannot fail, else the assignment > > - would silently be omitted. */ > > - expand_insn (icode, 2, ops); > > - } > > - > > if (result) > > preserve_temp_slots (result); > > pop_temp_slots (); > > @@ -5262,7 +5216,7 @@ store_expr (tree exp, rtx target, int ca > > 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 > > @@ -7881,11 +7835,21 @@ expand_constructor (tree exp, rtx target > > 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; > > > > @@ -7897,7 +7861,8 @@ expand_expr_real (tree exp, rtx target, > > 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; > > } > > > > @@ -9190,7 +9155,8 @@ expand_expr_real_2 (sepops ops, rtx targ > > > > 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; > > @@ -9336,7 +9302,7 @@ expand_expr_real_1 (tree exp, rtx target > > > > 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); > > @@ -9557,7 +9523,8 @@ expand_expr_real_1 (tree exp, rtx target > > 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)) > > { > > @@ -9706,6 +9673,7 @@ expand_expr_real_1 (tree exp, rtx target > > MEM_VOLATILE_P (temp) = 1; > > if (modifier != EXPAND_WRITE > > && modifier != EXPAND_MEMORY > > + && !inner_reference_p > > && mode != BLKmode > > && align < GET_MODE_ALIGNMENT (mode)) > > { > > @@ -9940,18 +9908,19 @@ expand_expr_real_1 (tree exp, rtx target > > 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_INITIALIZER > > - || modifier == EXPAND_CONST_ADDRESS > > - || modifier == EXPAND_STACK_PARM) > > - ? modifier : EXPAND_NORMAL); > > + = 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_INITIALIZER > > + || modifier == EXPAND_CONST_ADDRESS > > + || modifier == EXPAND_STACK_PARM) > > + ? modifier : EXPAND_NORMAL, > > + NULL, true); > > > > > > /* If the bitfield is volatile, we want to access it in the > > @@ -10302,17 +10271,18 @@ expand_expr_real_1 (tree exp, rtx target > > { > > /* 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_INITIALIZER > > - || modifier == EXPAND_CONST_ADDRESS > > - || modifier == EXPAND_STACK_PARM) > > - ? modifier : EXPAND_NORMAL); > > + = 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_INITIALIZER > > + || modifier == EXPAND_CONST_ADDRESS > > + || modifier == EXPAND_STACK_PARM) > > + ? modifier : EXPAND_NORMAL, > > + NULL, true); > > > > if (MEM_P (orig_op0)) > > { > > @@ -10339,8 +10309,8 @@ expand_expr_real_1 (tree exp, rtx target > > } > > > > 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)) > > @@ -10407,50 +10377,53 @@ expand_expr_real_1 (tree exp, rtx target > > 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); > > - > > - 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); > > + /* 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; > > > > - op0 = new_rtx; > > + 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) > > + { > > + 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 = adjust_address (op0, mode, 0); > > @@ -10550,7 +10523,7 @@ expand_expr_real_1 (tree exp, rtx target > > /* 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); > > diff -rupN gcc-4.8-20150122/gcc/expr.h gcc-4.8-20150122.pr57748/gcc/expr.h > > --- gcc-4.8-20150122/gcc/expr.h 2014-04-04 16:09:23.000000000 +0200 > > +++ gcc-4.8-20150122.pr57748/gcc/expr.h 2015-01-25 15:00:35.240949368 +0100 > > @@ -41,7 +41,8 @@ along with GCC; see the file COPYING3. > > 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}; > > @@ -428,9 +429,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); > > > > @@ -441,13 +442,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 > > diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-1.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-1.c > > --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-1.c 1970-01-01 01:00:00.000000000 +0100 > > +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-1.c 2015-01-25 15:00:32.660962074 +0100 > > @@ -0,0 +1,49 @@ > > +/* PR middle-end/57748 */ > > +/* { dg-do run } */ > > +/* ICE in expand_assignment: > > + misalignp == true, !MEM_P (to_rtx), offset != 0, > > + => gcc_assert (TREE_CODE (offset) == INTEGER_CST) */ > > + > > +#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 (struct T *t) > > +{ > > + if (t->s.b[0][0] != 3 || t->s.b[0][1] != 4) > > + abort (); > > +} > > + > > +int __attribute__((noinline, noclone)) > > +get_i (void) > > +{ > > + return 0; > > +} > > + > > +void __attribute__((noinline, noclone)) > > +foo (P *p) > > +{ > > + V a = { 3, 4 }; > > + int i = get_i (); > > + p->b[i] = a; > > +} > > + > > +int > > +main () > > +{ > > + struct T *t = (struct T *) calloc (128, 1); > > + > > + foo (&t->s); > > + check (t); > > + > > + free (t); > > + return 0; > > +} > > diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-2.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-2.c > > --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-2.c 1970-01-01 01:00:00.000000000 +0100 > > +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-2.c 2015-01-25 15:00:32.660962074 +0100 > > @@ -0,0 +1,43 @@ > > +/* PR middle-end/57748 */ > > +/* { dg-do run } */ > > +/* wrong code in expand_assignment: > > + misalignp == true, !MEM_P (to_rtx), > > + offset == 0, bitpos >= GET_MODE_PRECISION, > > + => result = NULL. */ > > + > > +#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 (struct T *t) > > +{ > > + if (t->s.b[0][0] != 3 || t->s.b[0][1] != 4) > > + abort (); > > +} > > + > > +void __attribute__((noinline, noclone)) > > +foo (P *p) > > +{ > > + V a = { 3, 4 }; > > + p->b[0] = a; > > +} > > + > > +int > > +main () > > +{ > > + struct T *t = (struct T *) calloc (128, 1); > > + > > + foo (&t->s); > > + check (t); > > + > > + free (t); > > + return 0; > > +} > > diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-3.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-3.c > > --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-3.c 1970-01-01 01:00:00.000000000 +0100 > > +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-3.c 2015-01-25 15:00:35.240949368 +0100 > > @@ -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; > > +} > > diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-4.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-4.c > > --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-4.c 1970-01-01 01:00:00.000000000 +0100 > > +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-4.c 2015-01-25 15:00:35.240949368 +0100 > > @@ -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; > > +} --
diff -rupN gcc-4.8-20150122/gcc/cfgexpand.c gcc-4.8-20150122.pr57748/gcc/cfgexpand.c --- gcc-4.8-20150122/gcc/cfgexpand.c 2014-01-07 17:49:22.000000000 +0100 +++ gcc-4.8-20150122.pr57748/gcc/cfgexpand.c 2015-01-25 15:00:35.240949368 +0100 @@ -2111,7 +2111,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); } diff -rupN gcc-4.8-20150122/gcc/expr.c gcc-4.8-20150122.pr57748/gcc/expr.c --- gcc-4.8-20150122/gcc/expr.c 2014-11-28 18:06:23.000000000 +0100 +++ gcc-4.8-20150122.pr57748/gcc/expr.c 2015-01-25 15:00:35.240949368 +0100 @@ -4708,8 +4708,6 @@ expand_assignment (tree to, tree from, b int unsignedp; int volatilep = 0; tree tem; - bool misalignp; - rtx mem = NULL_RTX; push_temp_slots (); tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1, @@ -4728,40 +4726,7 @@ expand_assignment (tree to, tree from, b && DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1))) get_bit_range (&bitregion_start, &bitregion_end, to, &bitpos, &offset); - /* If we are going to use store_bit_field and extract_bit_field, - make sure to_rtx will be safe for multiple use. */ - mode = TYPE_MODE (TREE_TYPE (tem)); - if (TREE_CODE (tem) == MEM_REF - && mode != BLKmode - && ((align = get_object_alignment (tem)) - < GET_MODE_ALIGNMENT (mode)) - && ((icode = optab_handler (movmisalign_optab, mode)) - != CODE_FOR_nothing)) - { - struct expand_operand ops[2]; - - misalignp = true; - to_rtx = gen_reg_rtx (mode); - mem = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); - - /* If the misaligned store doesn't overwrite all bits, perform - rmw cycle on MEM. */ - if (bitsize != GET_MODE_BITSIZE (mode)) - { - create_input_operand (&ops[0], to_rtx, mode); - create_fixed_operand (&ops[1], mem); - /* The movmisalign<mode> pattern cannot fail, else the assignment - would silently be omitted. */ - expand_insn (icode, 2, ops); - - mem = copy_rtx (mem); - } - } - else - { - misalignp = false; - to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); - } + to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); /* If the bitfield is volatile, we want to access it in the field's mode, not the computed mode. @@ -4900,17 +4865,6 @@ expand_assignment (tree to, tree from, b get_alias_set (to), nontemporal); } - if (misalignp) - { - struct expand_operand ops[2]; - - create_fixed_operand (&ops[0], mem); - create_input_operand (&ops[1], to_rtx, mode); - /* The movmisalign<mode> pattern cannot fail, else the assignment - would silently be omitted. */ - expand_insn (icode, 2, ops); - } - if (result) preserve_temp_slots (result); pop_temp_slots (); @@ -5262,7 +5216,7 @@ store_expr (tree exp, rtx target, int ca 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 @@ -7881,11 +7835,21 @@ expand_constructor (tree exp, rtx target 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; @@ -7897,7 +7861,8 @@ expand_expr_real (tree exp, rtx target, 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; } @@ -9190,7 +9155,8 @@ expand_expr_real_2 (sepops ops, rtx targ 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; @@ -9336,7 +9302,7 @@ expand_expr_real_1 (tree exp, rtx target 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); @@ -9557,7 +9523,8 @@ expand_expr_real_1 (tree exp, rtx target 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)) { @@ -9706,6 +9673,7 @@ expand_expr_real_1 (tree exp, rtx target MEM_VOLATILE_P (temp) = 1; if (modifier != EXPAND_WRITE && modifier != EXPAND_MEMORY + && !inner_reference_p && mode != BLKmode && align < GET_MODE_ALIGNMENT (mode)) { @@ -9940,18 +9908,19 @@ expand_expr_real_1 (tree exp, rtx target 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_INITIALIZER - || modifier == EXPAND_CONST_ADDRESS - || modifier == EXPAND_STACK_PARM) - ? modifier : EXPAND_NORMAL); + = 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_INITIALIZER + || modifier == EXPAND_CONST_ADDRESS + || modifier == EXPAND_STACK_PARM) + ? modifier : EXPAND_NORMAL, + NULL, true); /* If the bitfield is volatile, we want to access it in the @@ -10302,17 +10271,18 @@ expand_expr_real_1 (tree exp, rtx target { /* 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_INITIALIZER - || modifier == EXPAND_CONST_ADDRESS - || modifier == EXPAND_STACK_PARM) - ? modifier : EXPAND_NORMAL); + = 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_INITIALIZER + || modifier == EXPAND_CONST_ADDRESS + || modifier == EXPAND_STACK_PARM) + ? modifier : EXPAND_NORMAL, + NULL, true); if (MEM_P (orig_op0)) { @@ -10339,8 +10309,8 @@ expand_expr_real_1 (tree exp, rtx target } 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)) @@ -10407,50 +10377,53 @@ expand_expr_real_1 (tree exp, rtx target 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); - - 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); + /* 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; - op0 = new_rtx; + 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) + { + 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 = adjust_address (op0, mode, 0); @@ -10550,7 +10523,7 @@ expand_expr_real_1 (tree exp, rtx target /* 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); diff -rupN gcc-4.8-20150122/gcc/expr.h gcc-4.8-20150122.pr57748/gcc/expr.h --- gcc-4.8-20150122/gcc/expr.h 2014-04-04 16:09:23.000000000 +0200 +++ gcc-4.8-20150122.pr57748/gcc/expr.h 2015-01-25 15:00:35.240949368 +0100 @@ -41,7 +41,8 @@ along with GCC; see the file COPYING3. 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}; @@ -428,9 +429,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); @@ -441,13 +442,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 diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-1.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-1.c --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-1.c 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-1.c 2015-01-25 15:00:32.660962074 +0100 @@ -0,0 +1,49 @@ +/* PR middle-end/57748 */ +/* { dg-do run } */ +/* ICE in expand_assignment: + misalignp == true, !MEM_P (to_rtx), offset != 0, + => gcc_assert (TREE_CODE (offset) == INTEGER_CST) */ + +#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 (struct T *t) +{ + if (t->s.b[0][0] != 3 || t->s.b[0][1] != 4) + abort (); +} + +int __attribute__((noinline, noclone)) +get_i (void) +{ + return 0; +} + +void __attribute__((noinline, noclone)) +foo (P *p) +{ + V a = { 3, 4 }; + int i = get_i (); + p->b[i] = a; +} + +int +main () +{ + struct T *t = (struct T *) calloc (128, 1); + + foo (&t->s); + check (t); + + free (t); + return 0; +} diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-2.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-2.c --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-2.c 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-2.c 2015-01-25 15:00:32.660962074 +0100 @@ -0,0 +1,43 @@ +/* PR middle-end/57748 */ +/* { dg-do run } */ +/* wrong code in expand_assignment: + misalignp == true, !MEM_P (to_rtx), + offset == 0, bitpos >= GET_MODE_PRECISION, + => result = NULL. */ + +#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 (struct T *t) +{ + if (t->s.b[0][0] != 3 || t->s.b[0][1] != 4) + abort (); +} + +void __attribute__((noinline, noclone)) +foo (P *p) +{ + V a = { 3, 4 }; + p->b[0] = a; +} + +int +main () +{ + struct T *t = (struct T *) calloc (128, 1); + + foo (&t->s); + check (t); + + free (t); + return 0; +} diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-3.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-3.c --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-3.c 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-3.c 2015-01-25 15:00:35.240949368 +0100 @@ -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; +} diff -rupN gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-4.c gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-4.c --- gcc-4.8-20150122/gcc/testsuite/gcc.dg/torture/pr57748-4.c 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.8-20150122.pr57748/gcc/testsuite/gcc.dg/torture/pr57748-4.c 2015-01-25 15:00:35.240949368 +0100 @@ -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; +}