gimple-ssa-isolate-paths.c (check_loadstore): New function.
authorJeff Law <law@redhat.com>
Tue, 12 Nov 2013 16:41:51 +0000 (09:41 -0700)
committerJeff Law <law@gcc.gnu.org>
Tue, 12 Nov 2013 16:41:51 +0000 (09:41 -0700)
* gimple-ssa-isolate-paths.c (check_loadstore): New function.
(insert_trap_and_remove_trailing_statements): New argument OP which
is the NULL pointer.  Emit the trap after the load/store through
the NULL pointer.  Simplify the RHS of a store through a NULL pointer
when trivial to do so.
(isolate_path): Corresponding changes.
(gimple_ssa_isolate_erroneous_path): Likewise.

* gcc.dg/tree-ssa/isolate-1.c: Update expected output.
* gcc.dg/tree-ssa/isolate-5.c: New test.

From-SVN: r204708

gcc/ChangeLog
gcc/gimple-ssa-isolate-paths.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c
gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c [new file with mode: 0644]

index 32bd0ece09998ae6608887eb9c59c16ba43ffd67..a9254472c8eb162840b1b4995c338ea29e0ebb46 100644 (file)
@@ -1,3 +1,13 @@
+2013-11-12  Jeff Law  <law@redhat.com>
+
+       * gimple-ssa-isolate-paths.c (check_loadstore): New function.
+       (insert_trap_and_remove_trailing_statements): New argument OP which
+       is the NULL pointer.  Emit the trap after the load/store through
+       the NULL pointer.  Simplify the RHS of a store through a NULL pointer
+       when trivial to do so.
+       (isolate_path): Corresponding changes.
+       (gimple_ssa_isolate_erroneous_path): Likewise.
+
 2013-11-12  Teresa Johnson  <tejohnson@google.com>
            Jan Hubicka  <jh@suse.cz>
 
index 983ed4d7602bd84a42d351e3709724e3b493cb5b..48ab6049e4e896cc7534ad435d032a5e90686e7c 100644 (file)
@@ -39,17 +39,65 @@ along with GCC; see the file COPYING3.  If not see
 
 static bool cfg_altered;
 
-/* Insert a trap before SI and remove SI and all statements after SI.  */
+/* Callback for walk_stmt_load_store_ops.
+   Return TRUE if OP will dereference the tree stored in DATA, FALSE
+   otherwise.
+
+   This routine only makes a superficial check for a dereference.  Thus,
+   it must only be used if it is safe to return a false negative.  */
+static bool
+check_loadstore (gimple stmt ATTRIBUTE_UNUSED, tree op, void *data)
+{
+  if ((TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF)
+      && operand_equal_p (TREE_OPERAND (op, 0), (tree)data, 0))
+    return true;
+  return false;
+}
+
+/* Insert a trap after SI and remove SI and all statements after the trap.  */
 
 static void
-insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p)
+insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p, tree op)
 {
-  gimple_seq seq = NULL;
-  gimple stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
-  gimple_seq_add_stmt (&seq, stmt);
-  gsi_insert_before (si_p, seq, GSI_SAME_STMT);
+  /* We want the NULL pointer dereference to actually occur so that
+     code that wishes to catch the signal can do so.
 
-  /* Now delete all remaining statements in this block.  */
+     If the dereference is a load, then there's nothing to do as the
+     LHS will be a throw-away SSA_NAME and the LHS is the NULL dereference.
+
+     If the dereference is a store and we can easily transform the RHS,
+     then simplify the RHS to enable more DCE.  */
+  gimple stmt = gsi_stmt (*si_p);
+  if (walk_stmt_load_store_ops (stmt, (void *)op, NULL, check_loadstore)
+      && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt))))
+    {
+      /* We just need to turn the RHS into zero converted to the proper
+         type.  */
+      tree type = TREE_TYPE (gimple_assign_lhs (stmt));
+      gimple_assign_set_rhs_code (stmt, INTEGER_CST);
+      gimple_assign_set_rhs1 (stmt, fold_convert (type, integer_zero_node));
+      update_stmt (stmt);
+    }
+
+  gimple new_stmt
+    = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
+  gimple_seq seq = NULL;
+  gimple_seq_add_stmt (&seq, new_stmt);
+
+  /* If we had a NULL pointer dereference, then we want to insert the
+     __builtin_trap after the statement, for the other cases we want
+     to insert before the statement.  */
+  if (walk_stmt_load_store_ops (stmt, (void *)op,
+                               check_loadstore,
+                               check_loadstore))
+    gsi_insert_after (si_p, seq, GSI_NEW_STMT);
+  else
+    gsi_insert_before (si_p, seq, GSI_NEW_STMT);
+
+  /* The iterator points to the __builtin_trap.  Advance the iterator
+     and delete everything else in the block.  */
+  gsi_next (si_p);
   for (; !gsi_end_p (*si_p);)
     {
       stmt = gsi_stmt (*si_p);
@@ -73,7 +121,8 @@ insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p)
    Return BB'.  */
 
 basic_block
-isolate_path (basic_block bb, basic_block duplicate, edge e, gimple stmt)
+isolate_path (basic_block bb, basic_block duplicate,
+             edge e, gimple stmt, tree op)
 {
   gimple_stmt_iterator si, si2;
   edge_iterator ei;
@@ -133,7 +182,7 @@ isolate_path (basic_block bb, basic_block duplicate, edge e, gimple stmt)
      SI2 points to the duplicate of STMT in DUPLICATE.  Insert a trap
      before SI2 and remove SI2 and all trailing statements.  */
   if (!gsi_end_p (si2))
-    insert_trap_and_remove_trailing_statements (&si2);
+    insert_trap_and_remove_trailing_statements (&si2, op);
 
   return duplicate;
 }
@@ -224,7 +273,7 @@ gimple_ssa_isolate_erroneous_paths (void)
                  if (infer_nonnull_range (use_stmt, lhs))
                    {
                      duplicate = isolate_path (bb, duplicate,
-                                               e, use_stmt);
+                                               e, use_stmt, lhs);
 
                      /* When we remove an incoming edge, we need to
                         reprocess the Ith element.  */
@@ -247,7 +296,8 @@ gimple_ssa_isolate_erroneous_paths (void)
             where a non-NULL value is required.  */
          if (infer_nonnull_range (stmt, null_pointer_node))
            {
-             insert_trap_and_remove_trailing_statements (&si);
+             insert_trap_and_remove_trailing_statements (&si,
+                                                         null_pointer_node);
 
              /* And finally, remove all outgoing edges from BB.  */
              edge e;
index e685e6699080c310bdae1020580b81e4e6a3238c..82d0e7a14d46c3c6290bbcd1dfec15496a50541e 100644 (file)
@@ -1,3 +1,8 @@
+2013-11-12  Jeff Law  <law@redhat.com>
+
+       * gcc.dg/tree-ssa/isolate-1.c: Update expected output.
+       * gcc.dg/tree-ssa/isolate-5.c: New test.
+
 2013-11-12  Martin Jambor  <mjambor@suse.cz>
 
        PR rtl-optimization/10474
        PR fortran/58989
        * gfortran.dg/reshape_6.f90: New test.
 
-2013-10-05  Jeff Law  <law@redhat.com>
+2013-11-05  Jeff Law  <law@redhat.com>
 
        * gcc.dg/pr38984.c: Add -fno-isolate-erroneous-paths.
        * gcc.dg/tree-ssa/isolate-1.c: New test.
index 6b779b4a4bc21d03806e5530159a92319f60cff1..33745baf2f81261a25d458927e10342b80de909a 100644 (file)
@@ -43,12 +43,14 @@ d_type (struct d_info *di)
    return ret;
 }
 
-/* We're testing two aspects of isolation here.  First that isolation
+/* We're testing three aspects of isolation here.  First that isolation
    occurs, second that if we have two null dereferences in a block that
    that we delete everything from the first dereferece to the end of the
-   block, regardless of which comes first in the immediate use iterator.  */
+   block, regardless of which comes first in the immediate use iterator
+   and finally that we set the RHS of the store to zero.  */
 /* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
-/* { dg-final { scan-tree-dump-times "->type" 1 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->type = 42" 1 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->type = 0" 1 "isolate-paths"} } */
 /* { dg-final { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
 /* { dg-final { cleanup-tree-dump "isolate-paths" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c
new file mode 100644 (file)
index 0000000..a70871e
--- /dev/null
@@ -0,0 +1,60 @@
+
+/* { dg-do compile } */ 
+/* { dg-options "-O2 -fdump-tree-isolate-paths" } */
+
+
+struct demangle_component
+{
+
+  int type;
+  int zzz;
+
+};
+
+
+struct d_info
+{
+  struct demangle_component *comps;
+  int next_comp;
+  int num_comps;
+};
+
+
+static struct demangle_component *
+d_make_empty (struct d_info *di)
+{
+  struct demangle_component *p;
+
+  if (di->next_comp >= di->num_comps)
+    return ((void *)0);
+  p = &di->comps[di->next_comp];
+  return p;
+}
+
+
+
+struct demangle_component *
+d_type (struct d_info *di)
+{
+   struct demangle_component *ret;
+   ret = d_make_empty (di);
+   foo (ret->type);
+   bar (ret->zzz);
+   return ret;
+}
+
+/* We're testing two aspects of isolation here.  First that isolation
+   occurs, second that if we have two null dereferences in a block that
+   that we delete everything from the first dereferece to the end of the
+   block, regardless of which comes first in the immediate use iterator.
+
+   We leave the 0->type in the IL, so expect to see ->type twice.  */
+/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->type" 2 "isolate-paths"} } */
+/* { dg-final { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
+/* { dg-final { cleanup-tree-dump "isolate-paths" } } */
+
+
+
+
+