]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR middle-end/57748 (ICE when expanding assignment to unaligned zero-sized array)
authorBernd Edlinger <bernd.edlinger@hotmail.de>
Wed, 8 Jan 2014 17:25:38 +0000 (17:25 +0000)
committerBernd Edlinger <edlinger@gcc.gnu.org>
Wed, 8 Jan 2014 17:25:38 +0000 (17:25 +0000)
2014-01-08  Bernd Edlinger  <bernd.edlinger@hotmail.de>

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

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

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

From-SVN: r206437

gcc/ChangeLog
gcc/cfgexpand.c
gcc/expr.c
gcc/expr.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/pr57748-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/pr57748-4.c [new file with mode: 0644]

index 2fc426d85358c5813033660d35f67910923711bf..7c1edb58dea4fa2caeb3267ec9df2b86993e94d3 100644 (file)
@@ -1,3 +1,14 @@
+2014-01-08  Bernd Edlinger  <bernd.edlinger@hotmail.de>
+
+       PR middle-end/57748
+       * expr.h (expand_expr_real, expand_expr_real_1): Add new parameter
+       inner_reference_p.
+       (expand_expr, expand_normal): Adjust.
+       * expr.c (expand_expr_real, expand_expr_real_1): Add new parameter
+       inner_reference_p. Use inner_reference_p to expand inner references.
+       (store_expr): Adjust.
+       * cfgexpand.c (expand_call_stmt): Adjust.
+
 2014-01-08  Rong Xu  <xur@google.com> 
 
        * gcov-io.c (gcov_var): Move from gcov-io.h.
index 2ba1cf4e36e0d0946c3f53c86b0b23324a4b824e..0008be93d54da94146766926b83c952ceb47d7da 100644 (file)
@@ -2253,7 +2253,7 @@ expand_call_stmt (gimple stmt)
   if (lhs)
     expand_assignment (lhs, exp, false);
   else
-    expand_expr_real_1 (exp, const0_rtx, VOIDmode, EXPAND_NORMAL, NULL);
+    expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
   mark_transaction_restart_calls (stmt);
 }
index 916a8aa889acd9d79d3ca71cb85e37ee02fa56c3..400a152ce56417e8b842430b051cbc9f7c86d00c 100644 (file)
@@ -5325,7 +5325,7 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
       temp = expand_expr_real (exp, tmp_target, GET_MODE (target),
                               (call_param_p
                                ? EXPAND_STACK_PARM : EXPAND_NORMAL),
-                              &alt_rtl);
+                              &alt_rtl, false);
     }
 
   /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
@@ -7911,11 +7911,21 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
    address, and ALT_RTL is non-NULL, then *ALT_RTL is set to the
    DECL_RTL of the VAR_DECL.  *ALT_RTL is also set if EXP is a
    COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on
-   recursively.  */
+   recursively.
+
+   If INNER_REFERENCE_P is true, we are expanding an inner reference.
+   In this case, we don't adjust a returned MEM rtx that wouldn't be
+   sufficiently aligned for its mode; instead, it's up to the caller
+   to deal with it afterwards.  This is used to make sure that unaligned
+   base objects for which out-of-bounds accesses are supported, for
+   example record types with trailing arrays, aren't realigned behind
+   the back of the caller.
+   The normal operating mode is to pass FALSE for this parameter.  */
 
 rtx
 expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
-                 enum expand_modifier modifier, rtx *alt_rtl)
+                 enum expand_modifier modifier, rtx *alt_rtl,
+                 bool inner_reference_p)
 {
   rtx ret;
 
@@ -7927,7 +7937,8 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
       return ret ? ret : const0_rtx;
     }
 
-  ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
+  ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl,
+                           inner_reference_p);
   return ret;
 }
 
@@ -9232,7 +9243,8 @@ stmt_is_replaceable_p (gimple stmt)
 
 rtx
 expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
-                   enum expand_modifier modifier, rtx *alt_rtl)
+                   enum expand_modifier modifier, rtx *alt_rtl,
+                   bool inner_reference_p)
 {
   rtx op0, op1, temp, decl_rtl;
   tree type;
@@ -9378,7 +9390,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
          set_curr_insn_location (gimple_location (g));
          r = expand_expr_real (gimple_assign_rhs_to_tree (g), target,
-                               tmode, modifier, NULL);
+                               tmode, modifier, NULL, inner_reference_p);
          set_curr_insn_location (saved_loc);
          if (REG_P (r) && !REG_EXPR (r))
            set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (exp), r);
@@ -9597,7 +9609,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case SAVE_EXPR:
       {
        tree val = treeop0;
-       rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
+       rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl,
+                                     inner_reference_p);
 
        if (!SAVE_EXPR_RESOLVED_P (exp))
          {
@@ -9735,6 +9748,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          MEM_VOLATILE_P (temp) = 1;
        if (modifier != EXPAND_WRITE
            && modifier != EXPAND_MEMORY
+           && !inner_reference_p
            && mode != BLKmode
            && align < GET_MODE_ALIGNMENT (mode))
          {
@@ -9960,15 +9974,16 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
           computation, since it will need a temporary and TARGET is known
           to have to do.  This occurs in unchecked conversion in Ada.  */
        orig_op0 = op0
-         = expand_expr (tem,
-                        (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
-                         && COMPLETE_TYPE_P (TREE_TYPE (tem))
-                         && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
-                             != INTEGER_CST)
-                         && modifier != EXPAND_STACK_PARM
-                         ? target : NULL_RTX),
-                        VOIDmode,
-                        modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
+         = expand_expr_real (tem,
+                             (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+                              && COMPLETE_TYPE_P (TREE_TYPE (tem))
+                              && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
+                                  != INTEGER_CST)
+                              && modifier != EXPAND_STACK_PARM
+                              ? target : NULL_RTX),
+                             VOIDmode,
+                             modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier,
+                             NULL, true);
 
        /* If the field has a mode, we want to access it in the
           field's mode, not the computed mode.
@@ -10325,14 +10340,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          {
            /* See the normal_inner_ref case for the rationale.  */
            orig_op0
-             = expand_expr (tem,
-                            (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
-                             && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
-                                 != INTEGER_CST)
-                             && modifier != EXPAND_STACK_PARM
-                             ? target : NULL_RTX),
-                            VOIDmode,
-                            modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
+             = expand_expr_real (tem,
+                                 (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+                                  && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
+                                      != INTEGER_CST)
+                                  && modifier != EXPAND_STACK_PARM
+                                  ? target : NULL_RTX),
+                                 VOIDmode,
+                                 modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier,
+                                 NULL, true);
 
            if (MEM_P (orig_op0))
              {
@@ -10359,7 +10375,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       }
 
       if (!op0)
-       op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier);
+       op0 = expand_expr_real (treeop0, NULL_RTX, VOIDmode, modifier,
+                               NULL, inner_reference_p);
 
       /* If the input and output modes are both the same, we are done.  */
       if (mode == GET_MODE (op0))
@@ -10426,50 +10443,53 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
              op0 = copy_rtx (op0);
              set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
            }
-         else if (mode != BLKmode
-                  && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode)
-                  /* If the target does have special handling for unaligned
-                     loads of mode then use them.  */
-                  && ((icode = optab_handler (movmisalign_optab, mode))
-                      != CODE_FOR_nothing))
-           {
-             rtx reg, insn;
-
-             op0 = adjust_address (op0, mode, 0);
-             /* We've already validated the memory, and we're creating a
-                new pseudo destination.  The predicates really can't
-                fail.  */
-             reg = gen_reg_rtx (mode);
-
-             /* Nor can the insn generator.  */
-             insn = GEN_FCN (icode) (reg, op0);
-             emit_insn (insn);
-             return reg;
-           }
-         else if (STRICT_ALIGNMENT
+         else if (modifier != EXPAND_WRITE
+                  && modifier != EXPAND_MEMORY
+                  && !inner_reference_p
                   && mode != BLKmode
                   && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode))
            {
-             tree inner_type = TREE_TYPE (treeop0);
-             HOST_WIDE_INT temp_size
-               = MAX (int_size_in_bytes (inner_type),
-                      (HOST_WIDE_INT) GET_MODE_SIZE (mode));
-             rtx new_rtx
-               = assign_stack_temp_for_type (mode, temp_size, type);
-             rtx new_with_op0_mode
-               = adjust_address (new_rtx, GET_MODE (op0), 0);
-
-             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 = 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 = new_rtx;
+               }
            }
 
          op0 = adjust_address (op0, mode, 0);
@@ -10569,7 +10589,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* WITH_SIZE_EXPR expands to its first argument.  The caller should
         have pulled out the size to use in whatever context it needed.  */
       return expand_expr_real (treeop0, original_target, tmode,
-                              modifier, alt_rtl);
+                              modifier, alt_rtl, inner_reference_p);
 
     default:
       return expand_expr_real_2 (&ops, target, tmode, modifier);
index a39b98ea5efbfc31cad0ab7b3a754362a8647864..da5d4a6d56fdbeaf438a9631e281bfff1f655894 100644 (file)
@@ -41,7 +41,8 @@ along with GCC; see the file COPYING3.  If not see
     is a constant that is not a legitimate address.
    EXPAND_WRITE means we are only going to write to the resulting rtx.
    EXPAND_MEMORY means we are interested in a memory result, even if
-    the memory is constant and we could have propagated a constant value.  */
+    the memory is constant and we could have propagated a constant value,
+    or the memory is unaligned on a STRICT_ALIGNMENT target.  */
 enum expand_modifier {EXPAND_NORMAL = 0, EXPAND_STACK_PARM, EXPAND_SUM,
                      EXPAND_CONST_ADDRESS, EXPAND_INITIALIZER, EXPAND_WRITE,
                      EXPAND_MEMORY};
@@ -437,9 +438,9 @@ extern rtx force_operand (rtx, rtx);
 
 /* Work horses for expand_expr.  */
 extern rtx expand_expr_real (tree, rtx, enum machine_mode,
-                            enum expand_modifier, rtx *);
+                            enum expand_modifier, rtx *, bool);
 extern rtx expand_expr_real_1 (tree, rtx, enum machine_mode,
-                              enum expand_modifier, rtx *);
+                              enum expand_modifier, rtx *, bool);
 extern rtx expand_expr_real_2 (sepops, rtx, enum machine_mode,
                               enum expand_modifier);
 
@@ -450,13 +451,13 @@ static inline rtx
 expand_expr (tree exp, rtx target, enum machine_mode mode,
             enum expand_modifier modifier)
 {
-  return expand_expr_real (exp, target, mode, modifier, NULL);
+  return expand_expr_real (exp, target, mode, modifier, NULL, false);
 }
 
 static inline rtx
 expand_normal (tree exp)
 {
-  return expand_expr_real (exp, NULL_RTX, VOIDmode, EXPAND_NORMAL, NULL);
+  return expand_expr_real (exp, NULL_RTX, VOIDmode, EXPAND_NORMAL, NULL, false);
 }
 
 /* At the start of a function, record that we have no previously-pushed
index 39e7af09ce59d1693e24231b1fc6d2a77ba16252..827b482c55ca6ba39710204927162bbf8d0e3a55 100644 (file)
@@ -1,3 +1,9 @@
+2014-01-08  Bernd Edlinger  <bernd.edlinger@hotmail.de>
+
+       PR middle-end/57748
+       * gcc.dg/torture/pr57748-3.c: New test.
+       * gcc.dg/torture/pr57748-4.c: New test.
+
 2014-01-08  Marek Polacek  <polacek@redhat.com>
 
        PR middle-end/59669
diff --git a/gcc/testsuite/gcc.dg/torture/pr57748-3.c b/gcc/testsuite/gcc.dg/torture/pr57748-3.c
new file mode 100644 (file)
index 0000000..5ddb609
--- /dev/null
@@ -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 --git a/gcc/testsuite/gcc.dg/torture/pr57748-4.c b/gcc/testsuite/gcc.dg/torture/pr57748-4.c
new file mode 100644 (file)
index 0000000..455cb3d
--- /dev/null
@@ -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;
+}