OSDN Git Service

* loop.c (try_copy_prop); Kill invalidated REG_EQUAL notes.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 4 Aug 2001 12:08:43 +0000 (12:08 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 4 Aug 2001 12:08:43 +0000 (12:08 +0000)
* reload1.c (fixup_abnormal_edges): New static function.
(reload): Use it.

* flow.c (need_fake_edge_p): New function.
(flow_call_edges_add): Fix handling of noreturn and sibbling calls;
avoid call insn to be very last insn in the insn stream.

* profile.c (branch_prob): Call flow_call_edges_add instead of
doing that by hand; cleanup cfg to re-merge basic blocks once
we are done.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@44635 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/flow.c
gcc/loop.c
gcc/profile.c
gcc/reload1.c

index 70d3130..7450115 100644 (file)
@@ -1,3 +1,18 @@
+Sat Aug  4 13:51:36 CEST 2001  Jan Hubicka  <jh@suse.cz>
+
+       * loop.c (try_copy_prop); Kill invalidated REG_EQUAL notes.
+
+       * reload1.c (fixup_abnormal_edges): New static function.
+       (reload): Use it.
+
+       * flow.c (need_fake_edge_p): New function.
+       (flow_call_edges_add): Fix handling of noreturn and sibbling calls;
+       avoid call insn to be very last insn in the insn stream.
+
+       * profile.c (branch_prob): Call flow_call_edges_add instead of
+       doing that by hand; cleanup cfg to re-merge basic blocks once
+       we are done.
+
 2001-08-04  Neil Booth  <neil@cat.daikokuya.demon.co.uk>
 
        * Makefile.in (CPPLIB_H): New, so that dependencies on cpplib.h
index ce67be5..c602fb1 100644 (file)
@@ -485,6 +485,7 @@ static int flow_loop_level_compute  PARAMS ((struct loop *, int));
 static int flow_loops_level_compute    PARAMS ((struct loops *));
 static void delete_dead_jumptables     PARAMS ((void));
 static bool back_edge_of_syntactic_loop_p PARAMS ((basic_block, basic_block));
+static bool need_fake_edge_p           PARAMS ((rtx));
 \f
 /* Find basic blocks of the current function.
    F is the first insn of the function and NREGS the number of register
@@ -2500,9 +2501,35 @@ commit_edge_insertions ()
     }
 }
 
-/* Add fake edges to the function exit for any non constant calls in
-   the bitmap of blocks specified by BLOCKS or to the whole CFG if
-   BLOCKS is zero.  Return the nuber of blocks that were split.  */
+/* Return true if we need to add fake edge to exit.
+   Helper function for the flow_call_edges_add.  */
+static bool
+need_fake_edge_p (insn)
+     rtx insn;
+{
+  if (!INSN_P (insn))
+    return false;
+
+  if ((GET_CODE (insn) == CALL_INSN
+       && !SIBLING_CALL_P (insn)
+       && !find_reg_note (insn, REG_NORETURN, NULL) && !CONST_CALL_P (insn)))
+    return true;
+
+  return ((GET_CODE (PATTERN (insn)) == ASM_OPERANDS
+          && MEM_VOLATILE_P (PATTERN (insn)))
+         || (GET_CODE (PATTERN (insn)) == PARALLEL
+             && asm_noperands (insn) != -1
+             && MEM_VOLATILE_P (XVECEXP (PATTERN (insn), 0, 0)))
+         || GET_CODE (PATTERN (insn)) == ASM_INPUT);
+}
+
+/* Add fake edges to the function exit for any non constant and non noreturn
+   calls, volatile inline assembly in the bitmap of blocks specified by
+   BLOCKS or to the whole CFG if BLOCKS is zero.  Return the nuber of blocks
+   that were split. 
+
+   The goal is to expose cases in which entering a basic block does not imply
+   that all subsequent instructions must be executed.  */
 
 int
 flow_call_edges_add (blocks)
@@ -2512,6 +2539,7 @@ flow_call_edges_add (blocks)
   int blocks_split = 0;
   int bb_num = 0;
   basic_block *bbs;
+  bool check_last_block = false;
 
   /* Map bb indicies into basic block pointers since split_block
      will renumber the basic blocks.  */
@@ -2522,15 +2550,41 @@ flow_call_edges_add (blocks)
     {
       for (i = 0; i < n_basic_blocks; i++)
        bbs[bb_num++] = BASIC_BLOCK (i);
+      check_last_block = true;
     }
   else
     {
       EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i, 
       {
        bbs[bb_num++] = BASIC_BLOCK (i);
+       if (i == n_basic_blocks - 1)
+         check_last_block = true;
       });
     }
 
+  /* In the last basic block, before epilogue generation, there will be
+     a fallthru edge to EXIT.  Special care is required if the last insn
+     of the last basic block is a call because make_edge folds duplicate
+     edges, which would result in the fallthru edge also being marked
+     fake, which would result in the fallthru edge being removed by 
+     remove_fake_edges, which would result in an invalid CFG.
+
+     Moreover, we can't elide the outgoing fake edge, since the block
+     profiler needs to take this into account in order to solve the minimal
+     spanning tree in the case that the call doesn't return.
+
+     Handle this by adding a dummy instruction in a new last basic block.  */
+  if (check_last_block
+      && need_fake_edge_p (BASIC_BLOCK (n_basic_blocks - 1)->end))
+    {
+       edge e;
+       for (e = BASIC_BLOCK (n_basic_blocks - 1)->succ; e; e = e->succ_next)
+        if (e->dest == EXIT_BLOCK_PTR)
+           break;
+       insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
+       commit_edge_insertions ();
+    }
+
 
   /* Now add fake edges to the function exit for any non constant
      calls since there is no way that we can determine if they will
@@ -2545,10 +2599,21 @@ flow_call_edges_add (blocks)
       for (insn = bb->end; ; insn = prev_insn)
        {
          prev_insn = PREV_INSN (insn);
-         if (GET_CODE (insn) == CALL_INSN && ! CONST_CALL_P (insn))
+         if (need_fake_edge_p (insn))
            {
              edge e;
 
+             /* The above condition should be enought to verify that there is
+                no edge to the exit block in CFG already.  Calling make_edge in
+                such case would make us to mark that edge as fake and remove it
+                later.  */
+#ifdef ENABLE_CHECKING
+             if (insn == bb->end)
+               for (e = bb->succ; e; e = e->succ_next)
+                 if (e->dest == EXIT_BLOCK_PTR)
+                   abort ();
+#endif
+
              /* Note that the following may create a new basic block
                 and renumber the existing basic blocks.  */
              e = split_block (bb, insn);
index 998832c..fbbef73 100644 (file)
@@ -9289,7 +9289,16 @@ try_copy_prop (loop, replacement, regno)
          arg.set_seen = 0;
          note_stores (PATTERN (insn), note_reg_stored, &arg);
          if (arg.set_seen)
-           break;
+           {
+             rtx note = find_reg_note (insn, REG_EQUAL, NULL);
+
+             /* It is possible that we've turned previously valid REG_EQUAL to
+                invalid, as we change the REGNO to REPLACEMENT and unlike REGNO,
+                REPLACEMENT is modified, we get different meaning.  */
+             if (note && reg_mentioned_p (replacement, XEXP (note, 0)))
+               remove_note (insn, note);
+             break;
+           }
        }
     }
   if (! init_insn)
index ddb621a..1335e9c 100644 (file)
@@ -528,6 +528,8 @@ branch_prob ()
 
   total_num_times_called++;
 
+  flow_call_edges_add (NULL);
+
   /* We can't handle cyclic regions constructed using abnormal edges.
      To avoid these we replace every source of abnormal edge by a fake
      edge from entry node and every destination by fake edge to exit.
@@ -562,28 +564,6 @@ branch_prob ()
            have_entry_edge = 1;
        }
 
-      /* ??? Not strictly needed unless flag_test_coverage, but adding
-        them anyway keeps the .da file consistent.  */
-      /* ??? Currently inexact for basic blocks with multiple calls. 
-        We need to split blocks here.  */
-      for (insn = bb->head;
-          insn != NEXT_INSN (bb->end);
-          insn = NEXT_INSN (insn))
-       {
-         rtx set;
-         if (GET_CODE (insn) == CALL_INSN && !CONST_CALL_P (insn))
-           need_exit_edge = 1;
-         else if (GET_CODE (insn) == INSN)
-           {
-             set = PATTERN (insn);
-             if (GET_CODE (set) == PARALLEL)
-               set = XVECEXP (set, 0, 0);
-             if ((GET_CODE (set) == ASM_OPERANDS && MEM_VOLATILE_P (set))
-                 || GET_CODE (set) == ASM_INPUT)
-               need_exit_edge = 1;
-           }
-       }
-
       if (need_exit_edge && !have_exit_edge)
        {
          if (rtl_dump_file)
@@ -787,6 +767,12 @@ branch_prob ()
     }
 
   remove_fake_edges ();
+  /* Re-merge split basic blocks and the mess introduced by
+     insert_insn_on_edge.  */
+  cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0);
+  if (rtl_dump_file)
+    dump_flow_info (rtl_dump_file);
+
   free (edge_infos);
   free_edge_list (el);
 }
index ced823b..09ef4ef 100644 (file)
@@ -461,6 +461,7 @@ static void failed_reload           PARAMS ((rtx, int));
 static int set_reload_reg              PARAMS ((int, int));
 static void reload_cse_delete_noop_set PARAMS ((rtx, rtx));
 static void reload_cse_simplify                PARAMS ((rtx));
+static void fixup_abnormal_edges       PARAMS ((void));
 extern void dump_needs                 PARAMS ((struct insn_chain *));
 \f
 /* Initialize the reload pass once per compilation.  */
@@ -1269,6 +1270,7 @@ reload (first, global)
   /* Free all the insn_chain structures at once.  */
   obstack_free (&reload_obstack, reload_startobj);
   unused_insn_chains = 0;
+  fixup_abnormal_edges ();
 
   return failure;
 }
@@ -9470,3 +9472,56 @@ copy_eh_notes (insn, x)
     }
 }
 
+/* This is used by reload pass, that does emit some instructions after
+   abnormal calls moving basic block end, but in fact it wants to emit
+   them on the edge.  Looks for abnormal call edges, find backward the
+   proper call and fix the damage.
+   Similar handle instructions throwing exceptions internally.  */
+static void
+fixup_abnormal_edges ()
+{
+  int i;
+  bool inserted = false;
+
+  for (i = 0; i < n_basic_blocks; i++)
+    {
+      basic_block bb = BASIC_BLOCK (i);
+      edge e;
+
+      /* Look for cases we are interested in - an calls or instructions causing
+         exceptions.  */
+      for (e = bb->succ; e; e = e->succ_next)
+       {
+         if (e->flags & EDGE_ABNORMAL_CALL)
+           break;
+         if ((e->flags & (EDGE_ABNORMAL | EDGE_EH))
+             == (EDGE_ABNORMAL | EDGE_EH))
+           break;
+       }
+      if (e && GET_CODE (bb->end) != CALL_INSN && !can_throw_internal (bb->end))
+       {
+         rtx insn = bb->end;
+         rtx next;
+         for (e = bb->succ; e; e = e->succ_next)
+           if (e->flags & EDGE_FALLTHRU)
+             break;
+         while (GET_CODE (insn) == INSN && !can_throw_internal (insn))
+           insn = PREV_INSN (insn);
+         if (GET_CODE (insn) != CALL_INSN && !can_throw_internal (insn))
+           abort ();
+         bb->end = insn;
+         inserted = true;
+         insn = NEXT_INSN (insn);
+         while (insn && GET_CODE (insn) == INSN)
+           {
+             next = NEXT_INSN (insn);
+             insert_insn_on_edge (PATTERN (insn), e);
+             flow_delete_insn (insn);
+             insn = next;
+           }
+       }
+    }
+  if (inserted)
+    commit_edge_insertions ();
+}