OSDN Git Service

PR middle-end/52419
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 29 Feb 2012 17:45:55 +0000 (17:45 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 29 Feb 2012 17:45:55 +0000 (17:45 +0000)
* expr.c (expand_assignment): If doing misaligned store that doesn't
cover all mode bits, perform a RMW cycle.

* gcc.dg/torture/pr52419.c: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@184666 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/expr.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/pr52419.c [new file with mode: 0644]

index 8b2e26b..8de6c89 100644 (file)
@@ -1,5 +1,9 @@
 2012-02-29  Jakub Jelinek  <jakub@redhat.com>
 
+       PR middle-end/52419
+       * expr.c (expand_assignment): If doing misaligned store that doesn't
+       cover all mode bits, perform a RMW cycle.
+
        PR tree-optimization/52429
        * tree-parloops.c (separate_decls_in_region_debug): Return early
        if var is LABEL_DECL.
index 2e716cc..a3ace7a 100644 (file)
@@ -4666,6 +4666,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
       int volatilep = 0;
       tree tem;
       bool misalignp;
+      rtx mem = NULL_RTX;
 
       push_temp_slots ();
       tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
@@ -4686,8 +4687,44 @@ expand_assignment (tree to, tree from, bool nontemporal)
          && ((icode = optab_handler (movmisalign_optab, mode))
              != CODE_FOR_nothing))
        {
+         enum machine_mode address_mode;
+         rtx op0;
+         struct expand_operand ops[2];
+         addr_space_t as = TYPE_ADDR_SPACE
+             (TREE_TYPE (TREE_TYPE (TREE_OPERAND (tem, 0))));
+         tree base = TREE_OPERAND (tem, 0);
+
          misalignp = true;
          to_rtx = gen_reg_rtx (mode);
+
+         address_mode = targetm.addr_space.address_mode (as);
+         op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+         op0 = convert_memory_address_addr_space (address_mode, op0, as);
+         if (!integer_zerop (TREE_OPERAND (tem, 1)))
+           {
+             rtx off = immed_double_int_const (mem_ref_offset (tem),
+                                               address_mode);
+             op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
+           }
+         op0 = memory_address_addr_space (mode, op0, as);
+         mem = gen_rtx_MEM (mode, op0);
+         set_mem_attributes (mem, tem, 0);
+         set_mem_addr_space (mem, as);
+         if (TREE_THIS_VOLATILE (tem))
+           MEM_VOLATILE_P (mem) = 1;
+
+         /* 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
        {
@@ -4842,26 +4879,6 @@ expand_assignment (tree to, tree from, bool nontemporal)
       if (misalignp)
        {
          struct expand_operand ops[2];
-         enum machine_mode address_mode;
-         rtx op0, mem;
-         addr_space_t as = TYPE_ADDR_SPACE
-             (TREE_TYPE (TREE_TYPE (TREE_OPERAND (tem, 0))));
-         tree base = TREE_OPERAND (tem, 0);
-         address_mode = targetm.addr_space.address_mode (as);
-         op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL);
-         op0 = convert_memory_address_addr_space (address_mode, op0, as);
-         if (!integer_zerop (TREE_OPERAND (tem, 1)))
-           {
-             rtx off = immed_double_int_const (mem_ref_offset (tem),
-                                               address_mode);
-             op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
-           }
-         op0 = memory_address_addr_space (mode, op0, as);
-         mem = gen_rtx_MEM (mode, op0);
-         set_mem_attributes (mem, tem, 0);
-         set_mem_addr_space (mem, as);
-         if (TREE_THIS_VOLATILE (tem))
-           MEM_VOLATILE_P (mem) = 1;
 
          create_fixed_operand (&ops[0], mem);
          create_input_operand (&ops[1], to_rtx, mode);
index 7b1ad21..5826e28 100644 (file)
@@ -1,5 +1,8 @@
 2012-02-29  Jakub Jelinek  <jakub@redhat.com>
 
+       PR middle-end/52419
+       * gcc.dg/torture/pr52419.c: New test.
+
        PR tree-optimization/52429
        * gcc.dg/torture/pr52429.c: New test.
        * g++.dg/opt/pr52429.C: New test.
diff --git a/gcc/testsuite/gcc.dg/torture/pr52419.c b/gcc/testsuite/gcc.dg/torture/pr52419.c
new file mode 100644 (file)
index 0000000..d24225a
--- /dev/null
@@ -0,0 +1,32 @@
+/* PR middle-end/52419 */
+/* { dg-do run } */
+
+extern void abort (void);
+
+typedef long long V
+  __attribute__ ((vector_size (2 * sizeof (long long)), may_alias));
+
+typedef struct S { V b; } P __attribute__((aligned (1)));
+
+struct __attribute__((packed)) T { char c; P s; };
+
+__attribute__((noinline, noclone)) void
+foo (P *p)
+{
+  p->b[1] = 5;
+}
+
+int
+main ()
+{
+  V a = { 3, 4 };
+  struct T t;
+
+  t.s.b = a;
+  foo (&t.s);
+
+  if (t.s.b[0] != 3 || t.s.b[1] != 5)
+    abort ();
+
+  return 0;
+}