haifa-sched.c (is_cfg_nonregular): Change return type to an int.
authorJeffrey A Law <law@cygnus.com>
Sun, 8 Mar 1998 02:15:26 +0000 (02:15 +0000)
committerJeff Law <law@gcc.gnu.org>
Sun, 8 Mar 1998 02:15:26 +0000 (19:15 -0700)
        * haifa-sched.c (is_cfg_nonregular): Change return type to
        an int.  No longer compute "estimated" number of edges.  Use
        computed_jump_p instead of duplicating the code.  Fixup/add
        some comments.
        (build_control_flow): Returns a value indicating an irregularity
        in the cfg was detected.  Count the number of edges in the cfg.
        allocate various edge tables.
        (find_rgns): No longer look for unreachable blocks.
        (schedule_insns): Do not allocate memory for edge tables here.
        Free memory for edge tables before returning.  Do not perform
        cross block scheduling if build_control_flow returns nonzero.
        * flow.c (compute_preds_succs): More accurately determine when
        a block drops in.
Fixes various compile hangs after haifa cleanup.

From-SVN: r18439

gcc/ChangeLog
gcc/flow.c
gcc/haifa-sched.c

index 4d95f77c780c96105bb1042cce6faf55bf2cb0f1..3554885792b3b273480d51e7cac55bdfba3687e4 100644 (file)
@@ -1,5 +1,19 @@
 Sat Mar  7 00:54:15 1998  Jeffrey A Law  (law@cygnus.com)
 
+       * haifa-sched.c (is_cfg_nonregular): Change return type to
+       an int.  No longer compute "estimated" number of edges.  Use
+       computed_jump_p instead of duplicating the code.  Fixup/add
+       some comments.
+       (build_control_flow): Returns a value indicating an irregularity
+       in the cfg was detected.  Count the number of edges in the cfg.
+       allocate various edge tables.
+       (find_rgns): No longer look for unreachable blocks.
+       (schedule_insns): Do not allocate memory for edge tables here.
+       Free memory for edge tables before returning.  Do not perform
+       cross block scheduling if build_control_flow returns nonzero.
+       * flow.c (compute_preds_succs): More accurately determine when
+       a block drops in.
+
        * basic-block.h (free_basic_block_vargs): Provide prototype.
 
        * cccp.c (main): Fix dumb mistakes in last change.
index 89696b04a3b34308d6cd5a65e1a83917d1efaecf..5daff7c3602380d1540594dae45098916aad0915 100644 (file)
@@ -3269,13 +3269,29 @@ compute_preds_succs (s_preds, s_succs, num_preds, num_succs)
         uid_block_number as needed.  */
       for (bb = 0; bb < n_basic_blocks; bb++)
        {
-         rtx insn;
+         rtx insn, stop_insn;
 
+         if (bb == 0)
+           stop_insn = NULL_RTX;
+         else
+           stop_insn = basic_block_end[bb-1];
+
+         /* Look backwards from the start of this block.  Stop if we
+            hit the start of the function or the end of a previous
+            block.  Don't walk backwards through blocks that are just
+            deleted insns!  */
          for (insn = PREV_INSN (basic_block_head[bb]);
-              insn && GET_CODE (insn) == NOTE; insn = PREV_INSN (insn))
+              insn && insn != stop_insn && GET_CODE (insn) == NOTE;
+              insn = PREV_INSN (insn))
            ;
 
-         basic_block_drops_in[bb] = insn && GET_CODE (insn) != BARRIER;
+         /* Never set basic_block_drops_in for the first block.  It is
+            implicit.
+
+            If we stopped on anything other than a BARRIER, then this
+            block drops in.  */
+         if (bb != 0)
+           basic_block_drops_in[bb] = (insn ? GET_CODE (insn) != BARRIER : 1);
 
          insn = basic_block_head[bb];
          while (insn)
@@ -3286,9 +3302,8 @@ compute_preds_succs (s_preds, s_succs, num_preds, num_succs)
              insn = NEXT_INSN (insn);
            }
        }
-      
-      
     }
+      
   for (bb = 0; bb < n_basic_blocks; bb++)
     {
       rtx head;
@@ -3300,8 +3315,14 @@ compute_preds_succs (s_preds, s_succs, num_preds, num_succs)
        for (jump = LABEL_REFS (head);
             jump != head;
             jump = LABEL_NEXTREF (jump))
-         add_pred_succ (BLOCK_NUM (CONTAINING_INSN (jump)), bb,
-                        s_preds, s_succs, num_preds, num_succs);
+         {
+           if (! INSN_DELETED_P (CONTAINING_INSN (jump))
+               && (GET_CODE (CONTAINING_INSN (jump)) != NOTE
+                   || (NOTE_LINE_NUMBER (CONTAINING_INSN (jump))
+                       != NOTE_INSN_DELETED)))
+             add_pred_succ (BLOCK_NUM (CONTAINING_INSN (jump)), bb,
+                            s_preds, s_succs, num_preds, num_succs);
+         }
 
       jump = BLOCK_END (bb);
       /* If this is a RETURN insn or a conditional jump in the last
index b9b6202e3ec9995456bf8882227f7725e9e9545b..264e4226fa02b9ff44edec5756dde5f53bcdb117 100644 (file)
@@ -517,10 +517,9 @@ static int *out_edges;
 extern rtx forced_labels;
 
 
-static char is_cfg_nonregular PROTO ((void));
-static int uses_reg_or_mem PROTO ((rtx));
+static int is_cfg_nonregular PROTO ((void));
 void debug_control_flow PROTO ((void));
-static void build_control_flow PROTO ((void));
+static int build_control_flow PROTO ((void));
 static void new_edge PROTO ((int, int));
 
 
@@ -1078,37 +1077,35 @@ static rtx *bb_sched_before_next_call;
 /* functions for construction of the control flow graph.  */
 
 /* Return 1 if control flow graph should not be constructed, 0 otherwise.
-   Estimate in nr_edges the number of edges on the graph.
+
    We decide not to build the control flow graph if there is possibly more
-   than one entry to the function, or if computed branches exist.  */
+   than one entry to the function, if computed branches exist, of if we
+   have nonlocal gotos.  */
 
-static char
+static int
 is_cfg_nonregular ()
 {
   int b;
   rtx insn;
   RTX_CODE code;
 
-  rtx nonlocal_label_list = nonlocal_label_rtx_list ();
-
-  /* check for non local labels */
-  if (nonlocal_label_list)
-    {
-      return 1;
-    }
+  /* If we have a label that could be the target of a nonlocal goto, then
+     the cfg is not well structured.  */
+  if (nonlocal_label_rtx_list () != NULL)
+    return 1;
 
-  /* check for labels which cannot be deleted */
+  /* If we have any forced labels, then the cfg is not well structured.  */
   if (forced_labels)
-    {
-      return 1;
-    }
+    return 1;
 
-  /* check for labels which probably cannot be deleted */
+  /* If we have exception handlers, then we consider the cfg not well
+     structured.  ?!?  We should be able to handle this now that flow.c
+     computes an accurate cfg for EH.  */
   if (exception_handler_labels)
-    {
-      return 1;
-    }
+    return 1;
 
+  /* If we have non-jumping insns which refer to labels, then we consider
+     the cfg not well structured.  */
   /* check for labels referred to other thn by jumps */
   for (b = 0; b < n_basic_blocks; b++)
     for (insn = basic_block_head[b];; insn = NEXT_INSN (insn))
@@ -1120,150 +1117,31 @@ is_cfg_nonregular ()
 
            for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
              if (REG_NOTE_KIND (note) == REG_LABEL)
-               {
-                 return 1;
-               }
+               return 1;
          }
 
        if (insn == basic_block_end[b])
          break;
       }
 
-  nr_edges = 0;
-
-  /* check for computed branches */
+  /* If this function has a computed jump, then we consider the cfg
+     not well structured.  */
   for (b = 0; b < n_basic_blocks; b++)
     {
       for (insn = basic_block_head[b];; insn = NEXT_INSN (insn))
        {
-
-         if (GET_CODE (insn) == JUMP_INSN)
-           {
-             rtx pat = PATTERN (insn);
-             int i;
-
-             if (GET_CODE (pat) == PARALLEL)
-               {
-                 int len = XVECLEN (pat, 0);
-                 int has_use_labelref = 0;
-
-                 for (i = len - 1; i >= 0; i--)
-                   if (GET_CODE (XVECEXP (pat, 0, i)) == USE
-                       && (GET_CODE (XEXP (XVECEXP (pat, 0, i), 0))
-                           == LABEL_REF))
-                     {
-                       nr_edges++;
-                       has_use_labelref = 1;
-                     }
-
-                 if (!has_use_labelref)
-                   for (i = len - 1; i >= 0; i--)
-                     if (GET_CODE (XVECEXP (pat, 0, i)) == SET
-                         && SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx
-                         && uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))
-                       {
-                         return 1;
-                       }
-               }
-             /* check for branch table */
-             else if (GET_CODE (pat) == ADDR_VEC
-                      || GET_CODE (pat) == ADDR_DIFF_VEC)
-               {
-                 int diff_vec_p = GET_CODE (pat) == ADDR_DIFF_VEC;
-                 int len = XVECLEN (pat, diff_vec_p);
-
-                 nr_edges += len;
-               }
-             else
-               {
-                 /* check for computed branch */
-                 if (GET_CODE (pat) == SET
-                     && SET_DEST (pat) == pc_rtx
-                     && uses_reg_or_mem (SET_SRC (pat)))
-                   {
-                     return 1;
-                   }
-               }
-           }
+         if (computed_jump_p (insn))
+           return 1;
 
          if (insn == basic_block_end[b])
            break;
        }
     }
 
-  /* count for the fallthrough edges */
-  for (b = 0; b < n_basic_blocks; b++)
-    {
-      for (insn = PREV_INSN (basic_block_head[b]);
-          insn && GET_CODE (insn) == NOTE; insn = PREV_INSN (insn))
-       ;
-
-      if (!insn && b != 0)
-       nr_edges++;
-      else if (insn && GET_CODE (insn) != BARRIER)
-       nr_edges++;
-    }
-
-  nr_edges++;
-
-  return 0;
-}
-
-
-/* Returns 1 if x uses a reg or a mem (function was taken from flow.c).
-   x is a target of a jump. Used for the detection of computed
-   branches. For each label seen, updates the edges estimation
-   counter nr_edges.  */
-
-static int
-uses_reg_or_mem (x)
-     rtx x;
-{
-  enum rtx_code code = GET_CODE (x);
-  int i, j;
-  char *fmt;
-
-  if (code == REG)
-    return 1;
-
-  if (code == MEM
-      && !(GET_CODE (XEXP (x, 0)) == SYMBOL_REF
-          && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))))
-    return 1;
-
-  if (code == IF_THEN_ELSE)
-    {
-      if (uses_reg_or_mem (XEXP (x, 1))
-         || uses_reg_or_mem (XEXP (x, 2)))
-       return 1;
-      else
-       return 0;
-    }
-
-  if (code == LABEL_REF)
-    {
-      nr_edges++;
-
-      return 0;
-    }
-
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      if (fmt[i] == 'e'
-         && uses_reg_or_mem (XEXP (x, i)))
-       return 1;
-
-      if (fmt[i] == 'E')
-       for (j = 0; j < XVECLEN (x, i); j++)
-         if (uses_reg_or_mem (XVECEXP (x, i, j)))
-           return 1;
-    }
-
+  /* All the tests passed.  Consider the cfg well structured.  */
   return 0;
 }
 
-
 /* Print the control flow graph, for debugging purposes.
    Callable from the debugger.  */
 
@@ -1312,9 +1190,12 @@ debug_control_flow ()
 /* Build the control flow graph and set nr_edges.
 
    Instead of trying to build a cfg ourselves, we rely on flow to
-   do it for us.  Stamp out useless code (and bug) duplication.  */
+   do it for us.  Stamp out useless code (and bug) duplication.
 
-static void
+   Return nonzero if an irregularity in the cfg is found which would
+   prevent cross block scheduling.  */
+
+static int
 build_control_flow ()
 {
   int i, j;
@@ -1323,6 +1204,7 @@ build_control_flow ()
   int_list_ptr succ;
   int *num_preds;
   int *num_succs;
+  int unreachable;
 
   /* The scheduler runs after flow; therefore, we can't blindly call
      back into find_basic_blocks since doing so could invalidate the
@@ -1341,6 +1223,27 @@ build_control_flow ()
   num_succs = (int *) alloca (n_basic_blocks * sizeof (int));
   compute_preds_succs (s_preds, s_succs, num_preds, num_succs);
 
+  /* Count the number of edges in the cfg.  */
+  nr_edges = 0;
+  unreachable = 0;
+  for (i = 0; i < n_basic_blocks; i++)
+    {
+      nr_edges += num_succs[i];
+      if (num_preds[i] == 0)
+       unreachable = 1;
+    }
+
+  /* Account for entry/exit edges.  */
+  nr_edges += 2;
+
+  in_edges = (int *) xmalloc (n_basic_blocks * sizeof (int));
+  out_edges = (int *) xmalloc (n_basic_blocks * sizeof (int));
+  bzero ((char *) in_edges, n_basic_blocks * sizeof (int));
+  bzero ((char *) out_edges, n_basic_blocks * sizeof (int));
+
+  edge_table = (edge *) xmalloc ((nr_edges) * sizeof (edge));
+  bzero ((char *) edge_table, ((nr_edges) * sizeof (edge)));
+
   nr_edges = 0;
   for (i = 0; i < n_basic_blocks; i++)
     for (succ = s_succs[i]; succ; succ = succ->next)
@@ -1355,6 +1258,7 @@ build_control_flow ()
   /* For now.  This will move as more and more of haifa is converted
      to using the cfg code in flow.c  */
   free_bb_mem ();
+  return unreachable;
 }
 
 
@@ -1627,7 +1531,6 @@ find_rgns ()
   int count = 0, sp, idx = 0, current_edge = out_edges[0];
   int num_bbs, num_insns;
   int too_large_failure;
-  char *reachable;
 
   /*
      The following data structures are computed by the first traversal and
@@ -1664,8 +1567,6 @@ find_rgns ()
   bzero ((char *) passed, nr_edges * sizeof (char));
   in_stack = (char *) alloca (nr_edges * sizeof (char));
   bzero ((char *) in_stack, nr_edges * sizeof (char));
-  reachable = (char *) alloca (n_basic_blocks * sizeof (char));
-  bzero ((char *) reachable, n_basic_blocks * sizeof (char));
 
   in_queue = (char *) alloca (n_basic_blocks * sizeof (char));
 
@@ -1677,7 +1578,6 @@ find_rgns ()
 
   /* First traversal: DFS, finds inner loops in control flow graph */
 
-  reachable[0] = 1;
   sp = -1;
   while (1)
     {
@@ -1711,7 +1611,6 @@ find_rgns ()
       dfs_nr[node] = ++count;
       in_stack[node] = 1;
       child = TO_BLOCK (current_edge);
-      reachable[child] = 1;
 
       /* found a loop header */
       if (in_stack[child])
@@ -1742,19 +1641,6 @@ find_rgns ()
       current_edge = OUT_EDGES (child);
     }                          /* while (1); */
 
-  /* if there are unreachable blocks, or more than one entry to
-     the subroutine, give up on interblock scheduling */
-  for (i = 1; i < n_basic_blocks; i++)
-    {
-      if (reachable[i] == 0)
-       {
-         find_single_block_region ();
-         if (sched_verbose >= 3)
-           fprintf (stderr, "sched: warning: found an unreachable block %d \n", i);
-         return;
-       }
-    }
-
   /* Second travsersal: find reducible inner loops, and sort
      topologically the blocks of each region */
   degree = dfs_nr;             /* reuse dfs_nr array - it is not needed anymore */
@@ -8547,31 +8433,20 @@ schedule_insns (dump_file)
     }
   else
     {
-      /* an estimation for nr_edges is computed in is_cfg_nonregular () */
-      nr_edges = 0;
-
       /* verify that a 'good' control flow graph can be built */
-      if (is_cfg_nonregular ()
-         || nr_edges <= 1)
+      if (is_cfg_nonregular ())
        {
          find_single_block_region ();
        }
       else
        {
-         /* build control flow graph */
-         in_edges = (int *) alloca (n_basic_blocks * sizeof (int));
-         out_edges = (int *) alloca (n_basic_blocks * sizeof (int));
-         bzero ((char *) in_edges, n_basic_blocks * sizeof (int));
-         bzero ((char *) out_edges, n_basic_blocks * sizeof (int));
-
-         edge_table =
-           (edge *) alloca ((nr_edges) * sizeof (edge));
-         bzero ((char *) edge_table,
-                ((nr_edges) * sizeof (edge)));
-         build_control_flow ();
-
-         /* identify reducible inner loops and compute regions */
-         find_rgns ();
+         /* build_control_flow will return nonzero if it detects unreachable
+            blocks or any other irregularity with the cfg which prevents
+            cross block scheduling.  */
+         if (build_control_flow () != 0)
+           find_single_block_region ();
+         else
+           find_rgns ();
 
          if (sched_verbose >= 3)
            {
@@ -8711,5 +8586,22 @@ schedule_insns (dump_file)
 
   if (bb_live_regs)
     FREE_REG_SET (bb_live_regs);
+
+  if (edge_table)
+    {
+      free (edge_table);
+      edge_table = NULL;
+    }
+
+  if (in_edges)
+    {
+      free (in_edges);
+      in_edges = NULL;
+    }
+  if (out_edges)
+    {
+      free (out_edges);
+      out_edges = NULL;
+    }
 }
 #endif /* INSN_SCHEDULING */