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]

[sel-sched] More cleanups and comments


Hello,

This patch adds more high-level comments about the scheduler, tidies a couple of functions, and converts the new files to GPLv3, which I missed earlier.

Tested on ia64, committed to sel-sched branch.
Andrey


2008-04-18 Andrey Belevanstev <abel@ispras.ru> Dmitry Melnik <dm@ispras.ru> Alexander Monakov <amonakov@ispras.ru>

* cfgrtl.c (create_basic_block_structure): Set bb_index in one place.
* cse.c (hash_rtx_string): Make static inline.
* haifa-sched.c: Tidy, add comments, move static definitions to one
place.
(schedule_block): Print less debugging info.
(check_sched_flags, sched_finish_bbs): Remove.
* loop-init.c (loop_optimizer_init): Remove old merge glitch.
* modulo-sched.c: Remove #if 0'd code.
* rtl.h (hash_rtx_string): Remove export.
* sched-int.h (sched_extend_bbs): Remove export.
(attach_life_info1): Likewise.
(SEL_SCHED_P): Rewrite macro to inline function, rename to sel_sched_p.
Update all uses.
* sel-sched-dump.c, sel-sched-dump.h, sel-sched-ir.c, sel-sched-ir.h,
sel-sched.c, sel-sched.h: Update headers to GPLv3.
* sel-sched.c (cfglayout.h, cselib.h): Remove excessive includes.
Update high-level overview of the scheduler.
(collect_unavailable_regs_from_bnds,
try_replace_dest_reg): Split from ...
(find_best_reg_for_expr): ... here.
(fur_orig_expr_found): Remove needs_spec_check_p.
* sel-sched-ir.h (struct _def): Remove needs_spec_check_p.
Update all uses.
* config/ia64/ia64.c (ia64_sched_init): Check SCHED_GROUP_P bits
when ! sel_sched_p.
(sel2_run): Add comment.
* config/ia64/ia64.opt (ia64_max_memory_insns): Extend comment.
* doc/invoke.texi: Fix documentation wrt removed sel-sched flags.



2008-04-17 Andrey Belevantsev <abel@ispras.ru>


        * sel-sched-ir.c (expr_greater_p): Use UIDs instead of LUIDs
        for comparison.
        * ia64.c (ia64_override_options): Make the selective scheduler
        the default one starting from -O3.

diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/cfgrtl.c cleanup/gcc/cfgrtl.c
*** remote/sel-sched-branch/gcc/cfgrtl.c	Wed Apr 16 00:20:11 2008
--- cleanup/gcc/cfgrtl.c	Thu Apr 17 12:49:41 2008
*************** basic_block
*** 262,268 ****
  create_basic_block_structure (rtx head, rtx end, rtx bb_note, basic_block after)
  {
    basic_block bb;
-   int bb_index;
  
    if (bb_note
        && (bb = NOTE_BASIC_BLOCK (bb_note)) != NULL
--- 262,267 ----
*************** create_basic_block_structure (rtx head, 
*** 282,291 ****
  
        if (after != bb_note && NEXT_INSN (after) != bb_note)
  	reorder_insns_nobb (bb_note, bb_note, after);
- 
-       /* ??? It would be better to set bb_index to BLOCK_NUM (bb_note),
- 	 but that causes add_to_dominance_info () to fail.  */
-       bb_index = last_basic_block++;
      }
    else
      {
--- 281,286 ----
*************** create_basic_block_structure (rtx head, 
*** 312,319 ****
  	}
  
        NOTE_BASIC_BLOCK (bb_note) = bb;
- 
-       bb_index = last_basic_block++;
      }
  
    /* Always include the bb note in the block.  */
--- 307,312 ----
*************** create_basic_block_structure (rtx head, 
*** 322,328 ****
  
    BB_HEAD (bb) = head;
    BB_END (bb) = end;
!   bb->index = bb_index;
    bb->flags = BB_NEW | BB_RTL;
    link_block (bb, after);
    SET_BASIC_BLOCK (bb->index, bb);
--- 315,321 ----
  
    BB_HEAD (bb) = head;
    BB_END (bb) = end;
!   bb->index = last_basic_block++;
    bb->flags = BB_NEW | BB_RTL;
    link_block (bb, after);
    SET_BASIC_BLOCK (bb->index, bb);
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/config/ia64/ia64.c cleanup/gcc/config/ia64/ia64.c
*** remote/sel-sched-branch/gcc/config/ia64/ia64.c	Wed Apr 16 19:41:19 2008
--- cleanup/gcc/config/ia64/ia64.c	Fri Apr 18 12:49:03 2008
*************** ia64_sched_init (FILE *dump ATTRIBUTE_UN
*** 6549,6555 ****
  #ifdef ENABLE_CHECKING
    rtx insn;
  
!   if (0 && reload_completed)
      for (insn = NEXT_INSN (current_sched_info->prev_head);
         insn != current_sched_info->next_tail;
         insn = NEXT_INSN (insn))
--- 6549,6555 ----
  #ifdef ENABLE_CHECKING
    rtx insn;
  
!   if (!sel_sched_p () && reload_completed)
      for (insn = NEXT_INSN (current_sched_info->prev_head);
         insn != current_sched_info->next_tail;
         insn = NEXT_INSN (insn))
*************** ia64_variable_issue (FILE *dump ATTRIBUT
*** 6757,6763 ****
  		     rtx insn ATTRIBUTE_UNUSED,
  		     int can_issue_more ATTRIBUTE_UNUSED)
  {
!   if (sched_deps_info->generate_spec_deps && !SEL_SCHED_P)
      /* Modulo scheduling does not extend h_i_d when emitting
         new instructions.  Don't use h_i_d, if we don't have to.  */
      {
--- 6757,6763 ----
  		     rtx insn ATTRIBUTE_UNUSED,
  		     int can_issue_more ATTRIBUTE_UNUSED)
  {
!   if (sched_deps_info->generate_spec_deps && !sel_sched_p ())
      /* Modulo scheduling does not extend h_i_d when emitting
         new instructions.  Don't use h_i_d, if we don't have to.  */
      {
*************** ia64_free_sched_context (void *_sc)
*** 7052,7126 ****
    free (_sc);
  }
  
- /* Provide information about speculation capabilities.  */
- static void
- ia64_set_sched_flags (spec_info_t spec_info)
- {
-   unsigned int *flags = &(current_sched_info->flags);
- 
-   if (*flags & SCHED_RGN
-       || *flags & SCHED_EBB
-       || *flags & SEL_SCHED)
-     {
-       int mask = 0;
- 
-       if ((!SEL_SCHED_P
- 	   && ((mflag_sched_br_data_spec && !reload_completed && optimize > 0)
- 	       || (mflag_sched_ar_data_spec && reload_completed)))
- 	  || (SEL_SCHED_P && mflag_sel_sched_data_spec))
- 	{
- 	  mask |= BEGIN_DATA;
- 
- 	  if (!SEL_SCHED_P
- 	      && ((mflag_sched_br_in_data_spec && !reload_completed)
- 		  || (mflag_sched_ar_in_data_spec && reload_completed)))
- 	    mask |= BE_IN_DATA;
- 	}
-       
-       if ((!SEL_SCHED_P && mflag_sched_control_spec)
- 	  || (SEL_SCHED_P && mflag_sel_sched_control_spec))
- 	{
- 	  mask |= BEGIN_CONTROL;
- 	  
- 	  if (!SEL_SCHED_P && mflag_sched_in_control_spec)
- 	    mask |= BE_IN_CONTROL;
- 	}
- 
-       spec_info->mask = mask;
- 
-       if (mask)
- 	{
- 	  *flags |= USE_DEPS_LIST | DO_SPECULATION;
- 
- 	  if (mask & BE_IN_SPEC)
-           *flags |= NEW_BBS;
- 	  
- 	  spec_info->mask = mask;
- 	  spec_info->flags = 0;
-       
- 	  if ((mask & DATA_SPEC) && mflag_sched_prefer_non_data_spec_insns)
- 	    spec_info->flags |= PREFER_NON_DATA_SPEC;
- 
- 	  if (mask & CONTROL_SPEC)
- 	    {
- 	      if (mflag_sched_prefer_non_control_spec_insns)
- 		spec_info->flags |= PREFER_NON_CONTROL_SPEC;
- 
- 	      if (SEL_SCHED_P && mflag_sel_sched_dont_check_control_spec)
- 		spec_info->flags |= SEL_SCHED_SPEC_DONT_CHECK_CONTROL;
- 	    }
- 
- 	  if (sched_verbose >= 1)
- 	    spec_info->dump = sched_dump;
- 	  else
- 	    spec_info->dump = 0;
- 	  
- 	  if (mflag_sched_count_spec_in_critical_path)
- 	    spec_info->flags |= COUNT_SPEC_IN_CRITICAL_PATH;
- 	}
-     }
- }
- 
  typedef rtx (* gen_func_t) (rtx, rtx);
  
  /* Return a function that will generate a load of mode MODE_NO
--- 7052,7057 ----
*************** ia64_mode_to_int (enum machine_mode mode
*** 7264,7269 ****
--- 7195,7269 ----
      }
  }
  
+ /* Provide information about speculation capabilities.  */
+ static void
+ ia64_set_sched_flags (spec_info_t spec_info)
+ {
+   unsigned int *flags = &(current_sched_info->flags);
+ 
+   if (*flags & SCHED_RGN
+       || *flags & SCHED_EBB
+       || *flags & SEL_SCHED)
+     {
+       int mask = 0;
+ 
+       if ((!sel_sched_p ()
+ 	   && ((mflag_sched_br_data_spec && !reload_completed && optimize > 0)
+ 	       || (mflag_sched_ar_data_spec && reload_completed)))
+ 	  || (sel_sched_p () && mflag_sel_sched_data_spec))
+ 	{
+ 	  mask |= BEGIN_DATA;
+ 
+ 	  if (!sel_sched_p ()
+ 	      && ((mflag_sched_br_in_data_spec && !reload_completed)
+ 		  || (mflag_sched_ar_in_data_spec && reload_completed)))
+ 	    mask |= BE_IN_DATA;
+ 	}
+       
+       if ((!sel_sched_p () && mflag_sched_control_spec)
+ 	  || (sel_sched_p () && mflag_sel_sched_control_spec))
+ 	{
+ 	  mask |= BEGIN_CONTROL;
+ 	  
+ 	  if (!sel_sched_p () && mflag_sched_in_control_spec)
+ 	    mask |= BE_IN_CONTROL;
+ 	}
+ 
+       spec_info->mask = mask;
+ 
+       if (mask)
+ 	{
+ 	  *flags |= USE_DEPS_LIST | DO_SPECULATION;
+ 
+ 	  if (mask & BE_IN_SPEC)
+           *flags |= NEW_BBS;
+ 	  
+ 	  spec_info->mask = mask;
+ 	  spec_info->flags = 0;
+       
+ 	  if ((mask & DATA_SPEC) && mflag_sched_prefer_non_data_spec_insns)
+ 	    spec_info->flags |= PREFER_NON_DATA_SPEC;
+ 
+ 	  if (mask & CONTROL_SPEC)
+ 	    {
+ 	      if (mflag_sched_prefer_non_control_spec_insns)
+ 		spec_info->flags |= PREFER_NON_CONTROL_SPEC;
+ 
+ 	      if (sel_sched_p () && mflag_sel_sched_dont_check_control_spec)
+ 		spec_info->flags |= SEL_SCHED_SPEC_DONT_CHECK_CONTROL;
+ 	    }
+ 
+ 	  if (sched_verbose >= 1)
+ 	    spec_info->dump = sched_dump;
+ 	  else
+ 	    spec_info->dump = 0;
+ 	  
+ 	  if (mflag_sched_count_spec_in_critical_path)
+ 	    spec_info->flags |= COUNT_SPEC_IN_CRITICAL_PATH;
+ 	}
+     }
+ }
+ 
  /* If INSN is an appropriate load return its mode.
     Return -1 otherwise.  */
  static int
*************** ia64_speculate_insn (rtx insn, ds_t ts, 
*** 7519,7532 ****
  
    if (mode_no != SPEC_MODE_INVALID)
      {
-       if (0 && SEL_SCHED_P && (ts & BEGIN_DATA)
- 	  && mode_no >= 5 && mode_no <= 7)
- 	/* !!! We can't data speculate float point loads because we might
- 	   get a trap-looking insn from the trap-free one.  This happens
- 	   because of the UNSPEC:?F part in the load, that is a floating
- 	   point operation that might trap.  */
- 	return -1;
- 
        if (ia64_get_insn_spec_ds (insn) == ds_get_speculation_types (ts))
  	res = 0;
        else
--- 7519,7524 ----
*************** emit_predicate_relation_info (void)
*** 9098,9103 ****
--- 9090,9096 ----
      }
  }
  
+ /* Counts how many times selective scheduling was run.  */
  static int sel2_run = 0;
  
  /* Perform machine dependent operations on the rtl chain INSNS.  */
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/config/ia64/ia64.opt cleanup/gcc/config/ia64/ia64.opt
*** remote/sel-sched-branch/gcc/config/ia64/ia64.opt	Mon Apr 14 18:39:37 2008
--- cleanup/gcc/config/ia64/ia64.opt	Thu Apr 17 12:49:41 2008
*************** Assume that floating-point stores and lo
*** 150,156 ****
  
  msched-max-memory-insns=
  Target RejectNegative Joined UInteger Var(ia64_max_memory_insns) Init(1)
! Limit on number of memory insns per instruction group. Frequently useful to prevent cache bank conflicts. Default value is 1
  
  msched-max-memory-insns-hard-limit
  Target Report Var(mflag_sched_mem_insns_hard_limit) Init(0)
--- 150,156 ----
  
  msched-max-memory-insns=
  Target RejectNegative Joined UInteger Var(ia64_max_memory_insns) Init(1)
! Soft limit on number of memory insns per instruction group, giving lower priority to subsequent memory insns attempting to schedule in the same insn group. Frequently useful to prevent cache bank conflicts.  Default value is 1
  
  msched-max-memory-insns-hard-limit
  Target Report Var(mflag_sched_mem_insns_hard_limit) Init(0)
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/config/rs6000/rs6000.c cleanup/gcc/config/rs6000/rs6000.c
*** remote/sel-sched-branch/gcc/config/rs6000/rs6000.c	Wed Apr 16 00:19:28 2008
--- cleanup/gcc/config/rs6000/rs6000.c	Thu Apr 17 20:10:02 2008
*************** rs6000_sched_reorder2 (FILE *dump, int s
*** 18895,18901 ****
                      ready[i] = ready[i + 1];
                    ready[*pn_ready-1] = tmp;
  
!                   if (!SEL_SCHED_P && INSN_PRIORITY_KNOWN (tmp))
                      INSN_PRIORITY (tmp)++;
                    break;
                  }
--- 18895,18901 ----
                      ready[i] = ready[i + 1];
                    ready[*pn_ready-1] = tmp;
  
!                   if (!sel_sched_p () && INSN_PRIORITY_KNOWN (tmp))
                      INSN_PRIORITY (tmp)++;
                    break;
                  }
*************** rs6000_sched_reorder2 (FILE *dump, int s
*** 18912,18918 ****
            while (pos >= 0)
              {
                if (is_load_insn (ready[pos])
!                   && !SEL_SCHED_P
  		  && INSN_PRIORITY_KNOWN (ready[pos]))
                  {
                    INSN_PRIORITY (ready[pos])++;
--- 18912,18918 ----
            while (pos >= 0)
              {
                if (is_load_insn (ready[pos])
!                   && !sel_sched_p ()
  		  && INSN_PRIORITY_KNOWN (ready[pos]))
                  {
                    INSN_PRIORITY (ready[pos])++;
*************** rs6000_sched_reorder2 (FILE *dump, int s
*** 18956,18962 ****
                          ready[i] = ready[i + 1];
                        ready[*pn_ready-1] = tmp;
  
!                       if (!SEL_SCHED_P && INSN_PRIORITY_KNOWN (tmp))
                          INSN_PRIORITY (tmp)++;
  
                        first_store_pos = -1;
--- 18956,18962 ----
                          ready[i] = ready[i + 1];
                        ready[*pn_ready-1] = tmp;
  
!                       if (!sel_sched_p () && INSN_PRIORITY_KNOWN (tmp))
                          INSN_PRIORITY (tmp)++;
  
                        first_store_pos = -1;
*************** rs6000_sched_reorder2 (FILE *dump, int s
*** 18977,18983 ****
                for (i=first_store_pos; i<*pn_ready-1; i++)
                  ready[i] = ready[i + 1];
                ready[*pn_ready-1] = tmp;
!               if (!SEL_SCHED_P && INSN_PRIORITY_KNOWN (tmp))
                  INSN_PRIORITY (tmp)++;
              }
          }
--- 18977,18983 ----
                for (i=first_store_pos; i<*pn_ready-1; i++)
                  ready[i] = ready[i + 1];
                ready[*pn_ready-1] = tmp;
!               if (!sel_sched_p () && INSN_PRIORITY_KNOWN (tmp))
                  INSN_PRIORITY (tmp)++;
              }
          }
*************** rs6000_sched_reorder2 (FILE *dump, int s
*** 18991,18997 ****
            while (pos >= 0)
              {
                if (is_store_insn (ready[pos])
!                   && !SEL_SCHED_P
  		  && INSN_PRIORITY_KNOWN (ready[pos]))
                  {
                    INSN_PRIORITY (ready[pos])++;
--- 18991,18997 ----
            while (pos >= 0)
              {
                if (is_store_insn (ready[pos])
!                   && !sel_sched_p ()
  		  && INSN_PRIORITY_KNOWN (ready[pos]))
                  {
                    INSN_PRIORITY (ready[pos])++;
*************** rs6000_sched_finish (FILE *dump, int sch
*** 19549,19555 ****
    if (reload_completed && rs6000_sched_groups)
      {
        if (rs6000_sched_insert_nops == sched_finish_none
! 	  || SEL_SCHED_P)
  	return;
  
        if (rs6000_sched_insert_nops == sched_finish_pad_groups)
--- 19549,19555 ----
    if (reload_completed && rs6000_sched_groups)
      {
        if (rs6000_sched_insert_nops == sched_finish_none
! 	  || sel_sched_p ())
  	return;
  
        if (rs6000_sched_insert_nops == sched_finish_pad_groups)
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/cse.c cleanup/gcc/cse.c
*** remote/sel-sched-branch/gcc/cse.c	Wed Apr 16 00:06:04 2008
--- cleanup/gcc/cse.c	Fri Apr 18 10:31:53 2008
*************** static rtx use_related_value (rtx, struc
*** 573,578 ****
--- 573,579 ----
  
  static inline unsigned canon_hash (rtx, enum machine_mode);
  static inline unsigned safe_hash (rtx, enum machine_mode);
+ static inline unsigned hash_rtx_string (const char *);
  
  static rtx canon_reg (rtx, rtx);
  static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
*************** use_related_value (rtx x, struct table_e
*** 2045,2051 ****
  
  
  /* Hash a string.  Just add its bytes up.  */
! unsigned
  hash_rtx_string (const char *ps)
  {
    unsigned hash = 0;
--- 2046,2052 ----
  
  
  /* Hash a string.  Just add its bytes up.  */
! static inline unsigned
  hash_rtx_string (const char *ps)
  {
    unsigned hash = 0;
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/doc/invoke.texi cleanup/gcc/doc/invoke.texi
*** remote/sel-sched-branch/gcc/doc/invoke.texi	Wed Apr 16 00:01:35 2008
--- cleanup/gcc/doc/invoke.texi	Thu Apr 17 20:47:15 2008
*************** Objective-C and Objective-C++ Dialects}.
*** 351,359 ****
  -fsched2-use-traces -fsched-spec-load -fsched-spec-load-dangerous @gol
  -fsched-stalled-insns-dep[=@var{n}] -fsched-stalled-insns[=@var{n}] @gol
  -fschedule-insns -fschedule-insns2 -fsection-anchors -fsee @gol
! -fselective-scheduling -fsel-sched-emulate-haifa -fsel-sched-bookkeeping @gol
  -fsel-sched-pipelining -fsel-sched-renaming -fsel-sched-substitution @gol
- -fsel-sched-single-block-regions -fsel-sched-ebb-regions @gol
  -fsignaling-nans -fsingle-precision-constant -fsplit-ivs-in-unroller @gol
  -fsplit-wide-types -fstack-protector -fstack-protector-all @gol
  -fstrict-aliasing -fstrict-overflow -fthread-jumps -ftracer -ftree-ccp @gol
--- 351,358 ----
  -fsched2-use-traces -fsched-spec-load -fsched-spec-load-dangerous @gol
  -fsched-stalled-insns-dep[=@var{n}] -fsched-stalled-insns[=@var{n}] @gol
  -fschedule-insns -fschedule-insns2 -fsection-anchors -fsee @gol
! -fselective-scheduling -fselective-scheduling2 -fsel-sched-bookkeeping @gol
  -fsel-sched-pipelining -fsel-sched-renaming -fsel-sched-substitution @gol
  -fsignaling-nans -fsingle-precision-constant -fsplit-ivs-in-unroller @gol
  -fsplit-wide-types -fstack-protector -fstack-protector-all @gol
  -fstrict-aliasing -fstrict-overflow -fthread-jumps -ftracer -ftree-ccp @gol
*************** and unit/insn info.  For @var{n} greater
*** 4947,4956 ****
  at abort point, control-flow and regions info.  And for @var{n} over
  four, @option{-fsched-verbose} also includes dependence info.
  
- @item -fsel-sched-verbose
- @opindex sel-sched-verbose
- Be verbose when running selective scheduling.
- 
  @item -fsel-sched-dump-cfg
  @opindex sel-sched-dump-cfg
  Dump CFG information during selective scheduling pass.
--- 4946,4951 ----
*************** from changing its schedule, we use this 
*** 5750,5762 ****
  @item -fselective-scheduling
  @opindex fselective-scheduling
  Schedule instructions using selective scheduling algorithm.  Selective
! scheduling runs instead of second haifa scheduler pass.
  
! @item -fsel-sched-emulate-haifa
! @opindex fsel-sched-emulate-haifa
! Emulate Haifa scheduler for better cooperation with the target.  With this
! option selective scheduling will call target hooks the same way haifa scheduler
! does before finishing scheduling.
  
  @item -fsel-sched-bookkeeping
  @opindex fsel-sched-bookkeeping
--- 5745,5756 ----
  @item -fselective-scheduling
  @opindex fselective-scheduling
  Schedule instructions using selective scheduling algorithm.  Selective
! scheduling runs instead of the first haifa scheduler pass.
  
! @item -fselective-scheduling2
! @opindex fselective-scheduling2
! Schedule instructions using selective scheduling algorithm.  Selective
! scheduling runs instead of the second haifa scheduler pass.
  
  @item -fsel-sched-bookkeeping
  @opindex fsel-sched-bookkeeping
*************** This option is useful in combination wit
*** 5784,5797 ****
  move instructions through back loop edges, though
  @option{-fsel-sched-pipelining} is not required for substitution to work.
  
- @item -fsel-sched-single-block-regions
- @opindex fsel-sched-single-block-regions
- Run selective scheduling on single basic block regions.
- 
- @item -fsel-sched-ebb-regions
- @opindex fsel-sched-ebb-regions
- Run selective scheduling on extended basic block regions.
- 
  @item -fcaller-saves
  @opindex fcaller-saves
  Enable values to be allocated in registers that will be clobbered by
--- 5778,5783 ----
*************** The default value is 40.
*** 7316,7322 ****
  @item selsched-max-lookahead
  The maximum size of the lookahead window of selective scheduling.  It is a
  depth of search for available instructions.
! The default value is 32.
  
  @item max-last-value-rtl
  
--- 7302,7308 ----
  @item selsched-max-lookahead
  The maximum size of the lookahead window of selective scheduling.  It is a
  depth of search for available instructions.
! The default value is 50.
  
  @item max-last-value-rtl
  
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/haifa-sched.c cleanup/gcc/haifa-sched.c
*** remote/sel-sched-branch/gcc/haifa-sched.c	Wed Apr 16 00:05:52 2008
--- cleanup/gcc/haifa-sched.c	Fri Apr 18 12:49:03 2008
*************** static int may_trap_exp (const_rtx, int)
*** 331,336 ****
--- 331,369 ----
  /* Returns a class that insn with GET_DEST(insn)=x may belong to,
     as found by analyzing insn's expression.  */
  
+ 
+ static int haifa_luid_for_non_insn (rtx x);
+ 
+ /* Haifa version of sched_info hooks common to all headers.  */
+ const struct common_sched_info_def haifa_common_sched_info = 
+   {
+     NULL, /* fix_recovery_cfg */
+     NULL, /* add_block */
+     NULL, /* estimate_number_of_insns */
+     haifa_luid_for_non_insn, /* luid_for_non_insn */
+     SCHED_PASS_UNKNOWN /* sched_pass_id */
+   };
+ 
+ const struct sched_scan_info_def *sched_scan_info;
+ 
+ /* Mapping from instruction UID to its Logical UID.  */
+ VEC (int, heap) *sched_luids = NULL;
+ 
+ /* Next LUID to assign to an instruction.  */
+ int sched_max_luid = 1;
+ 
+ /* Haifa Instruction Data.  */
+ VEC (haifa_insn_data_def, heap) *h_i_d = NULL;
+ 
+ void (* sched_init_only_bb) (basic_block, basic_block);
+ 
+ /* Split block function.  Different schedulers might use different functions
+    to handle their internal data consistent.  */
+ basic_block (* sched_split_block) (basic_block, rtx);
+ 
+ /* Create empty basic block after the specified block.  */
+ basic_block (* sched_create_empty_bb) (basic_block);
+ 
  static int
  may_trap_exp (const_rtx x, int is_store)
  {
*************** insn_cost (rtx insn)
*** 573,579 ****
  {
    int cost;
  
!   if (SEL_SCHED_P)
      {
        if (recog_memoized (insn) < 0)
  	return 0;
--- 606,612 ----
  {
    int cost;
  
!   if (sel_sched_p ())
      {
        if (recog_memoized (insn) < 0)
  	return 0;
*************** priority (rtx insn)
*** 743,749 ****
  	     recovery block.  */ 
  
            /* Selective scheduling does not define RECOVERY_BLOCK macro.  */
! 	  rec = SEL_SCHED_P ? NULL : RECOVERY_BLOCK (insn);
  	  if (!rec || rec == EXIT_BLOCK_PTR)
  	    {
  	      prev_first = PREV_INSN (insn);
--- 776,782 ----
  	     recovery block.  */ 
  
            /* Selective scheduling does not define RECOVERY_BLOCK macro.  */
! 	  rec = sel_sched_p () ? NULL : RECOVERY_BLOCK (insn);
  	  if (!rec || rec == EXIT_BLOCK_PTR)
  	    {
  	      prev_first = PREV_INSN (insn);
*************** priority (rtx insn)
*** 797,803 ****
  	  while (twin != prev_first);
  	}
  
-       /* NB: This fix should be submitted to gcc-patches.  */
        if (this_priority < 0)
  	{
  	  gcc_assert (this_priority == -1);
--- 830,835 ----
*************** unlink_other_notes (rtx insn, rtx tail)
*** 1348,1354 ****
  
    if (insn == tail)
      {
!       gcc_assert (common_sched_info->sched_pass_id == SCHED_SEL_PASS);
        return prev;
      }
  
--- 1380,1386 ----
  
    if (insn == tail)
      {
!       gcc_assert (sel_sched_p ());
        return prev;
      }
  
*************** rm_other_notes (rtx head, rtx tail)
*** 1432,1438 ****
  	  prev = insn;
  	  insn = unlink_other_notes (insn, next_tail);
  
! 	  gcc_assert ((common_sched_info->sched_pass_id == SCHED_SEL_PASS
  		       || prev != tail) && prev != head && insn != next_tail);
  	}
      }
--- 1464,1470 ----
  	  prev = insn;
  	  insn = unlink_other_notes (insn, next_tail);
  
! 	  gcc_assert ((sel_sched_p ()
  		       || prev != tail) && prev != head && insn != next_tail);
  	}
      }
*************** choose_ready (struct ready_list *ready, 
*** 2258,2264 ****
  			|| recog_memoized (insn) < 0);
  
  	    ready_try [i]
! 	      = (/* INSN_CODE check can be omited here as it is also done later
  		    in max_issue ().  */
  		 INSN_CODE (insn) < 0
  		 || (targetm.sched.first_cycle_multipass_dfa_lookahead_guard
--- 2290,2296 ----
  			|| recog_memoized (insn) < 0);
  
  	    ready_try [i]
! 	      = (/* INSN_CODE check can be omitted here as it is also done later
  		    in max_issue ().  */
  		 INSN_CODE (insn) < 0
  		 || (targetm.sched.first_cycle_multipass_dfa_lookahead_guard
*************** choose_ready (struct ready_list *ready, 
*** 2269,2282 ****
        if (max_issue (ready, 1, curr_state, &index) == 0)
  	{
  	  if (sched_verbose >= 4)
! 	    fprintf (sched_dump, ";;\t\tChoosed none\n");
  	  *insn_ptr = ready_remove_first (ready);
  	  return 0;
  	}
        else
  	{
  	  if (sched_verbose >= 4)    
! 	    fprintf (sched_dump, ";;\t\tChoosed insn : %s\n",
  		     (*current_sched_info->print_insn)
  		     (ready_element (ready, index), 0));
            
--- 2301,2314 ----
        if (max_issue (ready, 1, curr_state, &index) == 0)
  	{
  	  if (sched_verbose >= 4)
! 	    fprintf (sched_dump, ";;\t\tChosen none\n");
  	  *insn_ptr = ready_remove_first (ready);
  	  return 0;
  	}
        else
  	{
  	  if (sched_verbose >= 4)    
! 	    fprintf (sched_dump, ";;\t\tChosen insn : %s\n",
  		     (*current_sched_info->print_insn)
  		     (ready_element (ready, index), 0));
            
*************** schedule_block (basic_block *target_bb)
*** 2696,2733 ****
  	  }
      }
  
-   /* Debugging.  */
    if (sched_verbose)
!     {
!       if (sched_verbose >= 6)
! 	{
! 	  rtx insn = NEXT_INSN (prev_head);
! 	  rtx next_tail = NEXT_INSN (last_scheduled_insn);
! 	  int last_clock = -1;
! 	  int clock = 0;
! 
! 	  while (insn != next_tail)
! 	    {
! 	      char buf[2048];
! 	      int cost;
! 
! 	      clock = INSN_TICK (insn);
! 	      cost = clock - last_clock;
! 
! 	      print_insn (buf, insn, 0);
! 	      fprintf (sched_dump, "    cost: %d\t(pat:%s;bb:%d;cycle:%d;)\n",
! 		       cost, buf, BLOCK_NUM (insn), clock);
! 
! 	      last_clock = clock;
! 
! 	      insn = NEXT_INSN (insn);
! 	    }
! 
! 	  gcc_assert (last_clock == clock_var);
! 	}
! 
!       fprintf (sched_dump, ";;   total time = %d\n", clock_var);
!     }
  
    if (!current_sched_info->queue_must_finish_empty
        || haifa_recovery_bb_recently_added_p)
--- 2728,2735 ----
  	  }
      }
  
    if (sched_verbose)
!     fprintf (sched_dump, ";;   total time = %d\n", clock_var);
  
    if (!current_sched_info->queue_must_finish_empty
        || haifa_recovery_bb_recently_added_p)
*************** haifa_sched_finish (void)
*** 2987,2993 ****
       function.  Target will be finalized in md_global_finish ().  */
    sched_deps_finish ();
    sched_finish_luids ();
-   sched_finish_bbs ();
    current_sched_info = NULL;
    sched_finish ();
  }
--- 2989,2994 ----
*************** haifa_luid_for_non_insn (rtx x)
*** 3425,3439 ****
    return 0;
  }
  
- const struct common_sched_info_def haifa_common_sched_info = 
-   {
-     NULL, /* fix_recovery_cfg */
-     NULL, /* add_block */
-     NULL, /* estimate_number_of_insns */
-     haifa_luid_for_non_insn, /* luid_for_non_insn */
-     SCHED_PASS_UNKNOWN /* sched_pass_id */
-   };
- 
  /* Generates recovery code for INSN.  */
  static void
  generate_recovery_code (rtx insn)
--- 3426,3431 ----
*************** check_cfg (rtx head, rtx tail)
*** 4727,4748 ****
    gcc_assert (bb == 0);
  }
  
- #if 0
- /* Perform a few consistency checks of flags in different data structures.  */
- static void
- check_sched_flags (void)
- {
-   if (SEL_SCHED_P)
-     return;
- 
-   if (flag_sched_stalled_insns)
-     gcc_assert (!sched_deps_info->generate_spec_deps);
-   if (sched_deps_info->generate_spec_deps)
-     gcc_assert (!flag_sched_stalled_insns
- 		&& spec_info
- 		&& spec_info->mask);
- }
- #endif
  #endif /* ENABLE_CHECKING */
  
  const struct sched_scan_info_def *sched_scan_info;
--- 4719,4724 ----
*************** init_insns_in_bb (basic_block bb)
*** 4791,4798 ****
  
  /* A driver function to add a set of basic blocks (BBS),
     a single basic block (BB), a set of insns (INSNS) or a single insn (INSN)
!    to the scheduling region.
!    !!! This driver was only tested with one of the arguments non null.  */
  void
  sched_scan (const struct sched_scan_info_def *ssi,
  	    bb_vec_t bbs, basic_block bb, insn_vec_t insns, rtx insn)
--- 4767,4773 ----
  
  /* A driver function to add a set of basic blocks (BBS),
     a single basic block (BB), a set of insns (INSNS) or a single insn (INSN)
!    to the scheduling region.  */
  void
  sched_scan (const struct sched_scan_info_def *ssi,
  	    bb_vec_t bbs, basic_block bb, insn_vec_t insns, rtx insn)
*************** sched_init_bbs (void)
*** 4872,4887 ****
    sched_extend_bb ();
  }
  
- /* Finish per basic block data structures.  */
- void
- sched_finish_bbs (void)
- {
- }
- 
- 
- /* Mapping from instruction UID to its Logical UID.  */
- VEC (int, heap) *sched_luids = NULL;
- 
  /* Extend data structures for logical insn UID.  */
  static void
  luids_extend_insn (void)
--- 4847,4852 ----
*************** luids_extend_insn (void)
*** 4891,4899 ****
    VEC_safe_grow_cleared (int, heap, sched_luids, new_luids_max_uid);
  }
  
- /* Next LUID to assign to an instruction.  */
- int sched_max_luid = 1;
- 
  /* Initialize LUID for INSN.  */
  static void
  luids_init_insn (rtx insn)
--- 4856,4861 ----
*************** sched_extend_target (void)
*** 4952,4960 ****
      targetm.sched.h_i_d_extended ();
  }
  
- /* Haifa Instruction Data.  */
- VEC (haifa_insn_data_def, heap) *h_i_d = NULL;
- 
  /* Extend global scheduler structures (those, that live across calls to
     schedule_block) to include information about just emitted INSN.  */
  static void
--- 4914,4919 ----
*************** haifa_init_insn (rtx insn)
*** 5029,5036 ****
      }
  }
  
- void (* sched_init_only_bb) (basic_block, basic_block);
- 
  /* Init data for the new basic block BB which comes after AFTER.  */
  static void
  haifa_init_only_bb (basic_block bb, basic_block after)
--- 4988,4993 ----
*************** haifa_init_only_bb (basic_block bb, basi
*** 5044,5053 ****
      common_sched_info->add_block (bb, after);
  }
  
- /* Split block function.  Different schedulers might use different functions
-    to handle their internal data consistent.  */
- basic_block (* sched_split_block) (basic_block, rtx);
- 
  /* A generic version of sched_split_block ().  */
  basic_block
  sched_split_block_1 (basic_block first_bb, rtx after)
--- 5001,5006 ----
*************** sched_split_block_1 (basic_block first_b
*** 5063,5071 ****
    return e->dest;
  }
  
- /* Create empty basic block after the specified block.  */
- basic_block (* sched_create_empty_bb) (basic_block);
- 
  /* A generic version of sched_create_empty_bb ().  */
  basic_block
  sched_create_empty_bb_1 (basic_block after)
--- 5016,5021 ----
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/loop-init.c cleanup/gcc/loop-init.c
*** remote/sel-sched-branch/gcc/loop-init.c	Wed Apr 16 00:06:16 2008
--- cleanup/gcc/loop-init.c	Fri Apr 18 12:49:03 2008
*************** loop_optimizer_init (unsigned flags)
*** 64,82 ****
    else
      disambiguate_loops_with_multiple_latches ();
  
-   if (flags & LOOPS_MAY_HAVE_MULTIPLE_LATCHES)
-     {
-       /* If the loops may have multiple latches, we cannot canonicalize
- 	 them further (and most of the loop manipulation functions will
- 	 not work).  However, we avoid modifying cfg, which some
- 	 passes may want.  */
-       gcc_assert ((flags & ~(LOOPS_MAY_HAVE_MULTIPLE_LATCHES
- 			     | LOOPS_HAVE_RECORDED_EXITS)) == 0);
-       current_loops->state = LOOPS_MAY_HAVE_MULTIPLE_LATCHES;
-     }
-   else
-     disambiguate_loops_with_multiple_latches ();
- 
    /* Create pre-headers.  */
    if (flags & LOOPS_HAVE_PREHEADERS)
      {
--- 64,69 ----
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/modulo-sched.c cleanup/gcc/modulo-sched.c
*** remote/sel-sched-branch/gcc/modulo-sched.c	Wed Apr 16 00:05:58 2008
--- cleanup/gcc/modulo-sched.c	Fri Apr 18 12:49:03 2008
*************** static int compute_split_row (sbitmap, i
*** 187,201 ****
  /* This page defines constants and structures for the modulo scheduling
     driver.  */
  
- #if 0
- /* As in haifa-sched.c:  */
- /* issue_rate is the number of insns that can be scheduled in the same
-    machine cycle.  It can be defined in the config/mach/mach.h file,
-    otherwise we set it to 1.  */
- 
- static int issue_rate;
- #endif
- 
  static int sms_order_nodes (ddg_ptr, int, int *, int *);
  static void set_node_sched_params (ddg_ptr);
  static partial_schedule_ptr sms_schedule_by_order (ddg_ptr, int, int, int *);
--- 187,192 ----
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/opts.c cleanup/gcc/opts.c
*** remote/sel-sched-branch/gcc/opts.c	Wed Apr 16 00:46:03 2008
--- cleanup/gcc/opts.c	Thu Apr 17 12:49:41 2008
*************** decode_options (unsigned int argc, const
*** 1044,1050 ****
        flag_reorder_blocks = 1;
      }
  
!   /* Pipelining outer loops is only possible when general pipelining
       capabilities are requested.  */
    if (!flag_sel_sched_pipelining)
      flag_sel_sched_pipelining_outer_loops = 0;
--- 1044,1050 ----
        flag_reorder_blocks = 1;
      }
  
!   /* Pipelining of outer loops is only possible when general pipelining
       capabilities are requested.  */
    if (!flag_sel_sched_pipelining)
      flag_sel_sched_pipelining_outer_loops = 0;
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/rtl.h cleanup/gcc/rtl.h
*** remote/sel-sched-branch/gcc/rtl.h	Wed Apr 16 00:17:38 2008
--- cleanup/gcc/rtl.h	Thu Apr 17 17:41:22 2008
*************** extern int delete_trivially_dead_insns (
*** 2030,2036 ****
  extern int cse_main (rtx, int);
  extern int exp_equiv_p (const_rtx, const_rtx, int, bool);
  extern unsigned hash_rtx (const_rtx x, enum machine_mode, int *, int *, bool);
- extern unsigned hash_rtx_string (const char *);
  
  /* In jump.c */
  extern int comparison_dominates_p (enum rtx_code, enum rtx_code);
--- 2030,2035 ----
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/rtlanal.c cleanup/gcc/rtlanal.c
*** remote/sel-sched-branch/gcc/rtlanal.c	Wed Apr 16 00:02:21 2008
--- cleanup/gcc/rtlanal.c	Thu Apr 17 12:49:41 2008
*************** may_trap_p_1 (const_rtx x, unsigned flag
*** 2193,2199 ****
    if (x == 0)
      return 0;
    code = GET_CODE (x);
- 
    switch (code)
      {
        /* Handle these cases quickly.  */
--- 2193,2198 ----
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/sched-deps.c cleanup/gcc/sched-deps.c
*** remote/sel-sched-branch/gcc/sched-deps.c	Mon Apr 14 18:59:54 2008
--- cleanup/gcc/sched-deps.c	Thu Apr 17 12:49:41 2008
*************** along with GCC; see the file COPYING3.  
*** 42,48 ****
  #include "params.h"
  #include "cselib.h"
  
- 
  #ifdef INSN_SCHEDULING
  
  #ifdef ENABLE_CHECKING
--- 42,47 ----
*************** sd_add_dep (dep_t dep, bool resolved_p)
*** 1153,1159 ****
  
    add_to_deps_list (DEP_NODE_BACK (n), con_back_deps);
  
- 
  #ifdef ENABLE_CHECKING
    check_dep (dep, false);
  #endif
--- 1152,1157 ----
*************** sched_analyze_reg (struct deps *deps, in
*** 1684,1690 ****
  		   enum rtx_code ref, rtx insn)
  {
    /* We could emit new pseudos in renaming.  Extend the reg structures.  */
!   if (!reload_completed && SEL_SCHED_P
        && (regno >= max_reg_num () - 1 || regno >= deps->max_reg))
      extend_deps_reg_info (deps, regno);
  
--- 1682,1688 ----
  		   enum rtx_code ref, rtx insn)
  {
    /* We could emit new pseudos in renaming.  Extend the reg structures.  */
!   if (!reload_completed && sel_sched_p ()
        && (regno >= max_reg_num () - 1 || regno >= deps->max_reg))
      extend_deps_reg_info (deps, regno);
  
*************** sched_analyze_reg (struct deps *deps, in
*** 1740,1749 ****
  
        /* Don't let it cross a call after scheduling if it doesn't
  	 already cross one.  
! 	 If REGNO >= REG_INFO_P_SIZE then it was introduced in our scheduler,
! 	 and it could have happened only before reload.  Thus, we can consider
! 	 INSN moveable, since reload should take care of the all the operations
! 	 renamed into new pseudos.  */	 
        if (regno < FIRST_PSEUDO_REGISTER 
  	  && REG_N_CALLS_CROSSED (regno) == 0)
  	{
--- 1738,1747 ----
  
        /* Don't let it cross a call after scheduling if it doesn't
  	 already cross one.  
! 	 If REGNO >= REG_INFO_P_SIZE, then it was introduced in selective
! 	 scheduling, and it could have happened only before reload.  
! 	 Thus, we can consider INSN moveable, since reload should take care of
! 	 the all the operations renamed into new pseudos.  */	 
        if (regno < FIRST_PSEUDO_REGISTER 
  	  && REG_N_CALLS_CROSSED (regno) == 0)
  	{
*************** sched_analyze_2 (struct deps *deps, rtx 
*** 2068,2074 ****
  	    else if (deps_may_trap_p (x))
  	      {
  		if ((sched_deps_info->generate_spec_deps)
! 		    && SEL_SCHED_P && (spec_info->mask & BEGIN_CONTROL))
  		  {
  		    ds_t ds = set_dep_weak (DEP_ANTI, BEGIN_CONTROL,
  					    MAX_DEP_WEAK);
--- 2066,2072 ----
  	    else if (deps_may_trap_p (x))
  	      {
  		if ((sched_deps_info->generate_spec_deps)
! 		    && sel_sched_p () && (spec_info->mask & BEGIN_CONTROL))
  		  {
  		    ds_t ds = set_dep_weak (DEP_ANTI, BEGIN_CONTROL,
  					    MAX_DEP_WEAK);
*************** sched_analyze_insn (struct deps *deps, r
*** 2512,2518 ****
            }
  
        /* Flush pending lists on jumps, but not on speculative checks.  */
!       if (JUMP_P (insn) && !(SEL_SCHED_P 
                               && sel_insn_is_speculation_check (insn)))
  	flush_pending_lists (deps, insn, true, true);
        
--- 2510,2516 ----
            }
  
        /* Flush pending lists on jumps, but not on speculative checks.  */
!       if (JUMP_P (insn) && !(sel_sched_p () 
                               && sel_insn_is_speculation_check (insn)))
  	flush_pending_lists (deps, insn, true, true);
        
*************** sched_analyze_insn (struct deps *deps, r
*** 2530,2536 ****
       be moved into a different basic block.  */
  
    if (deps->libcall_block_tail_insn
!       && (!SEL_SCHED_P || sched_emulate_haifa_p))
      {
        SCHED_GROUP_P (insn) = 1;
        CANT_MOVE (insn) = 1;
--- 2528,2534 ----
       be moved into a different basic block.  */
  
    if (deps->libcall_block_tail_insn
!       && (!sel_sched_p () || sched_emulate_haifa_p))
      {
        SCHED_GROUP_P (insn) = 1;
        CANT_MOVE (insn) = 1;
*************** sched_analyze_insn (struct deps *deps, r
*** 2582,2588 ****
                && deps->in_post_call_group_p == post_call_initial)
  	    deps->in_post_call_group_p = post_call;
  
!           if (!SEL_SCHED_P || sched_emulate_haifa_p) 
              {
                SCHED_GROUP_P (insn) = 1;
                CANT_MOVE (insn) = 1;
--- 2580,2586 ----
                && deps->in_post_call_group_p == post_call_initial)
  	    deps->in_post_call_group_p = post_call;
  
!           if (!sel_sched_p () || sched_emulate_haifa_p) 
              {
                SCHED_GROUP_P (insn) = 1;
                CANT_MOVE (insn) = 1;
*************** sched_analyze_insn (struct deps *deps, r
*** 2601,2607 ****
      /* INSN has an internal dependency (e.g. r14 = [r14]) and thus cannot
         be speculated.  */
      {
!       if (SEL_SCHED_P)
          sel_mark_hard_insn (insn);
        else
          {
--- 2599,2605 ----
      /* INSN has an internal dependency (e.g. r14 = [r14]) and thus cannot
         be speculated.  */
      {
!       if (sel_sched_p ())
          sel_mark_hard_insn (insn);
        else
          {
*************** deps_analyze_insn (struct deps *deps, rt
*** 2630,2636 ****
           a scheduling barrier for memory references.  */
        if (!deps->readonly
            && JUMP_P (insn) 
!           && !(SEL_SCHED_P 
                 && sel_insn_is_speculation_check (insn)))
          {
            /* Keep the list a reasonable size.  */
--- 2628,2634 ----
           a scheduling barrier for memory references.  */
        if (!deps->readonly
            && JUMP_P (insn) 
!           && !(sel_sched_p () 
                 && sel_insn_is_speculation_check (insn)))
          {
            /* Keep the list a reasonable size.  */
*************** deps_analyze_insn (struct deps *deps, rt
*** 2778,2784 ****
  
    /* Fixup the dependencies in the sched group.  */
    if ((NONJUMP_INSN_P (insn) || JUMP_P (insn)) 
!       && SCHED_GROUP_P (insn) && !SEL_SCHED_P)
      fixup_sched_groups (insn);
  }
  
--- 2776,2782 ----
  
    /* Fixup the dependencies in the sched group.  */
    if ((NONJUMP_INSN_P (insn) || JUMP_P (insn)) 
!       && SCHED_GROUP_P (insn) && !sel_sched_p ())
      fixup_sched_groups (insn);
  }
  
*************** sched_deps_init (bool global_p)
*** 3012,3018 ****
    
    /* We use another caching mechanism for selective scheduling, so 
       we don't use this one.  */
!   if (!SEL_SCHED_P && global_p && insns_in_block > 100 * 5)
      {
        /* ?!? We could save some memory by computing a per-region luid mapping
           which could reduce both the number of vectors in the cache and the
--- 3010,3016 ----
    
    /* We use another caching mechanism for selective scheduling, so 
       we don't use this one.  */
!   if (!sel_sched_p () && global_p && insns_in_block > 100 * 5)
      {
        /* ?!? We could save some memory by computing a per-region luid mapping
           which could reduce both the number of vectors in the cache and the
*************** init_deps_global (void)
*** 3123,3129 ****
    reg_pending_uses = ALLOC_REG_SET (&reg_obstack);
    reg_pending_barrier = NOT_A_BARRIER;
  
!   if (!SEL_SCHED_P || sched_emulate_haifa_p)
      {
        sched_deps_info->start_insn = haifa_start_insn;
        sched_deps_info->finish_insn = haifa_finish_insn;
--- 3121,3127 ----
    reg_pending_uses = ALLOC_REG_SET (&reg_obstack);
    reg_pending_barrier = NOT_A_BARRIER;
  
!   if (!sel_sched_p () || sched_emulate_haifa_p)
      {
        sched_deps_info->start_insn = haifa_start_insn;
        sched_deps_info->finish_insn = haifa_finish_insn;
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/sched-int.h cleanup/gcc/sched-int.h
*** remote/sel-sched-branch/gcc/sched-int.h	Wed Apr 16 19:36:04 2008
--- cleanup/gcc/sched-int.h	Thu Apr 17 17:40:35 2008
*************** extern void sched_scan (const struct sch
*** 69,75 ****
  			bb_vec_t, basic_block, insn_vec_t, rtx);
  
  extern void sched_init_bbs (void);
- extern void sched_finish_bbs (void);
  
  extern void sched_init_luids (bb_vec_t, basic_block, insn_vec_t, rtx);
  extern void sched_finish_luids (void);
--- 69,74 ----
*************** extern struct common_sched_info_def *com
*** 115,121 ****
  extern const struct common_sched_info_def haifa_common_sched_info;
  
  /* Return true if selective scheduling pass is working.  */
! #define SEL_SCHED_P (common_sched_info->sched_pass_id == SCHED_SEL_PASS)
  
  /* True if during selective scheduling we need to emulate some of haifa
     scheduler behaviour.  */
--- 114,124 ----
  extern const struct common_sched_info_def haifa_common_sched_info;
  
  /* Return true if selective scheduling pass is working.  */
! static inline bool
! sel_sched_p (void)
! {
!   return common_sched_info->sched_pass_id == SCHED_SEL_PASS;
! }
  
  /* True if during selective scheduling we need to emulate some of haifa
     scheduler behaviour.  */
*************** extern int insn_luid (rtx);
*** 140,147 ****
     finished.  */
  extern rtx note_list;
  
- extern void attach_life_info (void);
- 
  extern void remove_notes (rtx, rtx);
  extern rtx restore_other_notes (rtx, basic_block);
  extern void sched_insns_init (rtx);
--- 143,148 ----
*************** extern VEC(haifa_deps_insn_data_def, hea
*** 783,789 ****
  
  /* INSN is either a simple or a branchy speculation check.  */
  #define IS_SPECULATION_CHECK_P(INSN) \
!   (SEL_SCHED_P ? sel_insn_is_speculation_check (INSN) : RECOVERY_BLOCK (INSN) != NULL)
  
  /* INSN is a speculation check that will simply reexecute the speculatively
     scheduled instruction if the speculation fails.  */
--- 784,790 ----
  
  /* INSN is either a simple or a branchy speculation check.  */
  #define IS_SPECULATION_CHECK_P(INSN) \
!   (sel_sched_p () ? sel_insn_is_speculation_check (INSN) : RECOVERY_BLOCK (INSN) != NULL)
  
  /* INSN is a speculation check that will simply reexecute the speculatively
     scheduled instruction if the speculation fails.  */
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/sched-rgn.c cleanup/gcc/sched-rgn.c
*** remote/sel-sched-branch/gcc/sched-rgn.c	Wed Apr 16 19:36:04 2008
--- cleanup/gcc/sched-rgn.c	Thu Apr 17 12:49:41 2008
*************** haifa_find_rgns (void)
*** 1062,1068 ****
  static void
  find_rgns (void)
  {
!   if (SEL_SCHED_P && flag_sel_sched_pipelining)
      sel_find_rgns ();
    else
      haifa_find_rgns ();
--- 1062,1068 ----
  static void
  find_rgns (void)
  {
!   if (sel_sched_p () && flag_sel_sched_pipelining)
      sel_find_rgns ();
    else
      haifa_find_rgns ();
*************** compute_block_dependences (int bb)
*** 2664,2670 ****
  #endif  
  
    /* Selective scheduling handles control dependencies by itself.  */
!   if (!SEL_SCHED_P)
      add_branch_dependences (head, tail);
  
    if (current_nr_blocks > 1)
--- 2664,2670 ----
  #endif  
  
    /* Selective scheduling handles control dependencies by itself.  */
!   if (!sel_sched_p ())
      add_branch_dependences (head, tail);
  
    if (current_nr_blocks > 1)
*************** void debug_dependencies (rtx head, rtx t
*** 2768,2777 ****
  	       INSN_CODE (insn),
  	       BLOCK_NUM (insn),
  	       sched_emulate_haifa_p ? -1 : sd_lists_size (insn, SD_LIST_BACK),
! 	       (SEL_SCHED_P ? (sched_emulate_haifa_p ? -1
  			       : INSN_PRIORITY (insn))
  		: INSN_PRIORITY (insn)),
! 	       (SEL_SCHED_P ? (sched_emulate_haifa_p ? -1
  			       : insn_cost (insn))
  		: insn_cost (insn)));
  
--- 2768,2777 ----
  	       INSN_CODE (insn),
  	       BLOCK_NUM (insn),
  	       sched_emulate_haifa_p ? -1 : sd_lists_size (insn, SD_LIST_BACK),
! 	       (sel_sched_p () ? (sched_emulate_haifa_p ? -1
  			       : INSN_PRIORITY (insn))
  		: INSN_PRIORITY (insn)),
! 	       (sel_sched_p () ? (sched_emulate_haifa_p ? -1
  			       : insn_cost (insn))
  		: insn_cost (insn)));
  
*************** sched_rgn_init (bool single_blocks_p)
*** 2961,2972 ****
        || !flag_schedule_interblock
        || is_cfg_nonregular ())
      {
!       find_single_block_region (SEL_SCHED_P);
      }
    else
      {
        /* Compute the dominators and post dominators.  */
!       if (!SEL_SCHED_P)
  	calculate_dominance_info (CDI_DOMINATORS);
  
        /* Find regions.  */
--- 2961,2972 ----
        || !flag_schedule_interblock
        || is_cfg_nonregular ())
      {
!       find_single_block_region (sel_sched_p ());
      }
    else
      {
        /* Compute the dominators and post dominators.  */
!       if (!sel_sched_p ())
  	calculate_dominance_info (CDI_DOMINATORS);
  
        /* Find regions.  */
*************** sched_rgn_init (bool single_blocks_p)
*** 2977,2983 ****
  
        /* For now.  This will move as more and more of haifa is converted
  	 to using the cfg code.  */
!       if (!SEL_SCHED_P)
  	free_dominance_info (CDI_DOMINATORS);
      }
  
--- 2977,2983 ----
  
        /* For now.  This will move as more and more of haifa is converted
  	 to using the cfg code.  */
!       if (!sel_sched_p ())
  	free_dominance_info (CDI_DOMINATORS);
      }
  
*************** sched_rgn_compute_dependencies (int rgn)
*** 3055,3061 ****
      {
        int bb;
  
!       if (SEL_SCHED_P)
  	sched_emulate_haifa_p = 1;
  
        init_deps_global ();
--- 3055,3061 ----
      {
        int bb;
  
!       if (sel_sched_p ())
  	sched_emulate_haifa_p = 1;
  
        init_deps_global ();
*************** sched_rgn_compute_dependencies (int rgn)
*** 3080,3092 ****
        /* We don't want to recalculate this twice.  */
        RGN_DONT_CALC_DEPS (rgn) = 1;
  
!       if (SEL_SCHED_P)
  	sched_emulate_haifa_p = 0;
      }
    else
      /* (This is a recovery block.  It is always a single block region.)
         OR (We use selective scheduling.)  */
!     gcc_assert (current_nr_blocks == 1 || SEL_SCHED_P);
  }
  
  /* Init region data structures.  Returns true if this region should
--- 3080,3092 ----
        /* We don't want to recalculate this twice.  */
        RGN_DONT_CALC_DEPS (rgn) = 1;
  
!       if (sel_sched_p ())
  	sched_emulate_haifa_p = 0;
      }
    else
      /* (This is a recovery block.  It is always a single block region.)
         OR (We use selective scheduling.)  */
!     gcc_assert (current_nr_blocks == 1 || sel_sched_p ());
  }
  
  /* Init region data structures.  Returns true if this region should
*************** sched_rgn_local_free (void)
*** 3166,3172 ****
  void
  sched_rgn_local_finish (void)
  {
!   if (current_nr_blocks > 1 && !SEL_SCHED_P)
      {
        sched_rgn_local_free ();
      }
--- 3166,3172 ----
  void
  sched_rgn_local_finish (void)
  {
!   if (current_nr_blocks > 1 && !sel_sched_p ())
      {
        sched_rgn_local_free ();
      }
*************** rgn_setup_common_sched_info (void)
*** 3191,3197 ****
  void
  rgn_setup_sched_infos (void)
  {
!   if (!SEL_SCHED_P)
      memcpy (&rgn_sched_deps_info, &rgn_const_sched_deps_info,
  	    sizeof (rgn_sched_deps_info));
    else
--- 3191,3197 ----
  void
  rgn_setup_sched_infos (void)
  {
!   if (!sel_sched_p ())
      memcpy (&rgn_sched_deps_info, &rgn_const_sched_deps_info,
  	    sizeof (rgn_sched_deps_info));
    else
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/sel-sched-dump.c cleanup/gcc/sel-sched-dump.c
*** remote/sel-sched-branch/gcc/sel-sched-dump.c	Mon Apr 14 18:57:51 2008
--- cleanup/gcc/sel-sched-dump.c	Thu Apr 17 17:48:47 2008
***************
*** 1,22 ****
! /* Instruction scheduling pass.  Log dumping infrastructure.
!    Copyright (C) 2006, 2007 Free Software Foundation, Inc.
  
!    This file is part of GCC.
  
!    GCC is free software; you can redistribute it and/or modify it under
!    the terms of the GNU General Public License as published by the Free
!    Software Foundation; either version 2, or (at your option) any later
!    version.
  
!    GCC is distributed in the hope that it will be useful, but WITHOUT ANY
!    WARRANTY; without even the implied warranty of MERCHANTABILITY or
!    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
!    for more details.
  
!    You should have received a copy of the GNU General Public License
!    along with GCC; see the file COPYING.  If not, write to the Free
!    Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
!    02110-1301, USA.  */
  
  #include "config.h"
  #include "system.h"
--- 1,21 ----
! /* Instruction scheduling pass.   Log dumping infrastructure.
!    Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
  
! This file is part of GCC.
  
! GCC is free software; you can redistribute it and/or modify it under
! the terms of the GNU General Public License as published by the Free
! Software Foundation; either version 3, or (at your option) any later
! version.
  
! GCC is distributed in the hope that it will be useful, but WITHOUT ANY
! WARRANTY; without even the implied warranty of MERCHANTABILITY or
! FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
! for more details.
  
! You should have received a copy of the GNU General Public License
! along with GCC; see the file COPYING3.  If not see
! <http://www.gnu.org/licenses/>.  */
  
  #include "config.h"
  #include "system.h"
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/sel-sched-dump.h cleanup/gcc/sel-sched-dump.h
*** remote/sel-sched-branch/gcc/sel-sched-dump.h	Mon Apr 14 18:57:51 2008
--- cleanup/gcc/sel-sched-dump.h	Thu Apr 17 17:49:54 2008
***************
*** 1,12 ****
  /* Instruction scheduling pass.  Log dumping infrastructure.  
! 
!    Copyright (C) 2006, 2007 Free Software Foundation, Inc.
  
  This file is part of GCC.
  
  GCC is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free
! Software Foundation; either version 2, or (at your option) any later
  version.
  
  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
--- 1,11 ----
  /* Instruction scheduling pass.  Log dumping infrastructure.  
!    Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
  
  This file is part of GCC.
  
  GCC is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free
! Software Foundation; either version 3, or (at your option) any later
  version.
  
  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
*************** FITNESS FOR A PARTICULAR PURPOSE.  See t
*** 15,23 ****
  for more details.
  
  You should have received a copy of the GNU General Public License
! along with GCC; see the file COPYING.  If not, write to the Free
! Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
! 02110-1301, USA.  */
  #ifndef GCC_SEL_SCHED_DUMP_H
  #define GCC_SEL_SCHED_DUMP_H
  
--- 14,23 ----
  for more details.
  
  You should have received a copy of the GNU General Public License
! along with GCC; see the file COPYING3.  If not see
! <http://www.gnu.org/licenses/>.  */
! 
! 
  #ifndef GCC_SEL_SCHED_DUMP_H
  #define GCC_SEL_SCHED_DUMP_H
  
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/sel-sched-ir.c cleanup/gcc/sel-sched-ir.c
*** remote/sel-sched-branch/gcc/sel-sched-ir.c	Wed Apr 16 19:41:36 2008
--- cleanup/gcc/sel-sched-ir.c	Fri Apr 18 10:31:53 2008
***************
*** 1,25 ****
! /* Instruction scheduling pass.
!    Copyright (C) 2006, 2007 Free Software Foundation, Inc.
! 
!    This file is part of GCC.
  
!    GCC is free software; you can redistribute it and/or modify it under
!    the terms of the GNU General Public License as published by the Free
!    Software Foundation; either version 2, or (at your option) any later
!    version.
  
!    GCC is distributed in the hope that it will be useful, but WITHOUT ANY
!    WARRANTY; without even the implied warranty of MERCHANTABILITY or
!    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
!    for more details.
  
!    You should have received a copy of the GNU General Public License
!    along with GCC; see the file COPYING.  If not, write to the Free
!    Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
!    02110-1301, USA.  */
  
  
- /* FIXME: check whether we need all these headers, and check the makefile.  */
  #include "config.h"
  #include "system.h"
  #include "coretypes.h"
--- 1,22 ----
! /* Instruction scheduling pass.  Selective scheduler and pipeliner.
!    Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
  
! This file is part of GCC.
  
! GCC is free software; you can redistribute it and/or modify it under
! the terms of the GNU General Public License as published by the Free
! Software Foundation; either version 3, or (at your option) any later
! version.
  
! GCC is distributed in the hope that it will be useful, but WITHOUT ANY
! WARRANTY; without even the implied warranty of MERCHANTABILITY or
! FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
! for more details.
  
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
  
  #include "config.h"
  #include "system.h"
  #include "coretypes.h"
***************
*** 36,48 ****
  #include "except.h"
  #include "toplev.h"
  #include "recog.h"
- #include "cfglayout.h"
  #include "params.h"
  #include "target.h"
  #include "timevar.h"
  #include "tree-pass.h"
  #include "sched-int.h"
- #include "cselib.h"
  #include "ggc.h"
  #include "tree.h"
  #include "vec.h"
--- 33,43 ----
*************** flist_clear (flist_t *lp)
*** 294,301 ****
  
  /* Add ORIGINAL_INSN the def list DL honoring CROSSES_CALL.  */
  void
! def_list_add (def_list_t *dl, insn_t original_insn, bool crosses_call,
! 	      bool needs_spec_check_p)
  {
    def_t d;
    _list_add (dl);
--- 289,295 ----
  
  /* Add ORIGINAL_INSN the def list DL honoring CROSSES_CALL.  */
  void
! def_list_add (def_list_t *dl, insn_t original_insn, bool crosses_call)
  {
    def_t d;
    _list_add (dl);
*************** def_list_add (def_list_t *dl, insn_t ori
*** 303,309 ****
  
    d->orig_insn = original_insn;
    d->crosses_call = crosses_call;
-   d->needs_spec_check_p = needs_spec_check_p;
  }
  
  
--- 297,302 ----
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/sel-sched-ir.h cleanup/gcc/sel-sched-ir.h
*** remote/sel-sched-branch/gcc/sel-sched-ir.h	Wed Apr 16 19:36:04 2008
--- cleanup/gcc/sel-sched-ir.h	Fri Apr 18 10:31:53 2008
***************
*** 1,12 ****
  /* Instruction scheduling pass.  This file contains definitions used
     internally in the scheduler.
!    Copyright (C) 2006, 2007 Free Software Foundation, Inc.
  
  This file is part of GCC.
  
  GCC is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free
! Software Foundation; either version 2, or (at your option) any later
  version.
  
  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
--- 1,12 ----
  /* Instruction scheduling pass.  This file contains definitions used
     internally in the scheduler.
!    Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
  
  This file is part of GCC.
  
  GCC is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free
! Software Foundation; either version 3, or (at your option) any later
  version.
  
  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
*************** FITNESS FOR A PARTICULAR PURPOSE.  See t
*** 15,23 ****
  for more details.
  
  You should have received a copy of the GNU General Public License
! along with GCC; see the file COPYING.  If not, write to the Free
! Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
! 02110-1301, USA.  */
  
  #ifndef GCC_SEL_SCHED_IR_H
  #define GCC_SEL_SCHED_IR_H
--- 15,22 ----
  for more details.
  
  You should have received a copy of the GNU General Public License
! along with GCC; see the file COPYING3.  If not see
! <http://www.gnu.org/licenses/>.  */
  
  #ifndef GCC_SEL_SCHED_IR_H
  #define GCC_SEL_SCHED_IR_H
*************** typedef struct expr_history_def_1 expr_h
*** 109,115 ****
  DEF_VEC_O (expr_history_def);
  DEF_VEC_ALLOC_O (expr_history_def, heap);
  
! /* Right hand side information.  */
  struct _expr
  {
    /* Insn description.  */
--- 108,114 ----
  DEF_VEC_O (expr_history_def);
  DEF_VEC_ALLOC_O (expr_history_def, heap);
  
! /* Expression information.  */
  struct _expr
  {
    /* Insn description.  */
*************** struct _def
*** 208,214 ****
       path or whether all paths crosses a call.  Thus we should move CROSSES_CALL
       to static params.  */
    bool crosses_call;
-   bool needs_spec_check_p;
  };
  typedef struct _def *def_t;
  
--- 207,212 ----
*************** extern void flist_tail_init (flist_tail_
*** 1461,1467 ****
  
  extern fence_t flist_lookup (flist_t, insn_t);
  extern void flist_clear (flist_t *);
! extern void def_list_add (def_list_t *, insn_t, bool, bool);
  
  /* Target context functions.  */
  extern tc_t create_target_context (bool);
--- 1459,1465 ----
  
  extern fence_t flist_lookup (flist_t, insn_t);
  extern void flist_clear (flist_t *);
! extern void def_list_add (def_list_t *, insn_t, bool);
  
  /* Target context functions.  */
  extern tc_t create_target_context (bool);
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/sel-sched.c cleanup/gcc/sel-sched.c
*** remote/sel-sched-branch/gcc/sel-sched.c	Wed Apr 16 19:36:04 2008
--- cleanup/gcc/sel-sched.c	Fri Apr 18 10:31:53 2008
***************
*** 1,25 ****
! /* Instruction scheduling pass.
!    Copyright (C) 2006, 2007 Free Software Foundation, Inc.
! 
!    This file is part of GCC.
  
!    GCC is free software; you can redistribute it and/or modify it under
!    the terms of the GNU General Public License as published by the Free
!    Software Foundation; either version 2, or (at your option) any later
!    version.
  
!    GCC is distributed in the hope that it will be useful, but WITHOUT ANY
!    WARRANTY; without even the implied warranty of MERCHANTABILITY or
!    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
!    for more details.
  
!    You should have received a copy of the GNU General Public License
!    along with GCC; see the file COPYING.  If not, write to the Free
!    Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
!    02110-1301, USA.  */
  
  
- /* FIXME: check whether we need all these headers, and check the makefile.  */
  #include "config.h"
  #include "system.h"
  #include "coretypes.h"
--- 1,22 ----
! /* Instruction scheduling pass.  Selective scheduler and pipeliner.
!    Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
  
! This file is part of GCC.
  
! GCC is free software; you can redistribute it and/or modify it under
! the terms of the GNU General Public License as published by the Free
! Software Foundation; either version 3, or (at your option) any later
! version.
  
! GCC is distributed in the hope that it will be useful, but WITHOUT ANY
! WARRANTY; without even the implied warranty of MERCHANTABILITY or
! FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
! for more details.
  
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
  
  #include "config.h"
  #include "system.h"
  #include "coretypes.h"
***************
*** 36,49 ****
  #include "except.h"
  #include "toplev.h"
  #include "recog.h"
- #include "cfglayout.h"
  #include "params.h"
  #include "target.h"
  #include "output.h"
  #include "timevar.h"
  #include "tree-pass.h"
  #include "sched-int.h"
- #include "cselib.h"
  #include "ggc.h"
  #include "tree.h"
  #include "vec.h"
--- 33,44 ----
***************
*** 56,68 ****
  #include "sel-sched-dump.h"
  #include "sel-sched.h"
  
! /* FIXME: extend this comment.
  
-    Implementation of selective scheduling approach.
     References:
     S.-M. Moon and K. Ebcioglu. Parallelizing nonnumerical code with
     selective scheduling and software pipelining. 
!    ACM TOPLAS, Vol 19, No. 6, pages 853--898, Nov. 1997.  */
  
  /* True when pipelining is enabled.  */
  bool pipelining_p;
--- 51,250 ----
  #include "sel-sched-dump.h"
  #include "sel-sched.h"
  
! /* Implementation of selective scheduling approach.
!    The below implementation follows the original approach with the following
!    changes:
! 
!    o the scheduler works after register allocation (but can be also tuned 
!    to work before RA);
!    o some instructions are not copied or register renamed;
!    o conditional jumps are not moved with code duplication;
!    o several jumps in one parallel group are not supported;
!    o when pipelining outer loops, code motion through inner loops
!    is not supported;
!    o control and data speculation are supported;
!    o some improvements for better compile time/performance were made.
! 
!    Terminology
!    ===========
! 
!    A vinsn, or virtual insn, is an insn with additional data characterizing 
!    insn pattern, such as LHS, RHS, register sets used/set/clobbered, etc.  
!    Vinsns also act as smart pointers to save memory by reusing them in 
!    different expressions.  A vinsn is described by vinsn_t type.
! 
!    An expression is a vinsn with additional data characterizing its properties
!    at some point in the control flow graph.  The data may be its usefulness, 
!    priority, speculative status, whether it was renamed/subsituted, etc.
!    An expression is described by expr_t type.
! 
!    Availability set (av_set) is a set of expressions at a given control flow 
!    point. It is represented as av_set_t.  The expressions in av sets are kept
!    sorted in the terms of expr_greater_p function.  It allows to truncate 
!    the set while leaving the best expressions.
!    
!    A fence is a point through which code motion is prohibited.  On each step,
!    we gather a parallel group of insns at a fence.  It is possible to have
!    multiple fences. A fence is represented via fence_t.
! 
!    A boundary is the border between the fence group and the rest of the code.
!    Currently, we never have more than one boundary per fence, as we finalize
!    the fence group when a jump is scheduled. A boundary is represented 
!    via bnd_t.
! 
!    High-level overview
!    ===================
! 
!    The scheduler finds regions to schedule, schedules each one, and finalizes.
!    The regions are formed starting from innermost loops, so that when the inner 
!    loop is pipelined, its prologue can be scheduled together with yet unprocessed
!    outer loop. The rest of acyclic regions are found using extend_rgns: 
!    the blocks that are not yet allocated to any regions are traversed in top-down
!    order, and a block is added to a region to which all its predecessors belong; 
!    otherwise, the block starts its own region.
! 
!    The main scheduling loop (sel_sched_region_2) consists of just
!    scheduling on each fence and updating fences.  For each fence,
!    we fill a parallel group of insns (fill_insns) until some insns can be added.
!    First, we compute available exprs (av-set) at the boundary of the current 
!    group.  Second, we choose the best expression from it.  If the stall is 
!    required to schedule any of the expressions, we advance the current cycle
!    appropriately.  So, tThe final group does not exactly correspond to a VLIW 
!    word.  Third, we move the chosen expression to the boundary (move_op)
!    and update the intermediate av sets and liveness sets.  We quit fill_insns
!    when either no insns left for scheduling or we have scheduled enough insns
!    so we feel like advancing a scheduling point.  
! 
!    Computing available expressions
!    ===============================
!    The computation (compute_av_set) is a bottom-up traversal.  At each insn,
!    we're moving the union of its successors' sets through it via 
!    moveup_expr_set.  The dependent expressions are removed.  Local 
!    transformations (substitution, speculation) are applied to move more 
!    exprs.  Then the expr corresponding to the current insn is added.
!    The result is saved on each basic block header.
! 
!    When traversing the CFG, we're moving down for no more than max_ws insns.
!    Also, we do not move down to ineligible successors (is_ineligible_successor),
!    which include moving along a back-edge, moving to already scheduled code,
!    and moving to another fence.  The first two restrictions are lifted during 
!    pipelining, which allows us to move insns along a back-edge.  We always have
!    an acyclic region for scheduling because we forbid motion through fences.
! 
!    Choosing the best expression
!    ============================
! 
!    We sort the final availability set via sel_rank_for_schedule, then we remove
!    expressions which are not yet ready (tick_check_p) or which dest registers
!    cannot be used.  For some of them, we choose another register via 
!    find_best_reg.  To do this, we run find_used_regs to calculate the set of 
!    registers which cannot be used.  The find_used_regs function performs
!    a traversal of code motion paths for an expr.  We consider for renaming
!    only registers which are from the same regclass as the original one and 
!    using which does not interfere with any live ranges.  Finally, we convert
!    the resulting set to the ready list format and use max_issue and reorder*
!    hooks similarly to the Haifa scheduler.
! 
!    Scheduling the best expression
!    ==============================
! 
!    We run the move_op routine to perform the same type of code motion paths 
!    traversal as in find_used_regs.  (These are working via the same driver,
!    code_motion_path_driver.)  When moving down the CFG, we look for original
!    instruction that gave birth to a chosen expression.  We undo 
!    the transformations performed on an expression via the history saved in it.
!    When found, we remove the instruction or leave a reg-reg copy/speculation 
!    check if needed.  On a way up, we insert bookkeeping copies at each join 
!    point.  If a copy is not needed, it will be removed later during this 
!    traversal.  We update the saved av sets and liveness sets on the way up, too.
! 
!    Finalizing the schedule
!    =======================
! 
!    When pipelining, we reschedule the blocks from which insns were pipelined 
!    to get a tighter schedule.  On Itanium, we also perform bundling via 
!    the same routine from ia64.c.  
! 
!    Dependence analysis changes
!    ===========================
! 
!    We augmented the sched-deps.c with hooks that get called when a particular
!    dependence is found in a particular part of an insn.  Using these hooks, we
!    can do several actions such as: determine whether an insn can be moved through
!    another (has_dependence_p, moveup_expr); find out whether an insn can be 
!    scheduled on the current cycle (tick_check_p); find out registers that 
!    are set/used/clobbered by an insn and find out all the strange stuff that 
!    restrict its movement, like SCHED_GROUP_P or CANT_MOVE (done in 
!    init_global_and_expr_for_insn).
! 
!    Initialization changes
!    ======================
!    There are parts of haifa-sched.c, sched-deps.c, and sched-rgn.c that are 
!    reused in all of the schedulers.  We have split up the initialization of data
!    of such parts into different functions prefixed with scheduler type and 
!    postfixed with the type of data initialized: {,sel_,haifa_}sched_{init,finish},
!    sched_rgn_init/finish, sched_deps_init/finish, sched_init_{luids/bbs}, etc.
!    The same splitting is done with current_sched_info structure: 
!    dependence-related parts are in sched_deps_info, common part is in 
!    common_sched_info, and haifa/sel/etc part is in current_sched_info.
!    
!    Target contexts
!    ===============
!    As we now have multiple-point scheduling, this would not work with backends
!    which save some of the scheduler state to use it in the target hooks.  
!    For this purpose, we introduce a concept of target contexts, which 
!    encapsulate such information.  The backend should implement simple routines
!    of allocating/freeing/setting such a context.  The scheduler calls these
!    as target hooks and handles the target context as an opaque pointer (similar
!    to the DFA state type, state_t).
! 
!    Various speedups
!    ================
!    As the correct data dependence graph is not supported during scheduling (which
!    is to be changed in mid-term), we cache as much of the dependence analysis 
!    results as possible to avoid reanalyzing.  This includes: bitmap caches on 
!    each insn in stream of the region saying yes/no for a query with a pair of 
!    UIDs; hashtables with the previously done transformations on each insn in
!    stream; a vector keeping a history of transformations on each expr.
! 
!    Also, we try to minimize the dependence context used on each fence to check
!    whether the given expression is ready for scheduling by removing from it
!    insns that are definitely completed the execution.  The results of 
!    tick_check_p checks are also cached in a vector on each fence.
! 
!    We keep a valid liveness set on each insn in a region to avoid the high 
!    cost of recomputation on large basic blocks.
! 
!    Finally, we try to minimize the number of needed updates to the availability
!    sets.  The updates happen in two cases: when fill_insns terminates, 
!    we advance all fences and increase the stage number to show that the region
!    has changed and the sets are to be recomputed; and when the next iteration
!    of a loop in fill_insns happens (but this one reuses the saved av sets
!    on bb headers.)  Thus, we try to break the fill_insns loop only when
!    "significant" number of insns from the current scheduling window was
!    scheduled.  This should be made a target param.
!    
! 
!    TODO: correctly support the data dependence graph at all stages and get rid
!    of all caches.  This should speed up the scheduler.
!    TODO: implement moving cond jumps with bookkeeping copies on both targets.
!    TODO: tune the scheduler before RA so it does not create too much pseudos.
! 
  
     References:
     S.-M. Moon and K. Ebcioglu. Parallelizing nonnumerical code with
     selective scheduling and software pipelining. 
!    ACM TOPLAS, Vol 19, No. 6, pages 853--898, Nov. 1997.  
! 
!    Andrey Belevantsev, Maxim Kuvyrkov, Vladimir Makarov, Dmitry Melnik, 
!    and Dmitry Zhurikhin.  An interblock VLIW-targeted instruction scheduler 
!    for GCC. In Proceedings of GCC Developers' Summit 2006.
! 
!    Arutyun Avetisyan, Andrey Belevantsev, and Dmitry Melnik.  GCC Instruction 
!    Scheduler and Software Pipeliner on the Itanium Platform.   EPIC-7 Workshop.
!    http://rogue.colorado.edu/EPIC7/.
!    
! */
  
  /* True when pipelining is enabled.  */
  bool pipelining_p;
*************** verify_target_availability (expr_t expr,
*** 1371,1413 ****
  		|| !hard_available);
  }
  
! /* Returns best register for given rhs, or NULL_RTX, if no register can be
!    chosen.  The latter could happen when:
!      - EXPR_SCHEDULE_AS_RHS is true but we were unable to find suitable
!        register;
!      - EXPR_SCHEDULE_AS_RHS is false but the insn sets/clobbers one of
!        the registers that are used on the moving path.  */
! static bool
! find_best_reg_for_expr (expr_t expr, blist_t bnds, bool *is_orig_reg_p)
  {
!   static struct reg_rename reg_rename_data;
!  
!   regset used_regs;
!   HARD_REG_SET hard_regs_used;
!   rtx best_reg = NULL_RTX;
!   blist_t bnds1 = bnds;
!   def_list_t original_insns = NULL;
!   int res = 0;
!   bool reg_ok = true;
! 
!   *is_orig_reg_p = false;
! 
!   /* Don't bother to do anything if this insn doesn't set any registers.  */
!   if (bitmap_empty_p (VINSN_REG_SETS (EXPR_VINSN (expr)))
!       && bitmap_empty_p (VINSN_REG_CLOBBERS (EXPR_VINSN (expr))))
!     return true;
! 
!   used_regs = get_clear_regset_from_pool ();
!   CLEAR_HARD_REG_SET (reg_rename_data.unavailable_hard_regs);
! 
!   /* Collect unavailable registers from all boundaries into USED_REGS.  */
!   do
      {
        av_set_t orig_ops = NULL;
!       bnd_t bnd = BLIST_BND (bnds1);
  
!       /* If the chosen best expr doesn't belong to current boundary, 
!          skip it.  */
        if (!av_set_is_in_p (BND_AV1 (bnd), EXPR_VINSN (expr)))
  	continue;
  
--- 1553,1572 ----
  		|| !hard_available);
  }
  
! /* Collect unavailable registers for EXPR from BNDS into USED_REGS.  */
! static void
! collect_unavailable_regs_from_bnds (expr_t expr, blist_t bnds, regset used_regs,
! 				    struct reg_rename *reg_rename_p,
! 				    def_list_t *original_insns)
  {
!   for (; bnds; bnds = BLIST_NEXT (bnds))
      {
+       bool res;
        av_set_t orig_ops = NULL;
!       bnd_t bnd = BLIST_BND (bnds);
  
!       /* If the chosen best expr doesn't belong to current boundary,
! 	 skip it.  */
        if (!av_set_is_in_p (BND_AV1 (bnd), EXPR_VINSN (expr)))
  	continue;
  
*************** find_best_reg_for_expr (expr_t expr, bli
*** 1417,1536 ****
  
        /* Compute used regs and OR it into the USED_REGS.  */
        res = find_used_regs (BND_TO (bnd), orig_ops, used_regs,
!                             &reg_rename_data, &original_insns);
  
        /* FIXME: the assert is true until we'd have several boundaries.  */
        gcc_assert (res);
        av_set_clear (&orig_ops);
      }
!   while ((bnds1 = BLIST_NEXT (bnds1)));
  
!   if (res)
      {
! #ifdef ENABLE_CHECKING
!       /* If after reload, make sure we're working with hard regs here.  */
!       if (reload_completed) {
! 	reg_set_iterator rsi;
! 	unsigned i;
! 	EXECUTE_IF_SET_IN_REG_SET (used_regs, FIRST_PSEUDO_REGISTER, i, rsi)
! 	  gcc_unreachable ();
!       }
! #endif
  
!       if (EXPR_SEPARABLE_P (expr))
! 	{
!           /* Check that we have computed availability of a target register
!              correctly.  */
!           verify_target_availability (expr, used_regs, 
!                                       reg_rename_data.unavailable_hard_regs);
  
!           /* Turn everything in hard regs after reload.  */
!           if (reload_completed)
!             {
!               REG_SET_TO_HARD_REG_SET (hard_regs_used, used_regs);
  
!               /* Join hard registers unavailable due to register class 
!                  restrictions and live range intersection.  */
!               IOR_HARD_REG_SET (hard_regs_used, 
!                                 reg_rename_data.unavailable_hard_regs);
  
!               best_reg = choose_best_reg (hard_regs_used, &reg_rename_data, 
!                                           original_insns, is_orig_reg_p);
!             }
!           else
!             best_reg = choose_best_pseudo_reg (used_regs, &reg_rename_data, 
!                                                original_insns, is_orig_reg_p);
  
! 	  if (!*is_orig_reg_p && sel_vinsn_cost (EXPR_VINSN (expr)) < 2)
! 	    best_reg = NULL_RTX;
  
! 	  if (best_reg != NULL_RTX)
! 	    /* Try whether we'll be able to generate the insn
! 	       'dest := best_reg' at the place of the original operation.  */
! 	    {
! 	      ilist_t p = original_insns;
!     
! 	      gcc_assert (original_insns);
!     
! 	      while (p) 
! 		{
! 		  def_t def = DEF_LIST_DEF (p);
!     
! 		  gcc_assert (EXPR_SEPARABLE_P (INSN_EXPR (def->orig_insn)));
!     
! 		  if (!replace_src_with_reg_ok_p (def->orig_insn, best_reg)
! 		      || !replace_dest_with_reg_ok_p (def->orig_insn,
! 						      best_reg))
! 		    {
! 		      /* Insn will be removed from expr_vliw below.  
!                          FIXME: may be it will work with other regs?  */
! 		      reg_ok = false;
! 		      break;
! 		    }
  
! 		  p = ILIST_NEXT (p);
! 		}		
! 		
! 	      if (reg_ok)
! 		{
! 		  /* Make sure that EXPR has the right destination
! 		     register.  */
! 		  if (expr_dest_regno (expr) != REGNO (best_reg))
! 		    {
! 		      replace_dest_with_reg_in_expr (expr, best_reg);
!                       EXPR_WAS_RENAMED (expr) = 1;
!                       EXPR_TARGET_AVAILABLE (expr) = 1;
  
! 		      /* The resulting insn should be valid.  */
! 		      if (!insn_rtx_valid (EXPR_INSN_RTX (expr)))
! 			gcc_unreachable ();
! 		    }
! 		}
! 	    }
! 	  else
! 	    reg_ok = false;
!     	}
        else
  	{
! 	  /* If !EXPR_SCHEDULE_AS_RHS (EXPR), just make sure INSN doesn't set
! 	     any of the HARD_REGS_USED set.  */
! 	  if (vinsn_writes_one_of_regs_p 
!               (EXPR_VINSN (expr), used_regs,
!                reg_rename_data.unavailable_hard_regs))
!             {
!               reg_ok = false;
!               gcc_assert (EXPR_TARGET_AVAILABLE (expr) <= 0);
!             }
  	  else
! 	    {
! 	      gcc_assert (reg_ok);
!               gcc_assert (EXPR_TARGET_AVAILABLE (expr) != 0);
! 	      best_reg = NULL_RTX;
! 	    }
  	}
      }
    else
!     reg_ok = false;
  
    ilist_clear (&original_insns);
    return_regset_to_pool (used_regs);
--- 1576,1721 ----
  
        /* Compute used regs and OR it into the USED_REGS.  */
        res = find_used_regs (BND_TO (bnd), orig_ops, used_regs,
! 			    reg_rename_p, original_insns);
  
        /* FIXME: the assert is true until we'd have several boundaries.  */
        gcc_assert (res);
        av_set_clear (&orig_ops);
      }
! }
  
! /* Return TRUE if it is possible to replace LHSes of ORIG_INSNS with BEST_REG.
!    If BEST_REG is valid, replace LHS of EXPR with it.  */
! static bool
! try_replace_dest_reg (ilist_t orig_insns, rtx best_reg, expr_t expr)
! {
!   if (expr_dest_regno (expr) == REGNO (best_reg))
!     return true;
! 
!   gcc_assert (orig_insns);
! 
!   /* Try whether we'll be able to generate the insn
!      'dest := best_reg' at the place of the original operation.  */
!   for (; orig_insns; orig_insns = ILIST_NEXT (orig_insns))
      {
!       insn_t orig_insn = DEF_LIST_DEF (orig_insns)->orig_insn;
  
!       gcc_assert (EXPR_SEPARABLE_P (INSN_EXPR (orig_insn)));
  
!       if (!replace_src_with_reg_ok_p (orig_insn, best_reg)
! 	  || !replace_dest_with_reg_ok_p (orig_insn, best_reg))
! 	return false;
!     }
  
!   /* Make sure that EXPR has the right destination
!      register.  */
!   replace_dest_with_reg_in_expr (expr, best_reg);
!   EXPR_WAS_RENAMED (expr) = 1;
!   EXPR_TARGET_AVAILABLE (expr) = 1;
  
!   /* The resulting insn should be valid.  */
!   gcc_assert (insn_rtx_valid (EXPR_INSN_RTX (expr)));
!   return true;
! }
  
! /* Select and assign best register to EXPR.  Set *IS_ORIG_REG_P to TRUE if
!    original register was selected.  Return FALSE if no register can be
!    chosen, which could happen when:
!    * EXPR_SEPARABLE_P is true but we were unable to find suitable register;
!    * EXPR_SEPARABLE_P is false but the insn sets/clobbers one of the registers
!      that are used on the moving path.  */
! static bool
! find_best_reg_for_expr (expr_t expr, blist_t bnds, bool *is_orig_reg_p)
! {
!   static struct reg_rename reg_rename_data;
  
!   regset used_regs;
!   def_list_t original_insns = NULL;
!   bool reg_ok;
  
!   *is_orig_reg_p = false;
  
!   /* Don't bother to do anything if this insn doesn't set any registers.  */
!   if (bitmap_empty_p (VINSN_REG_SETS (EXPR_VINSN (expr)))
!       && bitmap_empty_p (VINSN_REG_CLOBBERS (EXPR_VINSN (expr))))
!     return true;
! 
!   used_regs = get_clear_regset_from_pool ();
!   CLEAR_HARD_REG_SET (reg_rename_data.unavailable_hard_regs);
! 
!   collect_unavailable_regs_from_bnds (expr, bnds, used_regs, &reg_rename_data,
! 				      &original_insns);
! 
! #ifdef ENABLE_CHECKING
!   /* If after reload, make sure we're working with hard regs here.  */
!   if (reload_completed) {
!     reg_set_iterator rsi;
!     unsigned i;
!     EXECUTE_IF_SET_IN_REG_SET (used_regs, FIRST_PSEUDO_REGISTER, i, rsi)
!       gcc_unreachable ();
!   }
! #endif
! 
!   if (EXPR_SEPARABLE_P (expr))
!     {
!       rtx best_reg = NULL_RTX;
!       /* Check that we have computed availability of a target register
! 	 correctly.  */
!       verify_target_availability (expr, used_regs,
! 				  reg_rename_data.unavailable_hard_regs);
! 
!       /* Turn everything in hard regs after reload.  */
!       if (reload_completed)
! 	{
! 	  HARD_REG_SET hard_regs_used;
! 	  REG_SET_TO_HARD_REG_SET (hard_regs_used, used_regs);
! 
! 	  /* Join hard registers unavailable due to register class
! 	     restrictions and live range intersection.  */
! 	  IOR_HARD_REG_SET (hard_regs_used,
! 			    reg_rename_data.unavailable_hard_regs);
! 
! 	  best_reg = choose_best_reg (hard_regs_used, &reg_rename_data,
! 				      original_insns, is_orig_reg_p);
! 	}
        else
+ 	best_reg = choose_best_pseudo_reg (used_regs, &reg_rename_data,
+ 					   original_insns, is_orig_reg_p);
+ 
+       if (!best_reg)
+ 	reg_ok = false;
+       else if (*is_orig_reg_p)
  	{
! 	  /* In case of unification BEST_REG may be different from EXPR's LHS
! 	     when EXPR's LHS is unavailable, and there is another LHS among
! 	     ORIGINAL_INSNS.  */
! 	  reg_ok = try_replace_dest_reg (original_insns, best_reg, expr);
! 	}
!       else
! 	{
! 	  /* Forbid renaming of low-cost insns.  */
! 	  if (sel_vinsn_cost (EXPR_VINSN (expr)) < 2)
! 	    reg_ok = false;
  	  else
! 	    reg_ok = try_replace_dest_reg (original_insns, best_reg, expr);
  	}
      }
    else
!     {
!       /* If !EXPR_SCHEDULE_AS_RHS (EXPR), just make sure INSN doesn't set
! 	 any of the HARD_REGS_USED set.  */
!       if (vinsn_writes_one_of_regs_p (EXPR_VINSN (expr), used_regs,
! 				      reg_rename_data.unavailable_hard_regs))
! 	{
! 	  reg_ok = false;
! 	  gcc_assert (EXPR_TARGET_AVAILABLE (expr) <= 0);
! 	}
!       else
! 	{
! 	  reg_ok = true;
! 	  gcc_assert (EXPR_TARGET_AVAILABLE (expr) != 0);
! 	}
!     }
  
    ilist_clear (&original_insns);
    return_regset_to_pool (used_regs);
*************** move_op_orig_expr_found (insn_t insn, ex
*** 5292,5311 ****
     INSN - current insn traversed, EXPR - the corresponding expr found,
     crosses_call and original_insns in STATIC_PARAMS are updated.  */
  static void
! fur_orig_expr_found (insn_t insn, expr_t expr, 
  		    cmpd_local_params_p lparams ATTRIBUTE_UNUSED,
                      void *static_params)
  {
    fur_static_params_p params = static_params;
-   bool needs_spec_check_p;
    regset tmp;
  
    if (CALL_P (insn))
      params->crosses_call = true;
  
!   needs_spec_check_p = (get_spec_check_type_for_insn (insn, expr) != 0);
!   def_list_add (params->original_insns, insn, params->crosses_call,
! 		needs_spec_check_p);
  
    /* Mark the registers that do not meet the following condition:
      (2) not among the live registers of the point 
--- 5477,5493 ----
     INSN - current insn traversed, EXPR - the corresponding expr found,
     crosses_call and original_insns in STATIC_PARAMS are updated.  */
  static void
! fur_orig_expr_found (insn_t insn, expr_t expr ATTRIBUTE_UNUSED,
  		    cmpd_local_params_p lparams ATTRIBUTE_UNUSED,
                      void *static_params)
  {
    fur_static_params_p params = static_params;
    regset tmp;
  
    if (CALL_P (insn))
      params->crosses_call = true;
  
!   def_list_add (params->original_insns, insn, params->crosses_call);
  
    /* Mark the registers that do not meet the following condition:
      (2) not among the live registers of the point 
*************** sel_global_finish (void)
*** 6998,7004 ****
  
    sched_rgn_finish ();
    sched_deps_finish ();
-   sched_finish_bbs ();
    sched_finish ();
  
    if (current_loops)
--- 7180,7185 ----
diff -cprd -x .svn -x .hg remote/sel-sched-branch/gcc/sel-sched.h cleanup/gcc/sel-sched.h
*** remote/sel-sched-branch/gcc/sel-sched.h	Fri Jan 11 14:07:51 2008
--- cleanup/gcc/sel-sched.h	Thu Apr 17 17:51:52 2008
***************
*** 1,12 ****
! /* Instruction scheduling pass.  This file contains definitions used
!    internally in the scheduler.
!    Copyright (C) 2006, 2007 Free Software Foundation, Inc.
  
  This file is part of GCC.
  
  GCC is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free
! Software Foundation; either version 2, or (at your option) any later
  version.
  
  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
--- 1,11 ----
! /* Instruction scheduling pass.  
!    Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
  
  This file is part of GCC.
  
  GCC is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free
! Software Foundation; either version 3, or (at your option) any later
  version.
  
  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
*************** FITNESS FOR A PARTICULAR PURPOSE.  See t
*** 15,23 ****
  for more details.
  
  You should have received a copy of the GNU General Public License
! along with GCC; see the file COPYING.  If not, write to the Free
! Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
! 02110-1301, USA.  */
  
  #ifndef GCC_SEL_SCHED_H
  #define GCC_SEL_SCHED_H
--- 14,21 ----
  for more details.
  
  You should have received a copy of the GNU General Public License
! along with GCC; see the file COPYING3.  If not see
! <http://www.gnu.org/licenses/>.  */
  
  #ifndef GCC_SEL_SCHED_H
  #define GCC_SEL_SCHED_H

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