diff mbox

[4.8] backport PR57748 fixes (wrong-code and ICE regression)

Message ID 21700.64719.307316.814539@gargle.gargle.HOWL
State New
Headers show

Commit Message

Mikael Pettersson Jan. 25, 2015, 2:25 p.m. UTC
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?

(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.

Comments

Richard Biener Jan. 26, 2015, 9:14 a.m. UTC | #1
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;
> +}
Mikael Pettersson Jan. 26, 2015, 8:46 p.m. UTC | #2
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 mbox

Patch

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;
+}