OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / cfgbuild.c
index 2f62b06..ef86939 100644 (file)
@@ -55,6 +55,8 @@ static void make_edges                        PARAMS ((rtx, int, int, int));
 static void make_label_edge            PARAMS ((sbitmap *, basic_block,
                                                 rtx, int));
 static void make_eh_edge               PARAMS ((sbitmap *, basic_block, rtx));
+static void find_bb_boundaries         PARAMS ((basic_block));
+static void compute_outgoing_frequencies PARAMS ((basic_block));
 
 /* Count the basic blocks of the function.  */
 
@@ -62,9 +64,9 @@ static int
 count_basic_blocks (f)
      rtx f;
 {
-  register rtx insn;
-  register RTX_CODE prev_code;
-  register int count = 0;
+  rtx insn;
+  RTX_CODE prev_code;
+  int count = 0;
   int saw_abnormal_edge = 0;
 
   prev_code = JUMP_INSN;
@@ -186,7 +188,7 @@ make_label_edge (edge_cache, src, label, flags)
   if (INSN_UID (label) == 0)
     return;
 
-  make_edge (edge_cache, src, BLOCK_FOR_INSN (label), flags);
+  cached_make_edge (edge_cache, src, BLOCK_FOR_INSN (label), flags);
 }
 
 /* Create the edges generated by INSN in REGION.  */
@@ -246,7 +248,8 @@ make_edges (label_value_list, min, max, update_p)
     }
 
   /* By nature of the way these get numbered, block 0 is always the entry.  */
-  make_edge (edge_cache, ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU);
+  if (min == 0)
+    cached_make_edge (edge_cache, ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU);
 
   for (i = min; i <= max; ++i)
     {
@@ -257,7 +260,7 @@ make_edges (label_value_list, min, max, update_p)
 
       if (GET_CODE (bb->head) == CODE_LABEL
          && LABEL_ALTERNATE_NAME (bb->head))
-       make_edge (NULL, ENTRY_BLOCK_PTR, bb, 0);
+       cached_make_edge (NULL, ENTRY_BLOCK_PTR, bb, 0);
 
       /* Examine the last instruction of the block, and discover the
         ways we can leave the block.  */
@@ -330,7 +333,7 @@ make_edges (label_value_list, min, max, update_p)
 
          /* Returns create an exit out.  */
          else if (returnjump_p (insn))
-           make_edge (edge_cache, bb, EXIT_BLOCK_PTR, 0);
+           cached_make_edge (edge_cache, bb, EXIT_BLOCK_PTR, 0);
 
          /* Otherwise, we have a plain conditional or unconditional jump.  */
          else
@@ -347,7 +350,7 @@ make_edges (label_value_list, min, max, update_p)
         wouldn't have created the sibling call in the first place.  */
 
       if (code == CALL_INSN && SIBLING_CALL_P (insn))
-       make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
+       cached_make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
                   EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
 
       /* If this is a CALL_INSN, then mark it as reaching the active EH
@@ -383,14 +386,14 @@ make_edges (label_value_list, min, max, update_p)
       /* Find out if we can drop through to the next block.  */
       insn = next_nonnote_insn (insn);
       if (!insn || (i + 1 == n_basic_blocks && force_fallthru))
-       make_edge (edge_cache, bb, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
+       cached_make_edge (edge_cache, bb, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
       else if (i + 1 < n_basic_blocks)
        {
          rtx tmp = BLOCK_HEAD (i + 1);
          if (GET_CODE (tmp) == NOTE)
            tmp = next_nonnote_insn (tmp);
          if (force_fallthru || insn == tmp)
-           make_edge (edge_cache, bb, BASIC_BLOCK (i + 1), EDGE_FALLTHRU);
+           cached_make_edge (edge_cache, bb, BASIC_BLOCK (i + 1), EDGE_FALLTHRU);
        }
     }
 
@@ -407,7 +410,7 @@ static void
 find_basic_blocks_1 (f)
      rtx f;
 {
-  register rtx insn, next;
+  rtx insn, next;
   int i = 0;
   rtx bb_note = NULL_RTX;
   rtx lvl = NULL_RTX;
@@ -442,7 +445,7 @@ find_basic_blocks_1 (f)
                if (bb_note == NULL_RTX)
                  bb_note = insn;
                else
-                 next = flow_delete_insn (insn);
+                 next = delete_insn (insn);
              }
            break;
          }
@@ -452,7 +455,7 @@ find_basic_blocks_1 (f)
             to a barrier or some such, no need to do it again.  */
          if (head != NULL_RTX)
            {
-             create_basic_block (i++, head, end, bb_note);
+             create_basic_block_structure (i++, head, end, bb_note);
              bb_note = NULL_RTX;
            }
 
@@ -523,7 +526,7 @@ find_basic_blocks_1 (f)
                end = insn;
 
              new_bb_exclusive:
-               create_basic_block (i++, head, end, bb_note);
+               create_basic_block_structure (i++, head, end, bb_note);
                head = end = NULL_RTX;
                bb_note = NULL_RTX;
                break;
@@ -579,9 +582,9 @@ find_basic_blocks_1 (f)
     }
 
   if (head != NULL_RTX)
-    create_basic_block (i++, head, end, bb_note);
+    create_basic_block_structure (i++, head, end, bb_note);
   else if (bb_note)
-    flow_delete_insn (bb_note);
+    delete_insn (bb_note);
 
   if (i != n_basic_blocks)
     abort ();
@@ -604,6 +607,8 @@ find_basic_blocks (f, nregs, file)
   int max_uid;
   timevar_push (TV_CFG);
 
+  basic_block_for_insn = 0;
+
   /* Flush out existing data.  */
   if (basic_block_info != NULL)
     {
@@ -655,26 +660,33 @@ find_basic_blocks (f, nregs, file)
      here and cleanup_cfg, e.g. thread_prologue_and_epilogue_insns.  */
   tidy_fallthru_edges ();
 
-  mark_critical_edges ();
-
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
 #endif
   timevar_pop (TV_CFG);
 }
 \f
-/* Assume that someone emitted code with control flow instructions to the
-   basic block.  Update the data structure.  */
-void
-find_sub_basic_blocks (bb)
+/* State of basic block as seen by find_sub_basic_blocks.  */
+enum state
+  {
+    BLOCK_NEW = 0,
+    BLOCK_ORIGINAL,
+    BLOCK_TO_SPLIT
+  };
+#define STATE(bb) (enum state)(size_t)(bb)->aux
+#define SET_STATE(bb, state) (bb)->aux = (void *)(state)
+
+/* Scan basic block BB for possible BB boundaries inside the block
+   and create new basic blocks in the progress.  */
+
+static void
+find_bb_boundaries (bb)
      basic_block bb;
 {
   rtx insn = bb->head;
   rtx end = bb->end;
-  rtx jump_insn = NULL_RTX;
-  edge falltru = 0;
-  basic_block first_bb = bb;
-  int i;
+  rtx flow_transfer_insn = NULL_RTX;
+  edge fallthru = NULL;
 
   if (insn == bb->end)
     return;
@@ -686,44 +698,66 @@ find_sub_basic_blocks (bb)
   while (1)
     {
       enum rtx_code code = GET_CODE (insn);
+
       switch (code)
        {
        case BARRIER:
-         if (!jump_insn)
+         if (!flow_transfer_insn)
            abort ();
          break;
-       /* On code label, split current basic block.  */
+
+         /* On code label, split current basic block.  */
        case CODE_LABEL:
-         falltru = split_block (bb, PREV_INSN (insn));
-         if (jump_insn)
-           bb->end = jump_insn;
-         bb = falltru->dest;
-         remove_edge (falltru);
-         jump_insn = 0;
+         fallthru = split_block (bb, PREV_INSN (insn));
+         if (flow_transfer_insn)
+           bb->end = flow_transfer_insn;
+         bb = fallthru->dest;
+         remove_edge (fallthru);
+         flow_transfer_insn = NULL_RTX;
          if (LABEL_ALTERNATE_NAME (insn))
-           make_edge (NULL, ENTRY_BLOCK_PTR, bb, 0);
+           make_edge (ENTRY_BLOCK_PTR, bb, 0);
          break;
+
        case INSN:
        case JUMP_INSN:
-         /* In case we've previously split insn on the JUMP_INSN, move the
-            block header to proper place.  */
-         if (jump_insn)
+       case CALL_INSN:
+         /* In case we've previously split an insn that effects a control
+            flow transfer, move the block header to proper place.  */
+         if (flow_transfer_insn)
            {
-             falltru = split_block (bb, PREV_INSN (insn));
-             bb->end = jump_insn;
-             bb = falltru->dest;
-             remove_edge (falltru);
-             jump_insn = 0;
+             fallthru = split_block (bb, PREV_INSN (insn));
+             bb->end = flow_transfer_insn;
+             bb = fallthru->dest;
+             remove_edge (fallthru);
+             flow_transfer_insn = NULL_RTX;
            }
+
          /* We need some special care for those expressions.  */
-         if (GET_CODE (insn) == JUMP_INSN)
+         if (code == JUMP_INSN)
            {
              if (GET_CODE (PATTERN (insn)) == ADDR_VEC
                  || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
-               abort();
-             jump_insn = insn;
+               abort ();
+             flow_transfer_insn = insn;
+           }
+         else if (code == CALL_INSN)
+           {
+             rtx note;
+             if (nonlocal_goto_handler_labels
+                 && (!(note = find_reg_note (insn, REG_EH_REGION, NULL_RTX))
+                     || INTVAL (XEXP (note, 0)) >= 0))
+               flow_transfer_insn = insn;
+             else if (can_throw_internal (insn))
+               flow_transfer_insn = insn;
+             else if (SIBLING_CALL_P (insn))
+               flow_transfer_insn = insn;
+             else if (find_reg_note (insn, REG_NORETURN, 0))
+               flow_transfer_insn = insn;
            }
+         else if (flag_non_call_exceptions && can_throw_internal (insn))
+           flow_transfer_insn = insn;
          break;
+
        default:
          break;
        }
@@ -735,25 +769,94 @@ find_sub_basic_blocks (bb)
   /* In case expander replaced normal insn by sequence terminating by
      return and barrier, or possibly other sequence not behaving like
      ordinary jump, we need to take care and move basic block boundary.  */
-  if (jump_insn && GET_CODE (bb->end) != JUMP_INSN)
-    bb->end = jump_insn;
+  if (flow_transfer_insn)
+    bb->end = flow_transfer_insn;
 
   /* We've possibly replaced the conditional jump by conditional jump
      followed by cleanup at fallthru edge, so the outgoing edges may
      be dead.  */
   purge_dead_edges (bb);
+}
+
+/*  Assume that frequency of basic block B is known.  Compute frequencies
+    and probabilities of outgoing edges.  */
+
+static void
+compute_outgoing_frequencies (b)
+     basic_block b;
+{
+  edge e, f;
+  if (b->succ && b->succ->succ_next && !b->succ->succ_next->succ_next)
+    {
+      rtx note = find_reg_note (b->end, REG_BR_PROB, NULL);
+      int probability;
+
+      if (!note)
+       return;
+      probability = INTVAL (XEXP (find_reg_note (b->end,
+                                                REG_BR_PROB, NULL), 0));
+      e = BRANCH_EDGE (b);
+      e->probability = probability;
+      e->count = ((b->count * probability + REG_BR_PROB_BASE / 2)
+                 / REG_BR_PROB_BASE);
+      f = FALLTHRU_EDGE (b);
+      f->probability = REG_BR_PROB_BASE - probability;
+      f->count = b->count - e->count;
+    }
+  if (b->succ && !b->succ->succ_next)
+    {
+      e = b->succ;
+      e->probability = REG_BR_PROB_BASE;
+      e->count = b->count;
+    }
+}
+
+/* Assume that someone emitted code with control flow instructions to the
+   basic block.  Update the data structure.  */
+
+void
+find_many_sub_basic_blocks (blocks)
+     sbitmap blocks;
+{
+  int i;
+  int min, max;
+
+  for (i = 0; i < n_basic_blocks; i++)
+    {
+      SET_STATE (BASIC_BLOCK (i),
+                TEST_BIT (blocks, i)
+                ? BLOCK_TO_SPLIT : BLOCK_ORIGINAL);
+    }
+
+  for (i = 0; i < n_basic_blocks; i++)
+    {
+      basic_block bb = BASIC_BLOCK (i);
+      if (STATE (bb) == BLOCK_TO_SPLIT)
+       find_bb_boundaries (bb);
+    }
+
+  for (i = 0; i < n_basic_blocks; i++)
+    if (STATE (BASIC_BLOCK (i)) != BLOCK_ORIGINAL)
+      break;
+  min = max = i;
+  for (; i < n_basic_blocks; i++)
+    if (STATE (BASIC_BLOCK (i)) != BLOCK_ORIGINAL)
+      max = i;
 
   /* Now re-scan and wire in all edges.  This expect simple (conditional)
      jumps at the end of each new basic blocks.  */
-  make_edges (NULL, first_bb->index, bb->index, 1);
+  make_edges (NULL, min, max, 1);
 
   /* Update branch probabilities.  Expect only (un)conditional jumps
      to be created with only the forward edges.  */
-  for (i = first_bb->index; i <= bb->index; i++)
+  for (i = min; i <= max; i++)
     {
-      edge e,f;
+      edge e;
       basic_block b = BASIC_BLOCK (i);
-      if (b != first_bb)
+
+      if (STATE (b) == BLOCK_ORIGINAL)
+       continue;
+      if (STATE (b) == BLOCK_NEW)
        {
          b->count = 0;
          b->frequency = 0;
@@ -763,29 +866,48 @@ find_sub_basic_blocks (bb)
              b->frequency += EDGE_FREQUENCY (e);
            }
        }
-      if (b->succ && b->succ->succ_next && !b->succ->succ_next->succ_next)
-       {
-         rtx note = find_reg_note (b->end, REG_BR_PROB, NULL);
-         int probability;
-
-         if (!note)
-           continue;
-         probability = INTVAL (XEXP (find_reg_note (b->end,
-                                                    REG_BR_PROB,
-                                                    NULL), 0));
-         e = BRANCH_EDGE (b);
-         e->probability = probability;
-         e->count = ((b->count * probability + REG_BR_PROB_BASE / 2)
-                     / REG_BR_PROB_BASE);
-         f = FALLTHRU_EDGE (b);
-         f->probability = REG_BR_PROB_BASE - probability;
-         f->count = b->count - e->count;
-       }
-      if (b->succ && !b->succ->succ_next)
+      compute_outgoing_frequencies (b);
+    }
+  for (i = 0; i < n_basic_blocks; i++)
+    SET_STATE (BASIC_BLOCK (i), 0);
+}
+
+/* Like above but for single basic block only.  */
+
+void
+find_sub_basic_blocks (bb)
+    basic_block bb;
+{
+  int i;
+  int min, max;
+  basic_block next = (bb->index == n_basic_blocks - 1
+                     ? NULL : BASIC_BLOCK (bb->index + 1));
+
+  min = bb->index;
+  find_bb_boundaries (bb);
+  max = (next ? next->index : n_basic_blocks) - 1;
+
+  /* Now re-scan and wire in all edges.  This expect simple (conditional)
+     jumps at the end of each new basic blocks.  */
+  make_edges (NULL, min, max, 1);
+
+  /* Update branch probabilities.  Expect only (un)conditional jumps
+     to be created with only the forward edges.  */
+  for (i = min; i <= max; i++)
+    {
+      edge e;
+      basic_block b = BASIC_BLOCK (i);
+
+      if (i != min)
        {
-         e = b->succ;
-         e->probability = REG_BR_PROB_BASE;
-         e->count = b->count;
+         b->count = 0;
+         b->frequency = 0;
+         for (e = b->pred; e; e=e->pred_next)
+           {
+             b->count += e->count;
+             b->frequency += EDGE_FREQUENCY (e);
+           }
        }
+      compute_outgoing_frequencies (b);
     }
 }