haifa-sched.c (ok_for_early_schedule): New function.
authorDorit Naishlos <dorit@il.ibm.com>
Thu, 9 Oct 2003 09:08:37 +0000 (09:08 +0000)
committerDorit Nuzman <dorit@gcc.gnu.org>
Thu, 9 Oct 2003 09:08:37 +0000 (09:08 +0000)
        * haifa-sched.c (ok_for_early_schedule): New function.
        (early_queue_to_ready): New function.
        (schedule_block): Allow early removal of insns from Q.
        (schedule_insn): Update INSN_TICK in case of premature
        issue.
        * common.opt (sched_stalled_insns): New flag.
        (sched_stalled_insns_dep): New flag.
        * flags.h: Same above flags.
        * opts.c: Same as above.
        * toplev.c: Same as above.
        * target.h (targetm.sched.is_costly_dependence): New
        hook.
        * target-def.h: Same as above.
        * config/rs6000/rs6000.h: (rs6000_sched_costly_dep):
        Support new flag -msched-costly-dep.
        (DEFAULT_SCHED_COSTLY_DEP): Define.
        * config/rs6000/rs6000.c:
        (rs6000_is_costly_dependence): New function.
        (is_load_insn, is_store_insn): New functions.
        (is_load_insn1, is_store_insn1, is_mem_ref): New
        functions.
        * doc/invoke.texi (-fsched-stalled-insns-dep)
        (-fsched-stalled-insns, -msched-costly-dep): Document
        options.
        * doc/tm.texi (is_costly_dependence): Define new
        scheduler target hook.

From-SVN: r72261

12 files changed:
gcc/ChangeLog
gcc/common.opt
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/doc/invoke.texi
gcc/doc/tm.texi
gcc/flags.h
gcc/haifa-sched.c
gcc/opts.c
gcc/target-def.h
gcc/target.h
gcc/toplev.c

index cd3b6d9d8eab300f8f77a5a4b239a0e83269a945..bfbdbcf9387da4358258fa649e68af76f7cfcd32 100644 (file)
@@ -1,3 +1,32 @@
+2003-10-09  Dorit Naishlos  <dorit@il.ibm.com>
+
+       * haifa-sched.c (ok_for_early_schedule): New function.
+       (early_queue_to_ready): New function. 
+       (schedule_block): Allow early removal of insns from Q.
+       (schedule_insn): Update INSN_TICK in case of premature
+       issue.
+       * common.opt (sched_stalled_insns): New flag.
+       (sched_stalled_insns_dep): New flag.
+       * flags.h: Same above flags.
+       * opts.c: Same as above.
+       * toplev.c: Same as above.
+       * target.h (targetm.sched.is_costly_dependence): New
+       hook.
+       * target-def.h: Same as above.
+       * config/rs6000/rs6000.h: (rs6000_sched_costly_dep):
+       Support new flag -msched-costly-dep.
+       (DEFAULT_SCHED_COSTLY_DEP): Define.
+       * config/rs6000/rs6000.c:       
+       (rs6000_is_costly_dependence): New function.
+       (is_load_insn, is_store_insn): New functions.
+       (is_load_insn1, is_store_insn1, is_mem_ref): New 
+       functions.
+       * doc/invoke.texi (-fsched-stalled-insns-dep)
+       (-fsched-stalled-insns, -msched-costly-dep): Document
+       options.
+       * doc/tm.texi (is_costly_dependence): Define new 
+       scheduler target hook.
+
 2003-10-09  Jason Merrill  <jason@redhat.com>
 
        PR c++/6392
index 68c37b0c69612efdc071982ef351576b7188cbdc..ab1a69dcf4b24bfd789e3bdb9d457026a3bc31d4 100644 (file)
@@ -592,6 +592,22 @@ fschedule-insns2
 Common
 Reschedule instructions after register allocation
 
+fsched-stalled-insns
+Common
+Allow premature scheduling of queued insns
+
+fsched-stalled-insns=
+Common RejectNegative Joined UInteger 
+-fsched-stalled-insns=<number>       Set number of queued insns that can be prematurely scheduled
+
+fsched-stalled-insns-dep
+Common
+Set dependence distance checking in premature scheduling of queued insns
+
+fsched-stalled-insns-dep=
+Common RejectNegative Joined UInteger
+-fsched-stalled-insns-dep=<number>   Set dependence distance checking in premature scheduling of queued insns
+
 fshared-data
 Common
 Mark data as shared rather than private
index af31de54c522919045b5c604f2c7bd9df0746b3b..669f6ac6f19adb7bc83877f6b9b6168965d75164 100644 (file)
@@ -86,6 +86,10 @@ struct rs6000_cpu_select rs6000_select[3] =
 const char *rs6000_sched_restricted_insns_priority_str;
 int rs6000_sched_restricted_insns_priority;
 
+/* Support for -msched-costly-dep option.  */
+const char *rs6000_sched_costly_dep_str;
+enum rs6000_dependence_cost rs6000_sched_costly_dep;
+
 /* Size of long double */
 const char *rs6000_long_double_size_string;
 int rs6000_long_double_type_size;
@@ -278,6 +282,7 @@ static int rs6000_adjust_cost (rtx, rtx, rtx, int);
 static int is_dispatch_slot_restricted (rtx);
 static int rs6000_adjust_priority (rtx, int);
 static int rs6000_issue_rate (void);
+static bool rs6000_is_costly_dependence (rtx, rtx, rtx, int, int);
 static int rs6000_use_sched_lookahead (void);
 
 static void rs6000_init_builtins (void);
@@ -469,6 +474,8 @@ static const char alt_reg_names[][8] =
 #define TARGET_SCHED_ADJUST_COST rs6000_adjust_cost
 #undef TARGET_SCHED_ADJUST_PRIORITY
 #define TARGET_SCHED_ADJUST_PRIORITY rs6000_adjust_priority
+#undef TARGET_SCHED_IS_COSTLY_DEPENDENCE      
+#define TARGET_SCHED_IS_COSTLY_DEPENDENCE rs6000_is_costly_dependence
 
 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD rs6000_use_sched_lookahead
@@ -864,6 +871,21 @@ rs6000_override_options (const char *default_cpu)
     rs6000_sched_restricted_insns_priority =
       atoi (rs6000_sched_restricted_insns_priority_str);
 
+  /* Handle -msched-costly-dep option.  */
+  rs6000_sched_costly_dep = DEFAULT_SCHED_COSTLY_DEP;
+  if (rs6000_sched_costly_dep_str)
+    {
+      if (! strcmp (rs6000_sched_costly_dep_str, "no"))  
+        rs6000_sched_costly_dep = no_dep_costly;
+      else if (! strcmp (rs6000_sched_costly_dep_str, "all"))
+        rs6000_sched_costly_dep = all_deps_costly;
+      else if (! strcmp (rs6000_sched_costly_dep_str, "true_store_to_load"))
+        rs6000_sched_costly_dep = true_store_to_load_dep_costly;
+      else if (! strcmp (rs6000_sched_costly_dep_str, "store_to_load"))
+        rs6000_sched_costly_dep = store_to_load_dep_costly;
+      else rs6000_sched_costly_dep = atoi (rs6000_sched_costly_dep_str);
+    }
+
 #ifdef TARGET_REGNAMES
   /* If the user desires alternate register names, copy in the
      alternate names now.  */
@@ -13383,6 +13405,145 @@ rs6000_use_sched_lookahead (void)
   return 0;
 }
 
+/* Determine is PAT refers to memory.  */
+
+static bool
+is_mem_ref (rtx pat)
+{
+  const char * fmt;
+  int i, j;
+  bool ret = false;
+
+  if (GET_CODE (pat) == MEM)
+    return true;
+
+  /* Recursively process the pattern.  */
+  fmt = GET_RTX_FORMAT (GET_CODE (pat));
+
+  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0 && !ret; i--)
+    {
+      if (fmt[i] == 'e')
+       ret |= is_mem_ref (XEXP (pat, i));
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+         ret |= is_mem_ref (XVECEXP (pat, i, j));
+    }
+
+  return ret;
+}
+
+/* Determine if PAT is a PATTERN of a load insn.  */
+static bool
+is_load_insn1 (rtx pat)
+{
+  if (!pat || pat == NULL_RTX)
+    return false;
+
+  if (GET_CODE (pat) == SET)
+    return is_mem_ref (SET_SRC (pat));
+
+  if (GET_CODE (pat) == PARALLEL)
+    {
+      int i;
+
+      for (i = 0; i < XVECLEN (pat, 0); i++)
+       if (is_load_insn1 (XVECEXP (pat, 0, i)))
+         return true;
+    }
+
+  return false;
+}
+
+/* Determine if INSN loads from memory.  */
+
+static bool
+is_load_insn (rtx insn)
+{
+  if (!insn || !INSN_P (insn))
+    return false;
+
+  if (GET_CODE (insn) == CALL_INSN)
+    return false;
+
+  return is_load_insn1 (PATTERN (insn));
+}
+
+/* Determine if PAT is a PATTERN of a store insn.  */
+
+static bool
+is_store_insn1 (rtx pat)
+{
+  if (!pat || pat == NULL_RTX)
+    return false;
+
+  if (GET_CODE (pat) == SET)
+    return is_mem_ref (SET_DEST (pat));
+
+  if (GET_CODE (pat) == PARALLEL)
+    {
+      int i;
+
+      for (i = 0; i < XVECLEN (pat, 0); i++)
+       if (is_store_insn1 (XVECEXP (pat, 0, i)))
+         return true;
+    }
+
+  return false;
+}
+
+/* Determine if INSN stores to memory.  */
+
+static bool
+is_store_insn (rtx insn)
+{
+  if (!insn || !INSN_P (insn))
+    return false;
+
+  return is_store_insn1 (PATTERN (insn));
+}
+
+/* Returns whether the dependence between INSN and NEXT is considered
+   costly by the given target.  */
+
+static bool
+rs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost, int distance)
+{      
+  /* If the flag is not enbled - no dependence is considered costly;
+     allow all dependent insns in the same group. 
+     This is the most aggressive option.  */
+  if (rs6000_sched_costly_dep == no_dep_costly)
+    return false;
+
+  /* If the flag is set to 1 - a dependence is always considered costly; 
+     do not allow dependent instructions in the same group.
+     This is the most conservative option.  */
+  if (rs6000_sched_costly_dep == all_deps_costly)
+    return true;       
+
+  if (rs6000_sched_costly_dep == store_to_load_dep_costly 
+      && is_load_insn (next) 
+      && is_store_insn (insn))
+    /* Prevent load after store in the same group.  */
+    return true;
+
+  if (rs6000_sched_costly_dep == true_store_to_load_dep_costly
+      && is_load_insn (next) 
+      && is_store_insn (insn)
+      && (!link || (int) REG_NOTE_KIND (link) == 0))
+     /* Prevent load after store in the same group if it is a true dependence.  */
+     return true;
+    
+  /* The flag is set to X; dependences with latency >= X are considered costly, 
+     and will not be scheduled in the same group.  */
+  if (rs6000_sched_costly_dep <= max_dep_latency
+      && ((cost - distance) >= (int)rs6000_sched_costly_dep))
+    return true;
+
+  return false;
+}
+
+
 \f
 /* Length in units of the trampoline for entering a nested function.  */
 
index 5d7e2e7d54629afd5f4972b8c469783a958e6ab9..fbdb6a5c06bd355f816c21c364cc0a97552bacbb 100644 (file)
@@ -376,6 +376,16 @@ extern enum processor_type rs6000_cpu;
    and the old mnemonics are dialect zero.  */
 #define ASSEMBLER_DIALECT (TARGET_NEW_MNEMONICS ? 1 : 0)
 
+/* Types of costly dependences.  */
+enum rs6000_dependence_cost
+ {
+   max_dep_latency = 1000,
+   no_dep_costly,
+   all_deps_costly,
+   true_store_to_load_dep_costly,
+   store_to_load_dep_costly
+ };
+
 /* This is meant to be overridden in target specific files.  */
 #define        SUBTARGET_OPTIONS
 
@@ -402,6 +412,8 @@ extern enum processor_type rs6000_cpu;
    {"longcall", &rs6000_longcall_switch,                               \
     N_("Avoid all range limits on call instructions"), 0},             \
    {"no-longcall", &rs6000_longcall_switch, "", 0},                    \
+   {"sched-costly-dep=", &rs6000_sched_costly_dep_str,                  \
+    N_("determine which dependences between insns are considered costly"), 0}, \
    {"align-", &rs6000_alignment_string,                                        \
     N_("Specify alignment of structure fields default/natural"), 0},   \
    {"prioritize-restricted-insns=", &rs6000_sched_restricted_insns_priority_str, \
@@ -461,6 +473,8 @@ extern const char* rs6000_alignment_string;
 extern int rs6000_alignment_flags;
 extern const char *rs6000_sched_restricted_insns_priority_str;
 extern int rs6000_sched_restricted_insns_priority;
+extern const char *rs6000_sched_costly_dep_str;
+extern enum rs6000_dependence_cost rs6000_sched_costly_dep;
 
 /* Alignment options for fields in structures for sub-targets following
    AIX-like ABI.
@@ -479,6 +493,11 @@ extern int rs6000_sched_restricted_insns_priority;
 #define TARGET_ALIGN_NATURAL 0
 #endif
 
+/* Set a default value for DEFAULT_SCHED_COSTLY_DEP used by target hook
+   is_costly_dependence.  */ 
+#define DEFAULT_SCHED_COSTLY_DEP                           \
+  (rs6000_cpu == PROCESSOR_POWER4 ? store_to_load_dep_costly : no_dep_costly)
+
 /* Define if the target has restricted dispatch slot instructions.  */
 #define DEFAULT_RESTRICTED_INSNS_PRIORITY (rs6000_cpu == PROCESSOR_POWER4 ? 1 : 0)
 
index b943146c9ec9e8f1c7cb14185ceebee8b0ebeb5c..20ef67f7586dc21fb9eef16366a6fef76b23cd09 100644 (file)
@@ -287,7 +287,9 @@ in the following sections.
 -frerun-cse-after-loop  -frerun-loop-opt @gol
 -frounding-math -fschedule-insns  -fschedule-insns2 @gol
 -fno-sched-interblock  -fno-sched-spec  -fsched-spec-load @gol
--fsched-spec-load-dangerous  -fsched2-use-superblocks @gol
+-fsched-spec-load-dangerous  @gol
+-fsched-stalled-insns=@var{n} -sched-stalled-insns-dep=@var{n} @gol
+-fsched2-use-superblocks @gol
 -fsched2-use-traces  -fsignaling-nans @gol
 -fsingle-precision-constant  -fssa  -fssa-ccp  -fssa-dce @gol
 -fstrength-reduce  -fstrict-aliasing  -ftracer  -fthread-jumps @gol
@@ -432,6 +434,7 @@ in the following sections.
 -mtoc  -mno-toc  -mlittle  -mlittle-endian  -mbig  -mbig-endian @gol
 -mdynamic-no-pic @gol
 -mprioritize-restricted-insns=@var{priority} @gol
+-msched-costly-dep=@var{dependence_type} @gol
 -mcall-sysv  -mcall-netbsd @gol
 -maix-struct-return  -msvr4-struct-return @gol
 -mabi=altivec  -mabi=no-altivec @gol
@@ -4115,6 +4118,18 @@ Allow speculative motion of more load instructions.  This only makes
 sense when scheduling before register allocation, i.e.@: with
 @option{-fschedule-insns} or at @option{-O2} or higher.
 
+@item -fsched-stalled-insns=@var{n}
+@opindex fsched-stalled-insns
+Define how many insns (if any) can be moved prematurely from the queue
+of stalled insns into the ready list, during the second scheduling pass.
+
+@item -fsched-stalled-insns-dep=@var{n}
+@opindex fsched-stalled-insns-dep
+Define how many insn groups (cycles) will be examined for a dependency 
+on a stalled insn that is candidate for premature removal from the queue 
+of stalled insns.  Has an effect only during the second scheduling pass, 
+and only if @option{-fsched-stalled-insns} is used and its value is not zero.
+
 @item -fsched2-use-superblocks
 @opindex fsched2-use-superblocks
 When scheduling after register allocation, do use superblock scheduling
@@ -7535,6 +7550,17 @@ pass.  The argument @var{priority} takes the value @var{0/1/2} to assign
 @var{no/highest/second-highest} priority to dispatch slot restricted 
 instructions.
 
+@item -msched-costly-dep=@var{dependence_type}
+@opindex msched-costly-dep
+This option controls which dependences are considered costly
+by the target during instruction scheduling.  The argument
+@var{dependence_type} takes one of the following values:
+@var{no}: no dependence is costly, 
+@var{all}: all dependences are costly, 
+@var{true_store_to_load}: a true dependence from store to load is costly,
+@var{store_to_load}: any dependence from store to load is costly,
+@var{number}: any dependence which latency >= @var{number} is costly.
 @item -mcall-sysv
 @opindex mcall-sysv
 On System V.4 and embedded PowerPC systems compile code using calling
index 2fa6fbd11e22f76ee8f977814d00c46c8e1e3b26..1645319dff0f707b74785d368033129bed97b887 100644 (file)
@@ -5668,6 +5668,28 @@ zero.  The hook should return @code{NULL} if there are no more nop
 insns with indexes greater than given index.
 @end deftypefn
 
+@deftypefn {Target Hook} bool IS_COSTLY_DEPENDENCE (rtx @var{insn1}, rtx @var{insn2}, rtx @var{dep_link}, int @var{dep_cost}, int @var{distance})
+This hook is used to define which dependences are considered costly by
+the target, so costly that it is not advisable to schedule the insns that 
+are involved in the dependence too close to one another.  The parameters
+to this hook are as follows:  The second parameter @var{insn2} is dependent 
+upon the first parameter @var{insn1}.  The dependence between @var{insn1} 
+and @var{insn2} is represented by the third parameter @var{dep_link}.  The 
+fourth parameter @var{cost} is the cost of the dependence, and the fifth 
+parameter @var{distance} is the distance in cycles between the two insns. 
+The hook returns @code{true} if considering the distance between the two
+insns the dependence between them is considered costly by the target,
+and @code{false} otherwise.
+
+Defining this hook can be useful in multiple-issue out-of-order machines,
+where (a) it's practically hopeless to predict the actual data/resource 
+delays, however: (b) there's a better chance to predict the actual grouping
+that will be formed, and (c) correctly emulating the grouping can be very 
+important.  In such targets one may want to allow issuing dependent insns
+closer to one another - i.e, closer than the dependence distance;  however, 
+not in cases of "costly dependences", which this hooks allows to define.
+@end deftypefn
+
 Macros in the following table are generated by the program
 @file{genattr} and can be useful for writing the hooks.
 
index 4d6ea074174bffb0dda208109b991937969924cb..f345b49719745af9866db639996780466d897368 100644 (file)
@@ -439,6 +439,20 @@ extern int flag_schedule_speculative;
 extern int flag_schedule_speculative_load;
 extern int flag_schedule_speculative_load_dangerous;
 
+/* The following flags have an effect during scheduling after register
+   allocation:   
+
+   sched_stalled_insns means that insns can be moved prematurely from the queue
+   of stalled insns into the ready list.
+
+   sched_stalled_insns_dep controls how many recently scheduled cycles will 
+   be examined for a dependency on a stalled insn that is candidate for
+   premature removal from the queue of stalled insns into the ready list (has 
+   an effect only if the flag 'sched_stalled_insns' is set).  */
+
+extern int flag_sched_stalled_insns;
+extern int flag_sched_stalled_insns_dep;
+
 /* flag_branch_on_count_reg means try to replace add-1,compare,branch tupple
    by a cheaper branch, on a count register.  */
 extern int flag_branch_on_count_reg;
index 652ad18b83b17d4144e38f7bd92b07e248d7ee5e..40a0a76b3f88c1b4550c05796a83540a84eb7839 100644 (file)
@@ -517,6 +517,7 @@ static void ready_sort (struct ready_list *);
 static rtx ready_remove_first (struct ready_list *);
 
 static void queue_to_ready (struct ready_list *);
+static int early_queue_to_ready (state_t, struct ready_list *);
 
 static void debug_ready_list (struct ready_list *);
 
@@ -1247,6 +1248,7 @@ schedule_insn (rtx insn, struct ready_list *ready, int clock)
   rtx link;
   int advance = 0;
   int unit = 0;
+  int premature_issue = 0;
 
   if (!targetm.sched.use_dfa_pipeline_interface
       || !(*targetm.sched.use_dfa_pipeline_interface) ())
@@ -1290,12 +1292,19 @@ schedule_insn (rtx insn, struct ready_list *ready, int clock)
        return 0;
     }
 
+  if (INSN_TICK (insn) > clock)
+    {
+      /* 'insn' has been prematurely moved from the queue to the
+        ready list.  */
+      premature_issue = INSN_TICK (insn) - clock;
+    }
+
   for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
     {
       rtx next = XEXP (link, 0);
       int cost = insn_cost (insn, link, next);
 
-      INSN_TICK (next) = MAX (INSN_TICK (next), clock + cost);
+      INSN_TICK (next) = MAX (INSN_TICK (next), clock + cost + premature_issue);
 
       if ((INSN_DEP_COUNT (next) -= 1) == 0)
        {
@@ -1809,6 +1818,159 @@ queue_to_ready (struct ready_list *ready)
     }
 }
 
+/* Used by early_queue_to_ready.  Determines whether it is "ok" to
+   prematurely move INSN from the queue to the ready list.  Currently, 
+   if a target defines the hook 'is_costly_dependence', this function 
+   uses the hook to check whether there exist any dependences which are
+   considered costly by the target, between INSN and other insns that 
+   have already been scheduled.  Dependences are checked up to Y cycles
+   back, with default Y=1; The flag -fsched-stalled-insns-dep=Y allows
+   controlling this value. 
+   (Other considerations could be taken into account instead (or in 
+   addition) depending on user flags and target hooks.  */
+
+static bool 
+ok_for_early_queue_removal (rtx insn)
+{
+  int n_cycles;
+  rtx prev_insn = last_scheduled_insn;
+
+  if (targetm.sched.is_costly_dependence)
+    {
+      for (n_cycles = flag_sched_stalled_insns_dep; n_cycles; n_cycles--)
+       {
+         for ( ; prev_insn; prev_insn = PREV_INSN (prev_insn))
+           {
+             rtx dep_link = 0;
+             int dep_cost;
+
+             if (GET_CODE (prev_insn) != NOTE)
+               {
+                 dep_link = find_insn_list (insn, INSN_DEPEND (prev_insn));
+                 if (dep_link)
+                   {
+                     dep_cost = insn_cost (prev_insn, dep_link, insn) ;
+                     if (targetm.sched.is_costly_dependence (prev_insn, insn, 
+                               dep_link, dep_cost, 
+                               flag_sched_stalled_insns_dep - n_cycles))
+                       return false;
+                   }
+               }
+
+             if (GET_MODE (prev_insn) == TImode) /* end of dispatch group */
+               break;
+           }
+
+         if (!prev_insn) 
+           break;
+         prev_insn = PREV_INSN (prev_insn);     
+       }
+    }
+
+  return true;
+}
+
+
+/* Remove insns from the queue, before they become "ready" with respect
+   to FU latency considerations.   */
+
+static int 
+early_queue_to_ready (state_t state, struct ready_list *ready)
+{
+  rtx insn;
+  rtx link;
+  rtx next_link;
+  rtx prev_link;
+  bool move_to_ready;
+  int cost;
+  state_t temp_state = alloca (dfa_state_size);
+  int stalls;
+  int insns_removed = 0;
+
+  /*
+     Flag '-fsched-stalled-insns=X' determines the aggressiveness of this 
+     function: 
+
+     X == 0: There is no limit on how many queued insns can be removed          
+             prematurely.  (flag_sched_stalled_insns = -1).
+
+     X >= 1: Only X queued insns can be removed prematurely in each 
+            invocation.  (flag_sched_stalled_insns = X).
+
+     Otherwise: Early queue removal is disabled.
+         (flag_sched_stalled_insns = 0)
+  */
+
+  if (! flag_sched_stalled_insns)   
+    return 0;
+
+  for (stalls = 0; stalls <= MAX_INSN_QUEUE_INDEX; stalls++)
+    {
+      if ((link = insn_queue[NEXT_Q_AFTER (q_ptr, stalls)]))
+       {
+         if (sched_verbose > 6)
+           fprintf (sched_dump, ";; look at index %d + %d\n", q_ptr, stalls);
+
+         prev_link = 0;
+         while (link)
+           {
+             next_link = XEXP (link, 1);
+             insn = XEXP (link, 0);
+             if (insn && sched_verbose > 6)
+               print_rtl_single (sched_dump, insn);
+
+             memcpy (temp_state, state, dfa_state_size);
+             if (recog_memoized (insn) < 0) 
+               /* non-negative to indicate that it's not ready
+                  to avoid infinite Q->R->Q->R... */
+               cost = 0;
+             else
+               cost = state_transition (temp_state, insn);
+
+             if (sched_verbose >= 6)
+               fprintf (sched_dump, "transition cost = %d\n", cost);
+
+             move_to_ready = false;
+             if (cost < 0) 
+               {
+                 move_to_ready = ok_for_early_queue_removal (insn);
+                 if (move_to_ready == true)
+                   {
+                     /* move from Q to R */
+                     q_size -= 1;
+                     ready_add (ready, insn);
+
+                     if (prev_link)   
+                       XEXP (prev_link, 1) = next_link;
+                     else
+                       insn_queue[NEXT_Q_AFTER (q_ptr, stalls)] = next_link;
+
+                     free_INSN_LIST_node (link);
+
+                     if (sched_verbose >= 2)
+                       fprintf (sched_dump, ";;\t\tEarly Q-->Ready: insn %s\n",
+                                (*current_sched_info->print_insn) (insn, 0));
+
+                     insns_removed++;
+                     if (insns_removed == flag_sched_stalled_insns)
+                       /* remove only one insn from Q at a time */
+                       return insns_removed;
+                   }
+               }
+
+             if (move_to_ready == false)
+               prev_link = link;
+
+             link = next_link;
+           } /* while link */
+       } /* if link */    
+
+    } /* for stalls.. */
+
+  return insns_removed; 
+}
+
+
 /* Print the ready list for debugging purposes.  Callable from debugger.  */
 
 static void
@@ -2251,6 +2413,20 @@ schedule_block (int b, int rgn_n_insns)
            }
          else
            {
+             if (ready.n_ready == 0 
+                 && can_issue_more 
+                 && reload_completed) 
+               {
+                 /* Allow scheduling insns directly from the queue in case
+                    there's nothing better to do (ready list is empty) but
+                    there are still vacant dispatch slots in the current cycle.  */
+                 if (sched_verbose >= 6)
+                   fprintf(sched_dump,";;\t\tSecond chance\n");
+                 memcpy (temp_state, curr_state, dfa_state_size);
+                 if (early_queue_to_ready (temp_state, &ready))
+                   ready_sort (&ready);
+               }
+
              if (ready.n_ready == 0 || !can_issue_more
                  || state_dead_lock_p (curr_state)
                  || !(*current_sched_info->schedule_more_p) ())
index c4c5b9fd414afef95947905c05b3f394e570f7eb..dc489e19b31bdc76b03db9fd2e2999cfca2e4a05 100644 (file)
@@ -1264,6 +1264,24 @@ common_handle_option (size_t scode, const char *arg,
       flag_schedule_insns_after_reload = value;
       break;
 
+    case OPT_fsched_stalled_insns:
+      flag_sched_stalled_insns = value;
+      break;
+
+    case OPT_fsched_stalled_insns_:
+      flag_sched_stalled_insns = value;
+      if (flag_sched_stalled_insns == 0)
+       flag_sched_stalled_insns = -1;
+      break;
+
+    case OPT_fsched_stalled_insns_dep:
+      flag_sched_stalled_insns_dep = 1;
+      break;
+
+    case OPT_fsched_stalled_insns_dep_:
+      flag_sched_stalled_insns_dep = value;
+      break;
+
     case OPT_fshared_data:
       flag_shared_data = value;
       break;
index e5606a3a5bc48cd0ebbace5ded602e954b088921..3f35e2e90d80dc661ce4a3a7d9b6edbea1d410e9 100644 (file)
@@ -230,6 +230,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #define TARGET_SCHED_DFA_NEW_CYCLE 0
 #define TARGET_SCHED_INIT_DFA_BUBBLES 0
 #define TARGET_SCHED_DFA_BUBBLE 0
+#define TARGET_SCHED_IS_COSTLY_DEPENDENCE 0
 
 #define TARGET_SCHED                                           \
   {TARGET_SCHED_ADJUST_COST,                                   \
@@ -250,7 +251,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD_GUARD,     \
    TARGET_SCHED_DFA_NEW_CYCLE,                                 \
    TARGET_SCHED_INIT_DFA_BUBBLES,                              \
-   TARGET_SCHED_DFA_BUBBLE}
+   TARGET_SCHED_DFA_BUBBLE,                                     \
+   TARGET_SCHED_IS_COSTLY_DEPENDENCE}
 
 /* In tree.c.  */
 #define TARGET_MERGE_DECL_ATTRIBUTES merge_decl_attributes
index 15d723334b85457130fb158a2734b62d9a56ba70..8d77dfde2d058685e3121764643a414ed34f7aba 100644 (file)
@@ -251,6 +251,18 @@ struct gcc_target
        scheduling.  */
     void (* init_dfa_bubbles) (void);
     rtx (* dfa_bubble) (int);
+    /* The following member value is a pointer to a function called
+       by the insn scheduler.  It should return true if there exists a
+       dependence which is considered costly by the target, between 
+       the insn passed as the first parameter, and the insn passed as 
+       the second parameter.  The third parameter is the INSN_DEPEND 
+       link that represents the dependence between the two insns.  The
+       fourth argument is the cost of the dependence as estimated by
+       the scheduler.  The last argument is the distance in cycles 
+       between the already scheduled insn (first parameter) and the
+       the second insn (second parameter).
+    */
+    bool (* is_costly_dependence) PARAMS ((rtx, rtx, rtx, int, int));
   } sched;
 
   /* Given two decls, merge their attributes and return the result.  */
index 425a02597c1b60fe3babd8ff4f2ce7aae6ffa95c..bc96c649879b89d5de23e0e78a62c58aa596258a 100644 (file)
@@ -826,6 +826,20 @@ int flag_schedule_speculative = 1;
 int flag_schedule_speculative_load = 0;
 int flag_schedule_speculative_load_dangerous = 0;
 
+/* The following flags have an effect during scheduling after register
+   allocation:
+
+   flag_sched_stalled_insns means that insns can be moved prematurely from the queue
+   of stalled insns into the ready list.
+  
+   flag_sched_stalled_insns_dep controls how many insn groups will be examined
+   for a dependency on a stalled insn that is candidate for premature removal
+   from the queue of stalled insns into the ready list (has an effect only if
+   the flag 'sched_stalled_insns' is set).  */ 
+
+int flag_sched_stalled_insns = 0;
+int flag_sched_stalled_insns_dep = 1;
+
 int flag_single_precision_constant;
 
 /* flag_branch_on_count_reg means try to replace add-1,compare,branch tupple
@@ -1069,6 +1083,8 @@ static const lang_independent_options f_options[] =
   {"sched-spec",&flag_schedule_speculative, 1 },
   {"sched-spec-load",&flag_schedule_speculative_load, 1 },
   {"sched-spec-load-dangerous",&flag_schedule_speculative_load_dangerous, 1 },
+  {"sched-stalled-insns", &flag_sched_stalled_insns, 0 },
+  {"sched-stalled-insns-dep", &flag_sched_stalled_insns_dep, 1 },
   {"sched2-use-superblocks", &flag_sched2_use_superblocks, 1 },
   {"sched2-use-traces", &flag_sched2_use_traces, 1 },
   {"branch-count-reg",&flag_branch_on_count_reg, 1 },