[PATCH] Allow FSM threader to thread more complex conditions
authorJeff Law <law@redhat.com>
Mon, 12 Oct 2015 21:39:35 +0000 (15:39 -0600)
committerJeff Law <law@gcc.gnu.org>
Mon, 12 Oct 2015 21:39:35 +0000 (15:39 -0600)
* tree-ssa-threadbackward.c (get_gimple_control_stmt): New function.
(fsm_find_control_stmt_paths): Change name of first argument to
more accurately relfect what it really is.  Handle simplification
of GIMPLE_COND after finding a thread path for NAME.
* tree-ssa-threadedge.c (simplify_control_stmt_condition): Allow
nontrivial conditions to be handled by FSM threader.
(thread_through_normal_block): Extract the name to looup via
FSM threader from COND_EXPR.

* gcc.dg/tree-ssa/ssa-thread-12.c: New test.
* gcc.dg/tree-ssa/ssa-dom-thread-7.c: Update expected output.
* gcc.dg/tree-ssa/ssa-thread-11.c: Renamed from
ssa-dom-thread-11.c.

From-SVN: r228739

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c [deleted file]
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-11.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c [new file with mode: 0644]
gcc/tree-ssa-threadbackward.c
gcc/tree-ssa-threadedge.c

index 61e46ff8c5612913b5bcbfa38fc35f87d0766cf5..a8650439eef6e3b1fc77b31a80ae298992175916 100644 (file)
@@ -7,6 +7,15 @@
 
 2015-10-12  Jeff Law  <law@redhat.com>
 
+       * tree-ssa-threadbackward.c (get_gimple_control_stmt): New function.
+       (fsm_find_control_stmt_paths): Change name of first argument to
+       more accurately relfect what it really is.  Handle simplification
+       of GIMPLE_COND after finding a thread path for NAME. 
+       * tree-ssa-threadedge.c (simplify_control_stmt_condition): Allow
+       nontrivial conditions to be handled by FSM threader.
+       (thread_through_normal_block): Extract the name to looup via
+       FSM threader from COND_EXPR.
+
        * tree-ssa-threadbackward.c (fsm_find_thread_path): Remove
        restriction that traced SSA_NAME is a user variable.
 
index 89f33632865815b41f9d212ec61e8c0196a848e3..4a08f0fe6370932a929a347cf1693fbade1cc1f2 100644 (file)
@@ -1,5 +1,10 @@
 2015-10-12  Jeff Law  <law@redhat.com>
 
+       * gcc.dg/tree-ssa/ssa-thread-12.c: New test.
+       * gcc.dg/tree-ssa/ssa-dom-thread-7.c: Update expected output.
+       * gcc.dg/tree-ssa/ssa-thread-11.c: Renamed from
+       ssa-dom-thread-11.c.
+
        * gcc.dg/tree-ssa/ssa-dom-thread-11.c: New test.
 
 2015-10-12  Ville Voutilainen  <ville.voutilainen@gmail.com>
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c
deleted file mode 100644 (file)
index 03d0334..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp2-details" } */
-/* { dg-final { scan-tree-dump "FSM" "vrp2" } } */
-
-void abort (void);
-typedef struct bitmap_head_def *bitmap;
-typedef const struct bitmap_head_def *const_bitmap;
-typedef struct bitmap_obstack
-{
-  struct bitmap_obstack *next;
-  unsigned int indx;
-}
-bitmap_element;
-typedef struct bitmap_head_def
-{
-  bitmap_element *first;
-}
-bitmap_head;
-static __inline__ unsigned char
-bitmap_elt_ior (bitmap dst, bitmap_element * dst_elt,
-               bitmap_element * dst_prev, const bitmap_element * a_elt,
-               const bitmap_element * b_elt)
-{
-  ((void) (!(a_elt || b_elt) ? abort (), 0 : 0));
-}
-
-unsigned char
-bitmap_ior_and_compl (bitmap dst, const_bitmap a, const_bitmap b,
-                     const_bitmap kill)
-{
-  bitmap_element *dst_elt = dst->first;
-  const bitmap_element *a_elt = a->first;
-  const bitmap_element *b_elt = b->first;
-  const bitmap_element *kill_elt = kill->first;
-  bitmap_element *dst_prev = ((void *) 0);
-  while (a_elt || b_elt)
-    {
-      if (b_elt && kill_elt && kill_elt->indx == b_elt->indx
-         && (!a_elt || a_elt->indx >= b_elt->indx));
-      else
-       {
-         bitmap_elt_ior (dst, dst_elt, dst_prev, a_elt, b_elt);
-         if (a_elt && b_elt && a_elt->indx == b_elt->indx)
-           ;
-         else if (a_elt && (!b_elt || a_elt->indx <= b_elt->indx))
-           a_elt = a_elt->next;
-       }
-    }
-}
index d8be023cd570def073a5ed10926ce97f8bbb6fe7..445f2509dc3041e44fc0d5d328c0bfb39891c2bb 100644 (file)
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-dom1-details" } */
-/* { dg-final { scan-tree-dump-times "FSM" 19 "dom1" } } */
+/* { dg-final { scan-tree-dump-times "FSM" 38 "dom1" } } */
 
 enum STATE {
   S0=0,
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-11.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-11.c
new file mode 100644 (file)
index 0000000..03d0334
--- /dev/null
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp2-details" } */
+/* { dg-final { scan-tree-dump "FSM" "vrp2" } } */
+
+void abort (void);
+typedef struct bitmap_head_def *bitmap;
+typedef const struct bitmap_head_def *const_bitmap;
+typedef struct bitmap_obstack
+{
+  struct bitmap_obstack *next;
+  unsigned int indx;
+}
+bitmap_element;
+typedef struct bitmap_head_def
+{
+  bitmap_element *first;
+}
+bitmap_head;
+static __inline__ unsigned char
+bitmap_elt_ior (bitmap dst, bitmap_element * dst_elt,
+               bitmap_element * dst_prev, const bitmap_element * a_elt,
+               const bitmap_element * b_elt)
+{
+  ((void) (!(a_elt || b_elt) ? abort (), 0 : 0));
+}
+
+unsigned char
+bitmap_ior_and_compl (bitmap dst, const_bitmap a, const_bitmap b,
+                     const_bitmap kill)
+{
+  bitmap_element *dst_elt = dst->first;
+  const bitmap_element *a_elt = a->first;
+  const bitmap_element *b_elt = b->first;
+  const bitmap_element *kill_elt = kill->first;
+  bitmap_element *dst_prev = ((void *) 0);
+  while (a_elt || b_elt)
+    {
+      if (b_elt && kill_elt && kill_elt->indx == b_elt->indx
+         && (!a_elt || a_elt->indx >= b_elt->indx));
+      else
+       {
+         bitmap_elt_ior (dst, dst_elt, dst_prev, a_elt, b_elt);
+         if (a_elt && b_elt && a_elt->indx == b_elt->indx)
+           ;
+         else if (a_elt && (!b_elt || a_elt->indx <= b_elt->indx))
+           a_elt = a_elt->next;
+       }
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c
new file mode 100644 (file)
index 0000000..0697fb0
--- /dev/null
@@ -0,0 +1,72 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dom1-details" } */
+/* { dg-final { scan-tree-dump "FSM" "dom1" } } */
+
+typedef struct bitmap_head_def *bitmap;
+typedef const struct bitmap_head_def *const_bitmap;
+typedef struct VEC_int_base
+{
+}
+VEC_int_base;
+typedef struct VEC_int_heap
+{
+  VEC_int_base base;
+}
+VEC_int_heap;
+typedef unsigned long BITMAP_WORD;
+typedef struct bitmap_element_def
+{
+  struct bitmap_element_def *next;
+  unsigned int indx;
+}
+bitmap_element;
+typedef struct bitmap_head_def
+{
+}
+bitmap_head;
+typedef struct
+{
+  bitmap_element *elt1;
+  bitmap_element *elt2;
+  BITMAP_WORD bits;
+}
+bitmap_iterator;
+static __inline__ void
+bmp_iter_and_compl_init (bitmap_iterator * bi, const_bitmap map1,
+                        const_bitmap map2, unsigned start_bit,
+                        unsigned *bit_no)
+{
+}
+
+static __inline__ void
+bmp_iter_next (bitmap_iterator * bi, unsigned *bit_no)
+{
+}
+
+static __inline__ unsigned char
+bmp_iter_and_compl (bitmap_iterator * bi, unsigned *bit_no)
+{
+  if (bi->bits)
+    {
+      while (bi->elt2 && bi->elt2->indx < bi->elt1->indx)
+       bi->elt2 = bi->elt2->next;
+    }
+}
+
+extern int VEC_int_base_length (VEC_int_base *);
+bitmap
+compute_idf (bitmap def_blocks, bitmap_head * dfs)
+{
+  bitmap_iterator bi;
+  unsigned bb_index, i;
+  VEC_int_heap *work_stack;
+  bitmap phi_insertion_points;
+  while ((VEC_int_base_length (((work_stack) ? &(work_stack)->base : 0))) > 0)
+    {
+      for (bmp_iter_and_compl_init
+          (&(bi), (&dfs[bb_index]), (phi_insertion_points), (0), &(i));
+          bmp_iter_and_compl (&(bi), &(i)); bmp_iter_next (&(bi), &(i)))
+       {
+       }
+    }
+}
index ff6481c95475d48df86e1fd5b15ed9a42a60334a..5be6ee443e3ab29b8c07212e9b9d31a9576196d6 100644 (file)
@@ -36,6 +36,22 @@ along with GCC; see the file COPYING3.  If not see
 
 static int max_threaded_paths;
 
+/* Simple helper to get the last statement from BB, which is assumed
+   to be a control statement.  */
+static gimple *
+get_gimple_control_stmt (basic_block bb)
+{
+  gimple_stmt_iterator gsi = gsi_last_bb (bb);
+
+  if (gsi_end_p (gsi))
+    return NULL;
+
+  gimple *stmt = gsi_stmt (gsi);
+  enum gimple_code code = gimple_code (stmt);
+  gcc_assert (code == GIMPLE_COND || code == GIMPLE_SWITCH || code == GIMPLE_GOTO);
+  return stmt;
+}
+
 /* Return true if the CFG contains at least one path from START_BB to END_BB.
    When a path is found, record in PATH the blocks from END_BB to START_BB.
    VISITED_BBS is used to make sure we don't fall into an infinite loop.  Bound
@@ -70,17 +86,17 @@ fsm_find_thread_path (basic_block start_bb, basic_block end_bb,
   return false;
 }
 
-/* We trace the value of the SSA_NAME EXPR back through any phi nodes looking
+/* We trace the value of the SSA_NAME NAME back through any phi nodes looking
    for places where it gets a constant value and save the path.  Stop after
    having recorded MAX_PATHS jump threading paths.  */
 
 static void
-fsm_find_control_statement_thread_paths (tree expr,
+fsm_find_control_statement_thread_paths (tree name,
                                         hash_set<basic_block> *visited_bbs,
                                         vec<basic_block, va_gc> *&path,
                                         bool seen_loop_phi)
 {
-  gimple *def_stmt = SSA_NAME_DEF_STMT (expr);
+  gimple *def_stmt = SSA_NAME_DEF_STMT (name);
   basic_block var_bb = gimple_bb (def_stmt);
 
   if (var_bb == NULL)
@@ -284,6 +300,20 @@ fsm_find_control_statement_thread_paths (tree expr,
          jump_thread_path->safe_push (x);
        }
 
+      gimple *stmt = get_gimple_control_stmt ((*path)[0]);
+      gcc_assert (stmt);
+      /* We have found a constant value for ARG.  For GIMPLE_SWITCH
+        and GIMPLE_GOTO, we use it as-is.  However, for a GIMPLE_COND
+        we need to substitute, fold and simplify.  */
+      if (gimple_code (stmt) == GIMPLE_COND)
+       {
+         enum tree_code cond_code = gimple_cond_code (stmt);
+
+         /* We know the underyling format of the condition.  */
+         arg = fold_binary (cond_code, boolean_type_node,
+                            arg, gimple_cond_rhs (stmt));
+       }
+
       /* Add the edge taken when the control variable has value ARG.  */
       edge taken_edge = find_taken_edge ((*path)[0], arg);
       jump_thread_edge *x
index 5ca945864e7036eedaba352043c9cf3726e5a5c7..da2fb1fde46991fe5710768d059ce0cfcb44a59f 100644 (file)
@@ -551,11 +551,13 @@ simplify_control_stmt_condition (edge e,
           || !is_gimple_min_invariant (cached_lhs))
         cached_lhs = (*simplify) (dummy_cond, stmt, avail_exprs_stack);
 
-      /* If we were just testing that an integral type was != 0, and that
-        failed, just return the first operand.  This gives the FSM code a
-        chance to optimize the path.  */
-      if (cached_lhs == NULL
-         && cond_code == NE_EXPR)
+      /* If we were testing an integer/pointer against a constant, then
+        we can use the FSM code to trace the value of the SSA_NAME.  If
+        a value is found, then the condition will collapse to a constant.
+
+        Return the SSA_NAME we want to trace back rather than the full
+        expression and give the FSM threader a chance to find its value.  */
+      if (cached_lhs == NULL)
        {
          /* Recover the original operands.  They may have been simplified
             using context sensitive equivalences.  Those context sensitive
@@ -563,9 +565,10 @@ simplify_control_stmt_condition (edge e,
          tree op0 = gimple_cond_lhs (stmt);
          tree op1 = gimple_cond_rhs (stmt);
 
-         if (INTEGRAL_TYPE_P (TREE_TYPE (op0))
+         if ((INTEGRAL_TYPE_P (TREE_TYPE (op0))
+              || POINTER_TYPE_P (TREE_TYPE (op0)))
              && TREE_CODE (op0) == SSA_NAME
-             && integer_zerop (op1))
+             && TREE_CODE (op1) == INTEGER_CST)
            return op0;
        }
 
@@ -1046,11 +1049,19 @@ thread_through_normal_block (edge e,
 
       if (!flag_expensive_optimizations
          || optimize_function_for_size_p (cfun)
-         || TREE_CODE (cond) != SSA_NAME
+         || !(TREE_CODE (cond) == SSA_NAME
+              || (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
+                  && TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME
+                  && TREE_CODE (TREE_OPERAND (cond, 1)) == INTEGER_CST))
          || e->dest->loop_father != e->src->loop_father
          || loop_depth (e->dest->loop_father) == 0)
        return 0;
 
+      /* Extract the SSA_NAME we want to trace backwards if COND is not
+        already a bare SSA_NAME.  */
+      if (TREE_CODE (cond) != SSA_NAME)
+       cond = TREE_OPERAND (cond, 0);
+
       /* When COND cannot be simplified, try to find paths from a control
         statement back through the PHI nodes which would affect that control
         statement.  */