Fix if-conversion pass for dead type-unsafe code
authorvries <vries@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 14 Aug 2014 16:13:59 +0000 (16:13 +0000)
committervries <vries@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 14 Aug 2014 16:13:59 +0000 (16:13 +0000)
2014-08-14  Tom de Vries  <tom@codesourcery.com>

PR rtl-optimization/62004
PR rtl-optimization/62030
* ifcvt.c (rtx_interchangeable_p): New function.
(noce_try_move, noce_process_if_block): Use rtx_interchangeable_p.
* emit-rtl.c (mem_attrs_eq_p): Remove static.
* emit-rtl.h (mem_attrs_eq_p): Declare.

* gcc.dg/pr62004.c: New test.
* gcc.dg/pr62030.c: Same.
* gcc.target/mips/pr62030-octeon.c: Same.

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

gcc/ChangeLog
gcc/emit-rtl.h
gcc/ifcvt.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr62004.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr62030.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/pr62030-octeon.c [new file with mode: 0644]

index 0761150..4194ac7 100644 (file)
@@ -1,3 +1,12 @@
+2014-08-14  Tom de Vries  <tom@codesourcery.com>
+
+       PR rtl-optimization/62004
+       PR rtl-optimization/62030
+       * ifcvt.c (rtx_interchangeable_p): New function.
+       (noce_try_move, noce_process_if_block): Use rtx_interchangeable_p.
+       * emit-rtl.c (mem_attrs_eq_p): Remove static.
+       * emit-rtl.h (mem_attrs_eq_p): Declare.
+
 2014-08-14  Roman Gareev  <gareevroman@gmail.com>
 
        * graphite-scop-detection.c:
index 8439750..bae6e69 100644 (file)
@@ -72,6 +72,7 @@ extern void set_reg_attrs_for_parm (rtx, rtx);
 extern void set_reg_attrs_for_decl_rtl (tree t, rtx x);
 extern void adjust_reg_mode (rtx, enum machine_mode);
 extern int mem_expr_equal_p (const_tree, const_tree);
+extern bool mem_attrs_eq_p (const struct mem_attrs *, const struct mem_attrs *);
 
 extern bool need_atomic_barrier_p (enum memmodel, bool);
 
index e44c1dc..521dca0 100644 (file)
@@ -305,6 +305,28 @@ block_fallthru (basic_block bb)
 
   return (e) ? e->dest : NULL_BLOCK;
 }
+
+/* Return true if RTXs A and B can be safely interchanged.  */
+
+static bool
+rtx_interchangeable_p (const_rtx a, const_rtx b)
+{
+  if (!rtx_equal_p (a, b))
+    return false;
+
+  if (GET_CODE (a) != MEM)
+    return true;
+
+  /* A dead type-unsafe memory reference is legal, but a live type-unsafe memory
+     reference is not.  Interchanging a dead type-unsafe memory reference with
+     a live type-safe one creates a live type-unsafe memory reference, in other
+     words, it makes the program illegal.
+     We check here conservatively whether the two memory references have equal
+     memory attributes.  */
+
+  return mem_attrs_eq_p (get_mem_attrs (a), get_mem_attrs (b));
+}
+
 \f
 /* Go through a bunch of insns, converting them to conditional
    execution format if possible.  Return TRUE if all of the non-note
@@ -1033,6 +1055,9 @@ noce_try_move (struct noce_if_info *if_info)
       || (rtx_equal_p (if_info->a, XEXP (cond, 1))
          && rtx_equal_p (if_info->b, XEXP (cond, 0))))
     {
+      if (!rtx_interchangeable_p (if_info->a, if_info->b))
+       return FALSE;
+
       y = (code == EQ) ? if_info->a : if_info->b;
 
       /* Avoid generating the move if the source is the destination.  */
@@ -2503,7 +2528,7 @@ noce_process_if_block (struct noce_if_info *if_info)
       if (! insn_b
          || insn_b != last_active_insn (else_bb, FALSE)
          || (set_b = single_set (insn_b)) == NULL_RTX
-         || ! rtx_equal_p (x, SET_DEST (set_b)))
+         || ! rtx_interchangeable_p (x, SET_DEST (set_b)))
        return FALSE;
     }
   else
@@ -2516,7 +2541,7 @@ noce_process_if_block (struct noce_if_info *if_info)
          || BLOCK_FOR_INSN (insn_b) != BLOCK_FOR_INSN (if_info->cond_earliest)
          || !NONJUMP_INSN_P (insn_b)
          || (set_b = single_set (insn_b)) == NULL_RTX
-         || ! rtx_equal_p (x, SET_DEST (set_b))
+         || ! rtx_interchangeable_p (x, SET_DEST (set_b))
          || ! noce_operand_ok (SET_SRC (set_b))
          || reg_overlap_mentioned_p (x, SET_SRC (set_b))
          || modified_between_p (SET_SRC (set_b), insn_b, jump)
@@ -2582,7 +2607,7 @@ noce_process_if_block (struct noce_if_info *if_info)
 
   /* Look and see if A and B are really the same.  Avoid creating silly
      cmove constructs that no one will fix up later.  */
-  if (rtx_equal_p (a, b))
+  if (rtx_interchangeable_p (a, b))
     {
       /* If we have an INSN_B, we don't have to create any new rtl.  Just
         move the instruction that we already have.  If we don't have an
index 55dae55..7a28779 100644 (file)
@@ -1,3 +1,11 @@
+2014-08-14  Tom de Vries  <tom@codesourcery.com>
+
+       PR rtl-optimization/62004
+       PR rtl-optimization/62030
+       * gcc.dg/pr62004.c: New test.
+       * gcc.dg/pr62030.c: Same.
+       * gcc.target/mips/pr62030-octeon.c: Same.
+
 2014-08-14  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * g++.dg/cpp0x/alias-decl-4.C: Adjust for parser change.
diff --git a/gcc/testsuite/gcc.dg/pr62004.c b/gcc/testsuite/gcc.dg/pr62004.c
new file mode 100644 (file)
index 0000000..c994a41
--- /dev/null
@@ -0,0 +1,47 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-tree-tail-merge" } */
+
+struct node
+{
+  struct node *next;
+  struct node *prev;
+};
+
+struct node node;
+
+struct head
+{
+  struct node *first;
+};
+
+struct head heads[5];
+
+int k = 2;
+
+struct head *head = &heads[2];
+
+int
+main ()
+{
+  struct node *p;
+
+  node.next = (void*)0;
+
+  node.prev = (void *)head;
+
+  head->first = &node;
+
+  struct node *n = head->first;
+
+  struct head *h = &heads[k];
+
+  heads[2].first = n->next;
+
+  if ((void*)n->prev == (void *)h)
+    p = h->first;
+  else
+    /* Dead tbaa-unsafe load from ((struct node *)&heads[2])->next.  */
+    p = n->prev->next;
+
+  return !(p == (void*)0);
+}
diff --git a/gcc/testsuite/gcc.dg/pr62030.c b/gcc/testsuite/gcc.dg/pr62030.c
new file mode 100644 (file)
index 0000000..b8baf93
--- /dev/null
@@ -0,0 +1,50 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern void abort (void);
+
+struct node
+{
+  struct node *next;
+  struct node *prev;
+};
+
+struct node node;
+
+struct head
+{
+  struct node *first;
+};
+
+struct head heads[5];
+
+int k = 2;
+
+struct head *head = &heads[2];
+
+static int __attribute__((noinline))
+foo (void)
+{
+  node.prev = (void *)head;
+  head->first = &node;
+
+  struct node *n = head->first;
+  struct head *h = &heads[k];
+  struct node *next = n->next;
+
+  if (n->prev == (void *)h)
+    h->first = next;
+  else
+    n->prev->next = next;
+
+  n->next = h->first;
+  return n->next == &node;
+}
+
+int
+main (void)
+{
+  if (foo ())
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/mips/pr62030-octeon.c b/gcc/testsuite/gcc.target/mips/pr62030-octeon.c
new file mode 100644 (file)
index 0000000..5e3d3b3
--- /dev/null
@@ -0,0 +1,50 @@
+/* { dg-do run } */
+/* { dg-options "-march=octeon" } */
+
+extern void abort (void);
+
+struct node
+{
+  struct node *next;
+  struct node *prev;
+};
+
+struct node node;
+
+struct head
+{
+  struct node *first;
+};
+
+struct head heads[5];
+
+int k = 2;
+
+struct head *head = &heads[2];
+
+static int __attribute__((noinline))
+foo (void)
+{
+  node.prev = (void *)head;
+  head->first = &node;
+
+  struct node *n = head->first;
+  struct head *h = &heads[k];
+  struct node *next = n->next;
+
+  if (n->prev == (void *)h)
+    h->first = next;
+  else
+    n->prev->next = next;
+
+  n->next = h->first;
+  return n->next == &node;
+}
+
+int
+main (void)
+{
+  if (foo ())
+    abort ();
+  return 0;
+}