tree-cfg.c (assert_unreachable_fallthru_edge_p): New function.
authorJakub Jelinek <jakub@redhat.com>
Thu, 31 Oct 2013 13:51:38 +0000 (14:51 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 31 Oct 2013 13:51:38 +0000 (14:51 +0100)
* tree-cfg.c (assert_unreachable_fallthru_edge_p): New function.
* tree-cfg.h (assert_unreachable_fallthru_edge_p): New prototype.
* tree-vrp.c (all_imm_uses_in_stmt_or_feed_cond): New function.
(remove_range_assertions): If ASSERT_EXPR_VAR has no other immediate
uses but in the condition and ASSERT_EXPR and the other successor of
the predecessor bb is __builtin_unreachable (), set_range_info of the
ASSERT_EXPR_VAR to the range info of the ASSERT_EXPR's lhs.

From-SVN: r204255

gcc/ChangeLog
gcc/tree-cfg.c
gcc/tree-cfg.h
gcc/tree-vrp.c

index 265300f9b918e79630400f71fcf77af6cc802ed3..e46ad1529a3695c6d4520c44685fa58dbe6e0892 100644 (file)
@@ -1,3 +1,13 @@
+2013-10-31  Jakub Jelinek  <jakub@redhat.com>
+
+       * tree-cfg.c (assert_unreachable_fallthru_edge_p): New function.
+       * tree-cfg.h (assert_unreachable_fallthru_edge_p): New prototype.
+       * tree-vrp.c (all_imm_uses_in_stmt_or_feed_cond): New function.
+       (remove_range_assertions): If ASSERT_EXPR_VAR has no other immediate
+       uses but in the condition and ASSERT_EXPR and the other successor of
+       the predecessor bb is __builtin_unreachable (), set_range_info of the
+       ASSERT_EXPR_VAR to the range info of the ASSERT_EXPR's lhs.
+
 2013-10-31  Martin Jambor  <mjambor@suse.cz>
 
        PR rtl-optimization/58934
index d70565735355de987027fc0fe09dac26db3a6435..d646693903259340de65f4f5beb20a4f59df8e02 100644 (file)
@@ -381,6 +381,50 @@ computed_goto_p (gimple t)
          && TREE_CODE (gimple_goto_dest (t)) != LABEL_DECL);
 }
 
+/* Returns true for edge E where e->src ends with a GIMPLE_COND and
+   the other edge points to a bb with just __builtin_unreachable ().
+   I.e. return true for C->M edge in:
+   <bb C>:
+   ...
+   if (something)
+     goto <bb N>;
+   else
+     goto <bb M>;
+   <bb N>:
+   __builtin_unreachable ();
+   <bb M>:  */
+
+bool
+assert_unreachable_fallthru_edge_p (edge e)
+{
+  basic_block pred_bb = e->src;
+  gimple last = last_stmt (pred_bb);
+  if (last && gimple_code (last) == GIMPLE_COND)
+    {
+      basic_block other_bb = EDGE_SUCC (pred_bb, 0)->dest;
+      if (other_bb == e->dest)
+       other_bb = EDGE_SUCC (pred_bb, 1)->dest;
+      if (EDGE_COUNT (other_bb->succs) == 0)
+       {
+         gimple_stmt_iterator gsi = gsi_after_labels (other_bb);
+         gimple stmt;
+
+         if (gsi_end_p (gsi))
+           return false;
+         stmt = gsi_stmt (gsi);
+         if (is_gimple_debug (stmt))
+           {
+             gsi_next_nondebug (&gsi);
+             if (gsi_end_p (gsi))
+               return false;
+             stmt = gsi_stmt (gsi);
+           }
+         return gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE);
+       }
+    }
+  return false;
+}
+
 
 /* Search the CFG for any computed gotos.  If found, factor them to a
    common computed goto site.  Also record the location of that site so
index d6a5d8fce0df0691653b1ca8abf8b4bb663f6e02..c5c105dbdaa980b27bca13d658da225f5d0ba5b3 100644 (file)
@@ -51,6 +51,7 @@ extern bool is_ctrl_stmt (gimple);
 extern bool is_ctrl_altering_stmt (gimple);
 extern bool simple_goto_p (gimple);
 extern bool stmt_ends_bb_p (gimple);
+extern bool assert_unreachable_fallthru_edge_p (edge);
 extern void delete_tree_cfg_annotations (void);
 extern gimple first_stmt (basic_block);
 extern gimple last_stmt (basic_block);
index d3a07f3fa166c9893d00223b34766cde1af98bd2..a28e9369660520ad6124838ac1e4c349fa28a62c 100644 (file)
@@ -6459,6 +6459,33 @@ check_all_array_refs (void)
     }
 }
 
+/* Return true if all imm uses of VAR are either in STMT, or
+   feed (optionally through a chain of single imm uses) GIMPLE_COND
+   in basic block COND_BB.  */
+
+static bool
+all_imm_uses_in_stmt_or_feed_cond (tree var, gimple stmt, basic_block cond_bb)
+{
+  use_operand_p use_p, use2_p;
+  imm_use_iterator iter;
+
+  FOR_EACH_IMM_USE_FAST (use_p, iter, var)
+    if (USE_STMT (use_p) != stmt)
+      {
+       gimple use_stmt = USE_STMT (use_p);
+       if (is_gimple_debug (use_stmt))
+         continue;
+       while (is_gimple_assign (use_stmt)
+              && single_imm_use (gimple_assign_lhs (use_stmt),
+                                 &use2_p, &use_stmt))
+         ;
+       if (gimple_code (use_stmt) != GIMPLE_COND
+           || gimple_bb (use_stmt) != cond_bb)
+         return false;
+      }
+  return true;
+}
+
 /* Convert range assertion expressions into the implied copies and
    copy propagate away the copies.  Doing the trivial copy propagation
    here avoids the need to run the full copy propagation pass after
@@ -6488,12 +6515,16 @@ remove_range_assertions (void)
 {
   basic_block bb;
   gimple_stmt_iterator si;
+  /* 1 if looking at ASSERT_EXPRs immediately at the beginning of
+     a basic block preceeded by GIMPLE_COND branching to it and
+     __builtin_trap, -1 if not yet checked, 0 otherwise.  */
+  int is_unreachable;
 
   /* Note that the BSI iterator bump happens at the bottom of the
      loop and no bump is necessary if we're removing the statement
      referenced by the current BSI.  */
   FOR_EACH_BB (bb)
-    for (si = gsi_start_bb (bb); !gsi_end_p (si);)
+    for (si = gsi_after_labels (bb), is_unreachable = -1; !gsi_end_p (si);)
       {
        gimple stmt = gsi_stmt (si);
        gimple use_stmt;
@@ -6501,6 +6532,7 @@ remove_range_assertions (void)
        if (is_gimple_assign (stmt)
            && gimple_assign_rhs_code (stmt) == ASSERT_EXPR)
          {
+           tree lhs = gimple_assign_lhs (stmt);
            tree rhs = gimple_assign_rhs1 (stmt);
            tree var;
            tree cond = fold (ASSERT_EXPR_COND (rhs));
@@ -6509,22 +6541,49 @@ remove_range_assertions (void)
 
            gcc_assert (cond != boolean_false_node);
 
-           /* Propagate the RHS into every use of the LHS.  */
            var = ASSERT_EXPR_VAR (rhs);
-           FOR_EACH_IMM_USE_STMT (use_stmt, iter,
-                                  gimple_assign_lhs (stmt))
+           gcc_assert (TREE_CODE (var) == SSA_NAME);
+
+           if (!POINTER_TYPE_P (TREE_TYPE (lhs))
+               && SSA_NAME_RANGE_INFO (lhs))
+             {
+               if (is_unreachable == -1)
+                 {
+                   is_unreachable = 0;
+                   if (single_pred_p (bb)
+                       && assert_unreachable_fallthru_edge_p
+                                                   (single_pred_edge (bb)))
+                     is_unreachable = 1;
+                 }
+               /* Handle
+                  if (x_7 >= 10 && x_7 < 20)
+                    __builtin_unreachable ();
+                  x_8 = ASSERT_EXPR <x_7, ...>;
+                  if the only uses of x_7 are in the ASSERT_EXPR and
+                  in the condition.  In that case, we can copy the
+                  range info from x_8 computed in this pass also
+                  for x_7.  */
+               if (is_unreachable
+                   && all_imm_uses_in_stmt_or_feed_cond (var, stmt,
+                                                         single_pred (bb)))
+                 set_range_info (var, SSA_NAME_RANGE_INFO (lhs)->min,
+                                 SSA_NAME_RANGE_INFO (lhs)->max);
+             }
+
+           /* Propagate the RHS into every use of the LHS.  */
+           FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
              FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
-               {
-                 SET_USE (use_p, var);
-                 gcc_assert (TREE_CODE (var) == SSA_NAME);
-               }
+               SET_USE (use_p, var);
 
            /* And finally, remove the copy, it is not needed.  */
            gsi_remove (&si, true);
            release_defs (stmt);
          }
        else
-         gsi_next (&si);
+         {
+           gsi_next (&si);
+           is_unreachable = 0;
+         }
       }
 }