]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
flow.c (find_basic_blocks): Refine further to get a more correct cfg...
authorJeffrey A Law <law@cygnus.com>
Wed, 12 Nov 1997 16:35:41 +0000 (16:35 +0000)
committerJeff Law <law@gcc.gnu.org>
Wed, 12 Nov 1997 16:35:41 +0000 (09:35 -0700)
        * flow.c (find_basic_blocks): Refine further to get a more correct
        cfg, especially in the presense of exception handling, computed
        gotos, and other non-trivial cases.  Call abort if an inaccuracy
        is detected in the cfg.

From-SVN: r16439

gcc/ChangeLog
gcc/flow.c

index 6cd456713127beeb347c29f41dc6bfe314cc97f0..8c32523e9290703eff1135a9dac809fa6a17defe 100644 (file)
@@ -1,3 +1,10 @@
+Wed Nov 12 09:37:01 1997  Jeffrey A Law  (law@cygnus.com)
+
+       * flow.c (find_basic_blocks): Refine further to get a more correct
+       cfg, especially in the presense of exception handling, computed
+       gotos, and other non-trivial cases.  Call abort if an inaccuracy
+       is detected in the cfg.
+
 Mon Nov 10 03:02:19 1997  Jason Merrill  <jason@yorick.cygnus.com>
 
        * stmt.c (expand_decl_cleanup_no_eh): New fn.
index e2c548db2fa50f8f1fed6b1456043ff37da52fdc..8c5e7e6a16850e2eaa0b6fa21fef79ec8cc96b1c 100644 (file)
@@ -372,22 +372,28 @@ find_basic_blocks (f, nonlocal_label_list)
   register int i;
   register char *block_live = (char *) alloca (n_basic_blocks);
   register char *block_marked = (char *) alloca (n_basic_blocks);
+  /* An array of CODE_LABELs, indexed by UID for the start of the active
+     EH handler for each insn in F.  */
+  rtx *active_eh_handler;
   /* List of label_refs to all labels whose addresses are taken
      and used as data.  */
   rtx label_value_list;
-  int label_value_list_marked_live;
-  rtx x, note;
+  /* List of label_refs from REG_LABEL notes.  */
+  rtx reg_label_list;
+  rtx x, note, eh_note;
   enum rtx_code prev_code, code;
   int depth, pass;
 
   pass = 1;
+  active_eh_handler = (rtx *) alloca ((max_uid_for_flow + 1) * sizeof (rtx));
  restart:
 
   label_value_list = 0;
-  label_value_list_marked_live = 0;
+  reg_label_list = 0;
   block_live_static = block_live;
   bzero (block_live, n_basic_blocks);
   bzero (block_marked, n_basic_blocks);
+  bzero (active_eh_handler, (max_uid_for_flow + 1) * sizeof (rtx));
 
   /* Initialize with just block 0 reachable and no blocks marked.  */
   if (n_basic_blocks > 0)
@@ -398,7 +404,7 @@ find_basic_blocks (f, nonlocal_label_list)
      the block it is in.   Also mark as reachable any blocks headed by labels
      that must not be deleted.  */
 
-  for (insn = f, i = -1, prev_code = JUMP_INSN, depth = 1;
+  for (eh_note = NULL_RTX, insn = f, i = -1, prev_code = JUMP_INSN, depth = 1;
        insn; insn = NEXT_INSN (insn))
     {
       code = GET_CODE (insn);
@@ -448,6 +454,35 @@ find_basic_blocks (f, nonlocal_label_list)
                                          label_value_list);
        }
 
+      /* Keep a lifo list of the currently active exception handlers.  */
+      if (GET_CODE (insn) == NOTE)
+       {
+         if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+           {
+             for (x = exception_handler_labels; x; x = XEXP (x, 1))
+               if (CODE_LABEL_NUMBER (XEXP (x, 0)) == NOTE_BLOCK_NUMBER (insn))
+                 {
+                   eh_note = gen_rtx (EXPR_LIST, VOIDmode,
+                                      XEXP (x, 0), eh_note);
+                   break;
+                 }
+             if (x == NULL_RTX)
+               abort ();
+           }
+         else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+           eh_note = XEXP (eh_note, 1);
+       }
+      /* If we encounter a CALL_INSN, note which exception handler it
+        might pass control to.
+
+        If doing asynchronous exceptions, record the active EH handler
+        for every insn, since most insns can throw.  */
+      else if (eh_note
+              && (asynchronous_exceptions
+                  || (GET_CODE (insn) == CALL_INSN
+                      && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))))
+       active_eh_handler[INSN_UID (insn)] = XEXP (eh_note, 0);
+
       BLOCK_NUM (insn) = i;
 
       if (code != NOTE)
@@ -461,14 +496,6 @@ find_basic_blocks (f, nonlocal_label_list)
     abort ();
   n_basic_blocks = i + 1;
 
-  for (x = forced_labels; x; x = XEXP (x, 1))
-    if (! LABEL_REF_NONLOCAL_P (x))
-      block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
-
-  if (asynchronous_exceptions)
-    for (x = exception_handler_labels; x; x = XEXP (x, 1))
-      block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
-
   /* Record which basic blocks control can drop in to.  */
 
   for (i = 0; i < n_basic_blocks; i++)
@@ -489,91 +516,6 @@ find_basic_blocks (f, nonlocal_label_list)
       int something_marked = 1;
       int deleted;
 
-      /* Find all indirect jump insns and mark them as possibly jumping to all
-        the labels whose addresses are explicitly used.  This is because,
-        when there are computed gotos, we can't tell which labels they jump
-        to, of all the possibilities.  */
-
-      for (insn = f; insn; insn = NEXT_INSN (insn))
-       if (computed_jump_p (insn))
-         {
-           if (label_value_list_marked_live == 0)
-             {
-               label_value_list_marked_live = 1;
-
-               /* This could be made smarter by only considering
-                  these live, if the computed goto is live.  */
-
-               /* Don't delete the labels (in this function) that
-                  are referenced by non-jump instructions.  */
-
-               for (x = label_value_list; x; x = XEXP (x, 1))
-                 if (! LABEL_REF_NONLOCAL_P (x))
-                   block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
-             }
-
-           for (x = label_value_list; x; x = XEXP (x, 1))
-             mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
-                             insn, 0);
-
-           for (x = forced_labels; x; x = XEXP (x, 1))
-             mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
-                             insn, 0);
-         }
-
-      /* Find all call insns and mark them as possibly jumping
-        to all the nonlocal goto handler labels, or to the current
-        exception handler.  */
-
-      for (note = NULL_RTX, insn = f; insn; insn = NEXT_INSN (insn))
-       {
-         if (! asynchronous_exceptions && GET_CODE (insn) == NOTE)
-           {
-             if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
-               {
-                 for (x = exception_handler_labels; x; x = XEXP (x, 1))
-                   if (CODE_LABEL_NUMBER (XEXP (x, 0))
-                       == NOTE_BLOCK_NUMBER (insn))
-                     {
-                       note = gen_rtx (EXPR_LIST, VOIDmode,
-                                        XEXP (x, 0), note);
-                       break;
-                     }
-                 if (x == NULL_RTX)
-                   abort ();
-               }
-             else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
-               note = XEXP (note, 1);
-           }
-         else if (GET_CODE (insn) == CALL_INSN
-                  && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
-           {
-             if (note)
-               mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (note, 0)),
-                               insn, 0);
-
-             for (x = nonlocal_label_list; x; x = XEXP (x, 1))
-               mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
-                               insn, 0);
-           /* ??? This could be made smarter:
-              in some cases it's possible to tell that certain
-              calls will not do a nonlocal goto.
-
-              For example, if the nested functions that do the
-              nonlocal gotos do not have their addresses taken, then
-              only calls to those functions or to other nested
-              functions that use them could possibly do nonlocal
-              gotos.  */
-           }
-       }
-
-      /* All blocks associated with labels in label_value_list are
-        trivially considered as marked live, if the list is empty.
-        We do this to speed up the below code.  */
-
-      if (label_value_list == 0)
-       label_value_list_marked_live = 1;
-
       /* Pass over all blocks, marking each block that is reachable
         and has not yet been marked.
         Keep doing this until, in one pass, no blocks have been marked.
@@ -594,43 +536,130 @@ find_basic_blocks (f, nonlocal_label_list)
                if (GET_CODE (insn) == JUMP_INSN)
                  mark_label_ref (PATTERN (insn), insn, 0);
 
-               if (label_value_list_marked_live == 0)
-                 /* Now that we know that this block is live, mark as
-                    live, all the blocks that we might be able to get
-                    to as live.  */
-
-                 for (insn = basic_block_head[i];
-                      insn != NEXT_INSN (basic_block_end[i]);
-                      insn = NEXT_INSN (insn))
-                   {
-                     if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
-                       {
-                         for (note = REG_NOTES (insn);
-                              note;
-                              note = XEXP (note, 1))
+               /* If we have any forced labels, mark them as potentially
+                  reachable from this block.  */
+               for (x = forced_labels; x; x = XEXP (x, 1))
+                 if (! LABEL_REF_NONLOCAL_P (x))
+                   mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
+                                   insn, 0);
+
+               /* Now scan the insns for this block, we may need to make
+                  edges for some of them to various non-obvious locations
+                  (exception handlers, nonlocal labels, etc).  */
+               for (insn = basic_block_head[i];
+                    insn != NEXT_INSN (basic_block_end[i]);
+                    insn = NEXT_INSN (insn))
+                 {
+                   if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+                     {
+                       
+                       /* We have no idea where the label referenced by this
+                          insn will actually be used.
+
+                          To create an accurate cfg we mark the target blocks
+                          as live and create a list of all the labels
+                          mentioned in REG_LABEL notes.  After we're done
+                          marking blocks, we go back and create an edge from
+                          every live block to labels on the list.  */ 
+                       for (note = REG_NOTES (insn);
+                            note;
+                            note = XEXP (note, 1))
+                         {
                            if (REG_NOTE_KIND (note) == REG_LABEL)
                              {
                                x = XEXP (note, 0);
                                block_live[BLOCK_NUM (x)] = 1;
+                               reg_label_list
+                                 = gen_rtx (EXPR_LIST, VOIDmode, x,
+                                            reg_label_list);
                              }
-                       }
-                   }
+                         }
+
+                       /* If this is a computed jump, then mark it as
+                          reaching everything on the label_value_list
+                          and forced_labels list.  */
+                       if (computed_jump_p (insn))
+                         {
+                           for (x = label_value_list; x; x = XEXP (x, 1))
+                             mark_label_ref (gen_rtx (LABEL_REF, VOIDmode,
+                                                      XEXP (x, 0)),
+                                             insn, 0);
+
+                           for (x = forced_labels; x; x = XEXP (x, 1))
+                             mark_label_ref (gen_rtx (LABEL_REF, VOIDmode,
+                                                      XEXP (x, 0)),
+                                             insn, 0);
+                           }
+
+                       /* If this is a CALL_INSN, then mark it as reaching
+                          the active EH handler for this CALL_INSN.  If
+                          we're handling asynchronous exceptions mark every
+                          insn as reaching the active EH handler.
+
+                          Also mark the CALL_INSN as reaching any nonlocal
+                          goto sites.  */
+                       else if (asynchronous_exceptions
+                                || (GET_CODE (insn) == CALL_INSN
+                                    && ! find_reg_note (insn, REG_RETVAL,
+                                                        NULL_RTX)))
+                         {
+                           if (active_eh_handler[INSN_UID (insn)])
+                             mark_label_ref (gen_rtx (LABEL_REF, VOIDmode,
+                                                      active_eh_handler[INSN_UID (insn)]),
+                                             insn, 0);
+
+                           if (!asynchronous_exceptions)
+                             {
+                               for (x = nonlocal_label_list;
+                                    x;
+                                    x = XEXP (x, 1))
+                                 mark_label_ref (gen_rtx (LABEL_REF, VOIDmode,
+                                                          XEXP (x, 0)),
+                                                 insn, 0);
+                             }
+                           /* ??? This could be made smarter:
+                              in some cases it's possible to tell that
+                              certain calls will not do a nonlocal goto.
+
+                              For example, if the nested functions that
+                              do the nonlocal gotos do not have their
+                              addresses taken, then only calls to those
+                              functions or to other nested functions that
+                              use them could possibly do nonlocal gotos.  */
+                         }
+                     }
+                 }
              }
        }
 
-      /* ??? See if we have a "live" basic block that is not reachable.
-        This can happen if it is headed by a label that is preserved or
-        in one of the label lists, but no call or computed jump is in
-        the loop.  It's not clear if we can delete the block or not,
-        but don't for now.  However, we will mess up register status if
-        it remains unreachable, so add a fake reachability from the
-        previous block.  */
+      /* We couldn't determine what edges are needed for labels on the
+        reg_label_list above.  So make an edge from every live block to
+        to every label on the reg_label_list.  */
+      if (reg_label_list)
+       {
+         for (i = 1; i < n_basic_blocks; i++)
+         if (block_live[i])
+           {
+             rtx x;
+
+             for (x = reg_label_list; x; x = XEXP (x, 1))
+               mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
+                               basic_block_end[i], 0);
+           }
+       }
+
+      /* This should never happen.  If it does that means we've computed an
+        incorrect flow graph, which can lead to aborts/crashes later in the
+        compiler or incorrect code generation.
 
+        We used to try and continue here, but that's just asking for trouble
+        later during the compile or at runtime.  It's easier to debug the
+        problem here than later!  */
       for (i = 1; i < n_basic_blocks; i++)
        if (block_live[i] && ! basic_block_drops_in[i]
            && GET_CODE (basic_block_head[i]) == CODE_LABEL
            && LABEL_REFS (basic_block_head[i]) == basic_block_head[i])
-         basic_block_drops_in[i] = 1;
+         abort ();
 
       /* Now delete the code for any basic blocks that can't be reached.
         They can occur because jump_optimize does not recognize