This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

per insn lexical block tracking


As discussed elsewhere, this is a sort-of extraction of Jan's per insn
scope tracking from cfg-branch.  The main difference is that we use the
block tree directly and don't create a "scope tree" that mirrors it.
Additionally, the interface is changed a bit and gets exported from
cfglayout.c so that the scheduler can use it.

Jan was right -- this is a *lot* cleaner and simpler than the current
cfglayout scope tracking.

Tested on i686, alphaev6 and ia64 linux.


r~


        * cfglayout.c (scope_def, scope_forest_info, forest,
        relate_bbs_with_scopes, make_new_scope, build_scope_forest,
        remove_scope_notes, insert_intra_before_1, insert_intra_1,
        insert_intra_bb_scope_notes, insert_inter_bb_scope_notes,
        rebuild_scope_notes, free_scope_forest_1, dump_scope_forest,
        dump_scope_forest_1, get_next_bb_note, get_prev_bb_note): Remove.
        (fixup_reorder_chain): Don't set scope for bb.
        (insn_scopes, scope_to_insns_initialize, set_block_levels,
        change_scope, scope_to_insns_finalize): New.
        (cfg_layout_initialize, cfg_layout_finalize): Update to match.
        * cfglayout.h (scope_def, scope): Remove.
        (reorder_block_def): Remove scope member.
        (scope_to_insns_initialize, scope_to_insns_finalize): Declare.
        * haifa-sched.c: Revert reemit_other_notes change.
        * sched-ebb.c (schedule_ebbs): Don't call remove_unnecessary_notes.
        Use scope_to_insns_initialize and scope_to_insns_finalize.
        * sched-rgn.c (schedule_insns): Likewise.

        * gcc.dg/debug-6.c: New.

Index: cfglayout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.c,v
retrieving revision 1.7
diff -c -p -d -r1.7 cfglayout.c
*** cfglayout.c	2001/12/29 20:01:13	1.7
--- cfglayout.c	2001/12/31 04:10:22
*************** Software Foundation, 59 Temple Place - S
*** 20,25 ****
--- 20,26 ----
  
  #include "config.h"
  #include "system.h"
+ #include "tree.h"
  #include "rtl.h"
  #include "hard-reg-set.h"
  #include "basic-block.h"
*************** Software Foundation, 59 Temple Place - S
*** 31,115 ****
  
  /* The contents of the current function definition are allocated
     in this obstack, and all are freed at the end of the function.  */
- 
  extern struct obstack flow_obstack;
  
- /* Structure to hold information about lexical scopes.  */
- struct scope_def
- {
-   int level;
- 
-   /* The NOTE_INSN_BLOCK_BEG that started this scope.  */
-   rtx note_beg;
- 
-   /* The NOTE_INSN_BLOCK_END that ended this scope.  */
-   rtx note_end;
- 
-   /* The bb containing note_beg (if any).  */
-   basic_block bb_beg;
- 
-   /* The bb containing note_end (if any).  */
-   basic_block bb_end;
- 
-   /* List of basic blocks contained within this scope.  */
-   basic_block *bbs;
- 
-   /* Number of blocks contained within this scope.  */
-   int num_bbs;
- 
-   /* The outer scope or NULL if outermost scope.  */
-   struct scope_def *outer;
- 
-   /* The first inner scope or NULL if innermost scope.  */
-   struct scope_def *inner;
- 
-   /* The last inner scope or NULL if innermost scope.  */
-   struct scope_def *inner_last;
- 
-   /* Link to the next (sibling) scope.  */
-   struct scope_def *next;
- };
- 
- /* Structure to hold information about the scope forest.  */
- typedef struct
- {
-   /* Number of trees in forest.  */
-   int num_trees;
- 
-   /* List of tree roots.  */
-   scope *trees;
- } scope_forest_info;
- 
  /* Holds the interesting trailing notes for the function.  */
  static rtx function_tail_eff_head;
  
- /* The scope forest of current function.  */
- static scope_forest_info forest;
- 
  static rtx skip_insns_after_block	PARAMS ((basic_block));
  static void record_effective_endpoints	PARAMS ((void));
  static rtx label_for_bb			PARAMS ((basic_block));
  static void fixup_reorder_chain		PARAMS ((void));
  
! static void relate_bbs_with_scopes	PARAMS ((scope));
! static scope make_new_scope		PARAMS ((int, rtx));
! static void build_scope_forest		PARAMS ((scope_forest_info *));
! static void remove_scope_notes		PARAMS ((void));
! static void insert_intra_before_1	PARAMS ((scope, rtx *, basic_block));
! static void insert_intra_1		PARAMS ((scope, rtx *, basic_block));
! static void insert_intra_bb_scope_notes PARAMS ((basic_block));
! static void insert_inter_bb_scope_notes PARAMS ((basic_block, basic_block));
! static void rebuild_scope_notes		PARAMS ((scope_forest_info *));
! static void free_scope_forest_1		PARAMS ((scope));
! static void free_scope_forest		PARAMS ((scope_forest_info *));
! void dump_scope_forest			PARAMS ((scope_forest_info *));
! static void dump_scope_forest_1		PARAMS ((scope, int));
! 
! static rtx get_next_bb_note		PARAMS ((rtx));
! static rtx get_prev_bb_note		PARAMS ((rtx));
  
  void verify_insn_chain			PARAMS ((void));
  static void fixup_fallthru_exit_predecessor PARAMS ((void));
  
  /* Skip over inter-block insns occurring after BB which are typically
     associated with BB (e.g., barriers). If there are any such insns,
--- 32,55 ----
  
  /* The contents of the current function definition are allocated
     in this obstack, and all are freed at the end of the function.  */
  extern struct obstack flow_obstack;
  
  /* Holds the interesting trailing notes for the function.  */
  static rtx function_tail_eff_head;
  
  static rtx skip_insns_after_block	PARAMS ((basic_block));
  static void record_effective_endpoints	PARAMS ((void));
  static rtx label_for_bb			PARAMS ((basic_block));
  static void fixup_reorder_chain		PARAMS ((void));
  
! static void set_block_levels		PARAMS ((tree, int));
! static void change_scope		PARAMS ((rtx, tree, tree));
  
  void verify_insn_chain			PARAMS ((void));
  static void fixup_fallthru_exit_predecessor PARAMS ((void));
+ 
+ /* Map insn uid to lexical block.  */
+ static varray_type insn_scopes;
  
  /* Skip over inter-block insns occurring after BB which are typically
     associated with BB (e.g., barriers). If there are any such insns,
*************** record_effective_endpoints ()
*** 245,852 ****
    function_tail_eff_head = next_insn;
  }
  
! /* Return the next NOTE_INSN_BASIC_BLOCK after X.  */
! 
! static rtx
! get_next_bb_note (x)
!      rtx x;
! {
!   for (; x; x = NEXT_INSN (x))
!     if (NOTE_INSN_BASIC_BLOCK_P (x))
!       return x;
! 
!   return NULL;
! }
! 
! /* Return the fist NOTE_INSN_BASIC_BLOCK before X.  */
! 
! static rtx
! get_prev_bb_note (x)
!      rtx x;
! {
!   for (; x; x = PREV_INSN (x))
!     if (NOTE_INSN_BASIC_BLOCK_P (x))
!       return x;
! 
!   return NULL;
! }
! 
! /* Determine and record the relationships between basic blocks and
!    scopes in scope tree S.  */
! 
! static void
! relate_bbs_with_scopes (s)
!      scope s;
! {
!   scope p;
!   int i, bbi1, bbi2, bbs_spanned;
!   rtx bbnote;
! 
!   for (p = s->inner; p; p = p->next)
!     relate_bbs_with_scopes (p);
! 
!   bbi1 = bbi2 = -1;
!   bbs_spanned = 0;
! 
!   /* If the begin and end notes are both inside the same basic block,
!      or if they are both outside of basic blocks, then we know immediately
!      how they are related. Otherwise, we need to poke around to make the
!      determination.  */
!   if (s->bb_beg != s->bb_end)
!     {
!       if (s->bb_beg && s->bb_end)
!         {
! 	  /* Both notes are in different bbs. This implies that all the
! 	     basic blocks spanned by the pair of notes are contained in
!              this scope.  */
! 	  bbi1 = s->bb_beg->index;
! 	  bbi2 = s->bb_end->index;
! 	  bbs_spanned = 1;
! 	}
!       else if (! s->bb_beg)
!         {
! 	  /* First note is outside of a bb. If the scope spans more than
! 	     one basic block, then they all are contained within this
!              scope. Otherwise, this scope is contained within the basic
! 	     block.  */
! 	  bbnote = get_next_bb_note (s->note_beg);
! 	  if (! bbnote)
! 	    abort ();
! 
! 	  if (NOTE_BASIC_BLOCK (bbnote) == s->bb_end)
! 	    {
! 	      bbs_spanned = 0;
! 	      s->bb_beg = NOTE_BASIC_BLOCK (bbnote);
! 	    }
! 	  else
! 	    {
! 	      bbi1 = NOTE_BASIC_BLOCK (bbnote)->index;
! 	      bbi2 = s->bb_end->index;
! 	      s->bb_end = NULL;
! 	      bbs_spanned = 1;
! 	    }
! 	}
!       else /* ! s->bb_end */
!         {
! 	  /* Second note is outside of a bb. If the scope spans more than
! 	     one basic block, then they all are contained within this
!              scope. Otherwise, this scope is contained within the basic
! 	     block.  */
! 	  bbnote = get_prev_bb_note (s->note_end);
! 	  if (! bbnote)
! 	    abort ();
! 
! 	  if (NOTE_BASIC_BLOCK (bbnote) == s->bb_beg)
! 	    {
! 	      bbs_spanned = 0;
! 	      s->bb_end = NOTE_BASIC_BLOCK (bbnote);
! 	    }
! 	  else
! 	    {
! 	      bbi1 = s->bb_beg->index;
! 	      bbi2 = NOTE_BASIC_BLOCK (bbnote)->index;
! 	      s->bb_beg = NULL;
! 	      bbs_spanned = 1;
! 	    }
! 	}
!     }
!   else
!     {
!       if (s->bb_beg)
!         /* Both notes are in the same bb, which implies the block
! 	   contains this scope.  */
! 	bbs_spanned = 0;
!       else
! 	{
! 	  /* Both notes are outside of any bbs. This implies that all the
! 	     basic blocks spanned by the pair of notes are contained in
!              this scope. 
! 	     There is a degenerate case to consider. If the notes do not
! 	     span any basic blocks, then it is an empty scope that can
! 	     safely be deleted or ignored. Mark these with level = -1.  */
! 	  rtx x1 = get_next_bb_note (s->note_beg);
! 	  rtx x2 = get_prev_bb_note (s->note_end);
! 
! 	  if (! (x1 && x2))
! 	    {
! 	      s->level = -1; 
! 	      bbs_spanned = 0; 
! 	    }
! 	  else
! 	    {
! 	      bbi1 = NOTE_BASIC_BLOCK (x1)->index;
! 	      bbi2 = NOTE_BASIC_BLOCK (x2)->index;
! 	      bbs_spanned = 1;
! 	    }
! 	}
!     }
! 
!   /* If the scope spans one or more basic blocks, we record them. We
!      only record the bbs that are immediately contained within this
!      scope. Note that if a scope is contained within a bb, we can tell
!      by checking that bb_beg = bb_end and that they are non-null.  */
!   if (bbs_spanned)
!     {
!       int j = 0;
! 
!       s->num_bbs = 0;
!       for (i = bbi1; i <= bbi2; i++)
! 	if (! RBI (BASIC_BLOCK (i))->scope)
! 	  s->num_bbs++;
! 
!       s->bbs = xmalloc (s->num_bbs * sizeof (basic_block));
!       for (i = bbi1; i <= bbi2; i++)
! 	{
! 	  basic_block curr_bb = BASIC_BLOCK (i);
! 	  if (! RBI (curr_bb)->scope)
! 	    {
! 	      s->bbs[j++] = curr_bb;
! 	      RBI (curr_bb)->scope = s;
! 	    }
! 	}
!     }
!   else
!     s->num_bbs = 0;
! }
! 
! /* Allocate and initialize a new scope structure with scope level LEVEL,
!    and record the NOTE beginning the scope.  */
! 
! static scope 
! make_new_scope (level, note)
!      int level;
!      rtx note;
! {
!   scope new_scope = xcalloc (1, sizeof (struct scope_def));
! 
!   new_scope->level = level;
!   new_scope->note_beg = note;
!   return new_scope;
! }
! 
! 
! /* Build a forest representing the scope structure of the function.
!    Return a pointer to a structure describing the forest.  */
  
! static void
! build_scope_forest (forest)
!     scope_forest_info *forest;
  {
!   rtx x;
!   int level, bbi, i;
!   basic_block curr_bb;
!   scope root, curr_scope = 0;
! 
!   forest->num_trees = 0;
!   forest->trees = NULL;
!   level = -1;
!   root = NULL;
!   curr_bb = NULL;
!   bbi = 0;
! 
!   for (x = get_insns (); x; x = NEXT_INSN (x))
!     {
!       if (bbi < n_basic_blocks && x == BASIC_BLOCK (bbi)->head)
! 	curr_bb = BASIC_BLOCK (bbi);
! 
!       if (GET_CODE (x) == NOTE)
! 	{
! 	  if (NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_BEG)
! 	    {
! 	      if (root)
! 		{
! 		  scope new_scope;
! 
! 		  if (! curr_scope)
! 		    abort();
! 
! 		  level++;
! 		  new_scope = make_new_scope (level, x);
! 		  new_scope->outer = curr_scope;
! 		  new_scope->next = NULL;
! 		  if (! curr_scope->inner)
! 		    {
! 		      curr_scope->inner = new_scope;
! 		      curr_scope->inner_last = new_scope;
! 		    }
! 		  else
! 		    {
! 		      curr_scope->inner_last->next = new_scope;
! 		      curr_scope->inner_last = new_scope;
! 		    }
! 		  curr_scope = curr_scope->inner_last;
! 
! 		}
! 	      else
! 		{
! 		  int ntrees = forest->num_trees;
! 
! 		  level++;
! 	          curr_scope = make_new_scope (level, x);
! 		  root = curr_scope;
! 		  forest->trees = xrealloc (forest->trees,
! 					    sizeof (scope) * (ntrees + 1));
! 		  forest->trees[forest->num_trees++] = root;
! 		}
! 
! 	      curr_scope->bb_beg = curr_bb;
! 	    }
! 	  else if (NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_END)
! 	    {
! 	      curr_scope->bb_end = curr_bb;
! 	      curr_scope->note_end = x;
! 	      level--;
! 	      curr_scope = curr_scope->outer;
! 	      if (level == -1)
! 		root = NULL;
! 	    }
! 	}
! 
!       if (curr_bb && curr_bb->end == x)
! 	{
! 	  curr_bb = NULL;
! 	  bbi++;
! 	}
!     } 
! 
!   for (i = 0; i < forest->num_trees; i++)
!     relate_bbs_with_scopes (forest->trees[i]);
! }
! 
! /* Remove all NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes from the insn
!    chain.  */
  
! static void
! remove_scope_notes ()
! {
!   rtx x, next;
!   basic_block currbb = NULL;
  
!   for (x = get_insns (); x; x = next)
      {
!       next = NEXT_INSN (x);
!       if (NOTE_INSN_BASIC_BLOCK_P (x))
! 	currbb = NOTE_BASIC_BLOCK (x);
  
!       if (GET_CODE (x) == NOTE
! 	  && (NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_BEG
! 	      || NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_END))
  	{
! 	  /* Check if the scope note happens to be the end of a bb.  */
! 	  if (currbb && x == currbb->end)
! 	    currbb->end = PREV_INSN (x);
! 	  if (currbb && x == currbb->head)
! 	    abort ();
! 
! 	  if (PREV_INSN (x))
  	    {
! 	      NEXT_INSN (PREV_INSN (x)) = next;
! 	      if (next)
! 	        PREV_INSN (next) = PREV_INSN (x);
! 
!               NEXT_INSN (x) = NULL;
!               PREV_INSN (x) = NULL;
  	    }
- 	  else
- 	    abort ();
  	}
      }
  }
- 
- /* Insert scope note pairs for a contained scope tree S after insn IP.  */
- 
- static void
- insert_intra_1 (s, ip, bb)
-      scope s;
-      rtx *ip;
-      basic_block bb;
- {
-   scope p;
- 
-   if (NOTE_BLOCK (s->note_beg))
-     {  
-       *ip = emit_note_after (NOTE_INSN_BLOCK_BEG, *ip);
-       NOTE_BLOCK (*ip) = NOTE_BLOCK (s->note_beg);
-     } 
- 
-   for (p = s->inner; p; p = p->next)
-     insert_intra_1 (p, ip, bb);
- 
-   if (NOTE_BLOCK (s->note_beg))
-     {  
-       *ip = emit_note_after (NOTE_INSN_BLOCK_END, *ip);
-       NOTE_BLOCK (*ip) = NOTE_BLOCK (s->note_end);
-     }
- }
  
! /* Insert scope note pairs for a contained scope tree S before insn IP.  */
! 
! static void
! insert_intra_before_1 (s, ip, bb)
!      scope s;
!      rtx *ip;
!      basic_block bb;
! {
!   scope p;
! 
!   if (NOTE_BLOCK (s->note_beg))
!     {  
!       *ip = emit_note_before (NOTE_INSN_BLOCK_END, *ip);
!       NOTE_BLOCK (*ip) = NOTE_BLOCK (s->note_end);
!     } 
! 
!   for (p = s->inner; p; p = p->next)
!     insert_intra_before_1 (p, ip, bb);
! 
!   if (NOTE_BLOCK (s->note_beg))
!     {  
!       *ip = emit_note_before (NOTE_INSN_BLOCK_BEG, *ip);
!       NOTE_BLOCK (*ip) = NOTE_BLOCK (s->note_beg);
!     }
! }
! 
! /* Insert NOTE_INSN_BLOCK_END notes and NOTE_INSN_BLOCK_BEG notes for
!    scopes that are contained within BB.  */
  
  static void
! insert_intra_bb_scope_notes (bb)
!      basic_block bb;
  {
!   scope s = RBI (bb)->scope;
!   scope p;
!   rtx ip;
! 
!   if (! s)
!     return;
! 
!   ip = bb->head;
!   if (GET_CODE (ip) == CODE_LABEL)
!     ip = NEXT_INSN (ip);
! 
!   for (p = s->inner; p; p = p->next)
      {
!       if (p->bb_beg != NULL && p->bb_beg == p->bb_end && p->bb_beg == bb)
! 	insert_intra_1 (p, &ip, bb);
      }
  }
  
! /* Given two consecutive basic blocks BB1 and BB2 with different scopes,
!    insert NOTE_INSN_BLOCK_END notes after BB1 and NOTE_INSN_BLOCK_BEG
!    notes before BB2 such that the notes are correctly balanced. If BB1 or
!    BB2 is NULL, we are inserting scope notes for the first and last basic
!    blocks, respectively.  */
  
  static void
! insert_inter_bb_scope_notes (bb1, bb2)
!      basic_block bb1;
!      basic_block bb2;
  {
!   rtx ip;
!   scope com;
! 
!   /* It is possible that a basic block is not contained in any scope.
!      In that case, we either open or close a scope but not both.  */
!   if (bb1 && bb2)
!     {
!       scope s1 = RBI (bb1)->scope;
!       scope s2 = RBI (bb2)->scope;
! 
!       if (! s1 && ! s2)
! 	return;
! 
!       if (! s1)
! 	bb1 = NULL;
!       else if (! s2)
! 	bb2 = NULL;
!     }
  
!   /* Find common ancestor scope.  */
!   if (bb1 && bb2)
      {
!       scope s1 = RBI (bb1)->scope;
!       scope s2 = RBI (bb2)->scope;
! 
!       while (s1 != s2)
  	{
! 	  if (s1->level > s2->level)
! 	    s1 = s1->outer;
! 	  else if (s2->level > s1->level)
! 	    s2 = s2->outer;
! 	  else
! 	    {
! 	      s1 = s1->outer;
! 	      s2 = s2->outer;
! 	    }
  	}
- 
-       com = s1;
      }
!   else
!     com = NULL;
  
    /* Close scopes.  */
!   if (bb1)
      {
!       rtx end = bb1->end;
!       scope s, p;
! 
!       ip = RBI (bb1)->eff_end;
!       for (s = RBI (bb1)->scope; s != com; s = s->outer)
! 	{
! 	  if (NOTE_BLOCK (s->note_beg))
! 	    {  
! 	      ip = emit_note_after (NOTE_INSN_BLOCK_END, ip);
! 	      NOTE_BLOCK (ip) = NOTE_BLOCK (s->note_end);
! 	    }
! 
! 	  /* Now emit all sibling scopes which don't span any basic
! 	     blocks.  */
! 	  if (s->outer)
! 	    for (p = s->outer->inner; p; p = p->next)
! 	      if (p != s && p->bb_beg == bb1 && p->bb_beg == p->bb_end)
! 		insert_intra_1 (p, &ip, bb1);
! 	}
! 
!       /* Emitting note may move the end of basic block to unwanted place.  */
!       bb1->end = end;
      }
  
    /* Open scopes.  */
!   if (bb2)
      {
!       scope s, p;
! 
!       ip = bb2->head;
!       for (s = RBI (bb2)->scope; s != com; s = s->outer)
! 	{
! 	  if (NOTE_BLOCK (s->note_beg))
! 	    {  
! 	      ip = emit_note_before (NOTE_INSN_BLOCK_BEG, ip);
! 	      NOTE_BLOCK (ip) = NOTE_BLOCK (s->note_beg);
! 	    }
! 
! 	  /* Now emit all sibling scopes which don't span any basic
! 	     blocks.  */
! 	  if (s->outer)
! 	    for (p = s->outer->inner; p; p = p->next)
! 	      if (p != s && p->bb_beg == bb2 && p->bb_beg == p->bb_end)
! 		insert_intra_before_1 (p, &ip, bb2);
! 	}
      }
  }
  
- 
  /* Rebuild all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes based
!    on the scope forest and the newly reordered basic blocks.  */
! 
! static void
! rebuild_scope_notes (forest)
!     scope_forest_info *forest;
! {
!   int i;
! 
!   if (forest->num_trees == 0)
!     return;
! 
!   /* Start by opening the scopes before the first basic block.  */
!   insert_inter_bb_scope_notes (NULL, BASIC_BLOCK (0));
! 
!   /* Then, open and close scopes as needed between blocks.  */
!   for (i = 0; i < n_basic_blocks - 1; i++)
!     {
!       basic_block bb1 = BASIC_BLOCK (i);
!       basic_block bb2 = BASIC_BLOCK (i + 1);
! 
!       if (RBI (bb1)->scope != RBI (bb2)->scope)
! 	insert_inter_bb_scope_notes (bb1, bb2);
!       insert_intra_bb_scope_notes (bb1);
!     }
! 
!   /* Finally, close the scopes after the last basic block.  */
!   insert_inter_bb_scope_notes (BASIC_BLOCK (n_basic_blocks - 1), NULL);
!   insert_intra_bb_scope_notes (BASIC_BLOCK (n_basic_blocks - 1));
! }
! 
! /* Free the storage associated with the scope tree at S.  */
! 
! static void
! free_scope_forest_1 (s)
!     scope s;
! {
!   scope p, next;
! 
!   for (p = s->inner; p; p = next)
!     {
!       next = p->next;
!       free_scope_forest_1 (p);
!     }
! 
!   if (s->bbs)
!     free (s->bbs);
!   free (s);
! }
! 
! /* Free the storage associated with the scope forest.  */
! 
! static void
! free_scope_forest (forest)
!     scope_forest_info *forest;
! {
!   int i;
! 
!   for (i = 0; i < forest->num_trees; i++)
!     free_scope_forest_1 (forest->trees[i]);
! }
! 
! /* Visualize the scope forest.  */
  
  void
! dump_scope_forest (forest)
!     scope_forest_info *forest;
  {
!   int i;
! 
!   if (forest->num_trees == 0)
!     fprintf (stderr, "\n< Empty scope forest >\n");
!   else
!     fprintf (stderr, "\n< Scope forest >\n");
  
!   for (i = 0; i < forest->num_trees; i++)
!     dump_scope_forest_1 (forest->trees[i], 0);
! }
  
! /* Recursive portion of dump_scope_forest.  */
  
! static void
! dump_scope_forest_1 (s, indent)
!      scope s;
!      int indent;
! {
!   scope p;
!   int i;
  
!   if (s->bb_beg != NULL && s->bb_beg == s->bb_end
!       && RBI (s->bb_beg)->scope
!       && RBI (s->bb_beg)->scope->level + 1 == s->level)
!     {
!       fprintf (stderr, "%*s", indent, "");
!       fprintf (stderr, "BB%d:\n", s->bb_beg->index);
      }
  
!   fprintf (stderr, "%*s", indent, "");
!   fprintf (stderr, "{ level %d (block %p)\n", s->level,
! 	   (PTR) NOTE_BLOCK (s->note_beg));
  
!   fprintf (stderr, "%*s%s", indent, "", "bbs:");
!   for (i = 0; i < s->num_bbs; i++)
!     fprintf (stderr, " %d", s->bbs[i]->index);
!   fprintf (stderr, "\n");
!   
!   for (p = s->inner; p; p = p->next)
!     dump_scope_forest_1 (p, indent + 2);
  
!   fprintf (stderr, "%*s", indent, "");
!   fprintf (stderr, "}\n");
  }
  
  /* Given a reorder chain, rearrange the code to match.  */
--- 185,328 ----
    function_tail_eff_head = next_insn;
  }
  
! /* Build a varray mapping INSN_UID to lexical block.  Return it.  */
  
! void
! scope_to_insns_initialize ()
  {
!   tree block = NULL;
!   rtx insn, next;
  
!   VARRAY_TREE_INIT (insn_scopes, get_max_uid (), "insn scopes");
  
!   for (insn = get_insns (); insn; insn = next)
      {
!       next = NEXT_INSN (insn);
  
!       if (active_insn_p (insn)
! 	  && GET_CODE (PATTERN (insn)) != ADDR_VEC
! 	  && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
! 	VARRAY_TREE (insn_scopes, INSN_UID (insn)) = block;
!       else if (GET_CODE (insn) == NOTE)
  	{
! 	  switch (NOTE_LINE_NUMBER (insn))
  	    {
! 	    case NOTE_INSN_BLOCK_BEG:
! 	      block = NOTE_BLOCK (insn);
! 	      delete_insn (insn);
! 	      break;
! 	    case NOTE_INSN_BLOCK_END:
! 	      block = BLOCK_SUPERCONTEXT (block);
! 	      delete_insn (insn);
! 	      break;
! 	    default:
! 	      break;
  	    }
  	}
      }
  }
  
! /* For each lexical block, set BLOCK_NUMBER to the depth at which it is
!    found in the block tree.  */
  
  static void
! set_block_levels (block, level)
!      tree block;
!      int level;
  {
!   while (block)
      {
!       BLOCK_NUMBER (block) = level;
!       set_block_levels (BLOCK_SUBBLOCKS (block), level + 1);
!       block = BLOCK_CHAIN (block);
      }
  }
  
! /* Emit lexical block notes needed to change scope from S1 to S2.  */
  
  static void
! change_scope (orig_insn, s1, s2)
!      rtx orig_insn;
!      tree s1, s2;
  {
!   rtx insn = orig_insn;
!   tree com = NULL_TREE;
!   tree ts1 = s1, ts2 = s2;
!   tree s;
  
!   while (ts1 != ts2)
      {
!       if (ts1 == NULL || ts2 == NULL)
! 	abort ();
!       if (BLOCK_NUMBER (ts1) > BLOCK_NUMBER (ts2))
! 	ts1 = BLOCK_SUPERCONTEXT (ts1);
!       else if (BLOCK_NUMBER (ts1) < BLOCK_NUMBER (ts2))
! 	ts2 = BLOCK_SUPERCONTEXT (ts2);
!       else
  	{
! 	  ts1 = BLOCK_SUPERCONTEXT (ts1);
! 	  ts2 = BLOCK_SUPERCONTEXT (ts2);
  	}
      }
!   com = ts1;
  
    /* Close scopes.  */
!   s = s1;
!   while (s != com)
      {
!       rtx note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
!       NOTE_BLOCK (note) = s;
!       s = BLOCK_SUPERCONTEXT (s);
      }
  
    /* Open scopes.  */
!   s = s2;
!   while (s != com)
      {
!       insn = emit_note_before (NOTE_INSN_BLOCK_BEG, insn);
!       NOTE_BLOCK (insn) = s;
!       s = BLOCK_SUPERCONTEXT (s);
      }
  }
  
  /* Rebuild all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes based
!    on the scope tree and the newly reordered instructions.  */
  
  void
! scope_to_insns_finalize ()
  {
!   tree cur_block = DECL_INITIAL (cfun->decl);
!   rtx insn, note;
  
!   /* Tag the blocks with a depth number so that change_scope can find
!      the common parent easily.  */
!   set_block_levels (cur_block, 0);
  
!   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
!     {
!       tree this_block;
  
!       if ((size_t) INSN_UID (insn) >= insn_scopes->num_elements)
! 	continue;
!       this_block = VARRAY_TREE (insn_scopes, INSN_UID (insn));
!       if (! this_block)
! 	continue;
  
!       if (this_block != cur_block)
! 	{
! 	  change_scope (insn, cur_block, this_block);
! 	  cur_block = this_block;
! 	}
      }
  
!   VARRAY_FREE (insn_scopes);
  
!   /* change_scope emits before the insn, not after.  */
!   note = emit_note (NULL, NOTE_INSN_DELETED);
!   change_scope (note, cur_block, DECL_INITIAL (cfun->decl));
!   delete_insn (note);
  
!   reorder_blocks ();
  }
  
  /* Given a reorder chain, rearrange the code to match.  */
*************** fixup_reorder_chain ()
*** 994,1000 ****
  	  alloc_aux_for_block (nb, sizeof (struct reorder_block_def));
  	  RBI (nb)->eff_head = nb->head;
  	  RBI (nb)->eff_end = NEXT_INSN (nb->end);
- 	  RBI (nb)->scope = RBI (bb)->scope;
  	  RBI (nb)->visited = 1;
  	  RBI (nb)->next = RBI (bb)->next;
  	  RBI (bb)->next = nb;
--- 470,475 ----
*************** cfg_layout_initialize ()
*** 1091,1098 ****
  {
    alloc_aux_for_blocks (sizeof (struct reorder_block_def));
  
!   build_scope_forest (&forest);
!   remove_scope_notes ();
  
    record_effective_endpoints ();
  }
--- 566,572 ----
  {
    alloc_aux_for_blocks (sizeof (struct reorder_block_def));
  
!   scope_to_insns_initialize ();
  
    record_effective_endpoints ();
  }
*************** cfg_layout_finalize ()
*** 1110,1118 ****
    verify_insn_chain ();
  #endif
  
!   rebuild_scope_notes (&forest);
!   free_scope_forest (&forest);
!   reorder_blocks ();
  
    free_aux_for_blocks ();
  
--- 584,590 ----
    verify_insn_chain ();
  #endif
  
!   scope_to_insns_finalize ();
  
    free_aux_for_blocks ();
  
Index: cfglayout.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.h,v
retrieving revision 1.1
diff -c -p -d -r1.1 cfglayout.h
*** cfglayout.h	2001/11/05 15:38:01	1.1
--- cfglayout.h	2001/12/31 04:10:22
***************
*** 18,32 ****
     Software Foundation, 59 Temple Place - Suite 330, Boston, MA
     02111-1307, USA.  */
  
- struct scope_def;
- typedef struct scope_def *scope;
- 
  /* Structure to hold information about the blocks during reordering.  */
  typedef struct reorder_block_def
  {
    rtx eff_head;
    rtx eff_end;
-   scope scope;
    basic_block next;
    int visited;
  } *reorder_block_def;
--- 18,28 ----
*************** typedef struct reorder_block_def
*** 35,37 ****
--- 31,36 ----
  
  extern void cfg_layout_initialize	PARAMS ((void));
  extern void cfg_layout_finalize		PARAMS ((void));
+ 
+ extern void scope_to_insns_initialize	PARAMS ((void));
+ extern void scope_to_insns_finalize	PARAMS ((void));
Index: haifa-sched.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/haifa-sched.c,v
retrieving revision 1.191
diff -c -p -d -r1.191 haifa-sched.c
*** haifa-sched.c	2001/12/27 22:19:58	1.191
--- haifa-sched.c	2001/12/31 04:10:22
*************** static void adjust_priority PARAMS ((rtx
*** 319,325 ****
  static rtx unlink_other_notes PARAMS ((rtx, rtx));
  static rtx unlink_line_notes PARAMS ((rtx, rtx));
  static rtx reemit_notes PARAMS ((rtx, rtx));
- static rtx reemit_other_notes PARAMS ((rtx, rtx));
  
  static rtx *ready_lastpos PARAMS ((struct ready_list *));
  static void ready_sort PARAMS ((struct ready_list *));
--- 319,324 ----
*************** reemit_notes (insn, last)
*** 1576,1635 ****
    return retval;
  }
  
- 
- /* NOTE_LIST is the end of a chain of notes previously found among the
-    insns.  Insert them at the beginning of the insns.  Actually, insert
-    NOTE_INSN_BLOCK_END notes at the end of the insns.  Doing otherwise
-    tends to collapse lexical blocks into empty regions, which is somewhat
-    less than useful.  */
- /* ??? Ideally we'd mark each insn with the block it originated from,
-    and preserve that information.  This requires some moderately
-    sophisticated block reconstruction code, since block nestings must
-    be preserved.  */
- 
- static rtx
- reemit_other_notes (head, tail)
-      rtx head, tail;
- {
-   bool saw_block_beg = false;
- 
-   while (note_list)
-     {
-       rtx note_tail = note_list;
-       note_list = PREV_INSN (note_tail);
- 
-       if (NOTE_LINE_NUMBER (note_tail) == NOTE_INSN_BLOCK_END
- 	  /* We can only extend the lexical block while we havn't
- 	     seen a BLOCK_BEG note.  Otherwise we risk mis-nesting
- 	     the notes.  */
- 	  && ! saw_block_beg)
- 	{
- 	  rtx insert_after = tail;
- 	  if (GET_CODE (NEXT_INSN (tail)) == BARRIER)
- 	    insert_after = NEXT_INSN (tail);
- 
- 	  PREV_INSN (note_tail) = insert_after;
- 	  NEXT_INSN (note_tail) = NEXT_INSN (insert_after);
- 	  if (NEXT_INSN (insert_after))
- 	    PREV_INSN (NEXT_INSN (insert_after)) = note_tail;
- 	  NEXT_INSN (insert_after) = note_tail;
- 	}
-       else
- 	{
- 	  if (NOTE_LINE_NUMBER (note_tail) == NOTE_INSN_BLOCK_BEG)
- 	    saw_block_beg = true;
- 
- 	  PREV_INSN (note_tail) = PREV_INSN (head);
- 	  NEXT_INSN (PREV_INSN (head)) = note_tail;
- 	  NEXT_INSN (note_tail) = head;
- 	  PREV_INSN (head) = note_tail;
- 	  head = note_tail;
- 	}
-     }
- 
-   return head;
- }
- 
  /* Move INSN, and all insns which should be issued before it,
     due to SCHED_GROUP_P flag.  Reemit notes if needed.
  
--- 1575,1580 ----
*************** schedule_block (b, rgn_n_insns)
*** 1855,1861 ****
    head = NEXT_INSN (prev_head);
    tail = last;
  
!   head = reemit_other_notes (head, tail);
  
    /* Debugging.  */
    if (sched_verbose)
--- 1800,1823 ----
    head = NEXT_INSN (prev_head);
    tail = last;
  
!   /* Restore-other-notes: NOTE_LIST is the end of a chain of notes
!      previously found among the insns.  Insert them at the beginning
!      of the insns.  */
!   if (note_list != 0)
!     {
!       rtx note_head = note_list;
! 
!       while (PREV_INSN (note_head))
! 	{
! 	  note_head = PREV_INSN (note_head);
! 	}
! 
!       PREV_INSN (note_head) = PREV_INSN (head);
!       NEXT_INSN (PREV_INSN (head)) = note_head;
!       PREV_INSN (head) = note_list;
!       NEXT_INSN (note_list) = head;
!       head = note_head;
!     }
  
    /* Debugging.  */
    if (sched_verbose)
Index: sched-ebb.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/sched-ebb.c,v
retrieving revision 1.7
diff -c -p -d -r1.7 sched-ebb.c
*** sched-ebb.c	2001/12/27 22:19:59	1.7
--- sched-ebb.c	2001/12/31 04:10:22
*************** Software Foundation, 59 Temple Place - S
*** 36,41 ****
--- 36,42 ----
  #include "except.h"
  #include "toplev.h"
  #include "recog.h"
+ #include "cfglayout.h"
  #include "sched-int.h"
  
  /* The number of insns to be scheduled in total.  */
*************** schedule_ebbs (dump_file)
*** 285,293 ****
    if (n_basic_blocks == 0)
      return;
  
!   /* Remove lexical block notes for empty regions.  These get shuffled
!      about during scheduling and confuse the debugging issue.  */
!   remove_unnecessary_notes ();
  
    sched_init (dump_file);
  
--- 286,292 ----
    if (n_basic_blocks == 0)
      return;
  
!   scope_to_insns_initialize ();
  
    sched_init (dump_file);
  
*************** schedule_ebbs (dump_file)
*** 356,361 ****
--- 355,362 ----
  
    if (write_symbols != NO_DEBUG)
      rm_redundant_line_notes ();
+ 
+   scope_to_insns_finalize ();
  
    sched_finish ();
  }
Index: sched-rgn.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/sched-rgn.c,v
retrieving revision 1.28
diff -c -p -d -r1.28 sched-rgn.c
*** sched-rgn.c	2001/12/27 22:19:59	1.28
--- sched-rgn.c	2001/12/31 04:10:22
*************** Software Foundation, 59 Temple Place - S
*** 60,65 ****
--- 60,66 ----
  #include "except.h"
  #include "toplev.h"
  #include "recog.h"
+ #include "cfglayout.h"
  #include "sched-int.h"
  
  /* Define when we want to do count REG_DEAD notes before and after scheduling
*************** schedule_insns (dump_file)
*** 2896,2904 ****
    if (n_basic_blocks == 0)
      return;
  
!   /* Remove lexical block notes for empty regions.  These get shuffled
!      about during scheduling and confuse the debugging issue.  */
!   remove_unnecessary_notes ();
  
    nr_inter = 0;
    nr_spec = 0;
--- 2897,2903 ----
    if (n_basic_blocks == 0)
      return;
  
!   scope_to_insns_initialize ();
  
    nr_inter = 0;
    nr_spec = 0;
*************** schedule_insns (dump_file)
*** 2985,2990 ****
--- 2984,2991 ----
    /* Delete redundant line notes.  */
    if (write_symbols != NO_DEBUG)
      rm_redundant_line_notes ();
+ 
+   scope_to_insns_finalize ();
  
    if (sched_verbose)
      {
Index: testsuite/gcc.dg/debug-6.c
===================================================================
RCS file: debug-6.c
diff -N debug-6.c
*** /dev/null	Tue May  5 13:32:27 1998
--- debug-6.c	Sun Dec 30 20:11:47 2001
***************
*** 0 ****
--- 1,38 ----
+ /* Verify that bb-reorder re-inserts nested scopes properly.  */
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -g -dA" } */
+ /* { dg-final { scan-assembler "xyzzy" } } */
+ 
+ extern void abort (void);
+ 
+ struct A { char *a, *b, *c, *d; };
+ 
+ static int
+ bar2 (struct A *x)
+ {
+   int a = x->c - x->b;
+   x->c += 26;
+   return a;
+ }
+    
+ void fnptr (int *);
+ 
+ void
+ foo (void)
+ {
+   struct A e;
+ 
+   if (bar2 (&e) < 0)
+     abort ();
+   {
+     int xyzzy;
+     fnptr (&xyzzy);
+   }
+   {
+     struct A *f;
+   
+     f = &e;
+     if (f->c - f->a > f->d - f->a)
+       f->c = f->d;
+   }
+ }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]