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] Implement readonly dependence contexts


Hello,

This patch implements readonly dependence contexts, which aim at reducing compile time of the scheduler. When moving up an expression through an insn, we spend quite a lot of time initializing the dependence context with an effect of this insn. This should be done just once per insn. To implement this, we need for the analysis to refrain from modifying this context, which brings us to the patch. The implementation is straightforward, we just introduce the new bitfield in struct deps and fix all appropriate places in sched-deps.c. While testing this, as usual I've fixed some thinkos from the previous patches.

Bootstrapped and regtested on ia64, committed to sel-sched branch.

Andrey
2007-10-02  Andrey Belevantsev  <abel@ispras.ru>

	Implement readonly dependence contexts.
	* sched-int.h (struct deps): New bitfield readonly.
	* sched-deps.c (add_dependence_list_and_free): Add deps parameter.
	Update all users.  Do not free dependence list when 
	deps context is readonly.
	(flush_pending_lists): Likewise.
	(add_insn_mem_dependence): Assert that deps context is not readonly.
	(deps_start_bb): Likewise.
	(extend_deps_reg_info): In a readonly context, do not extend 
	reg arrays.
	(sched_analyze_reg): Do not allocate sched_before_next_call in a 
	readonly context.
	(sched_analyze_1): Do not add memory dependence to a readonly context.
	(sched_analyze_2): Likewise.
	(sched_analyze_insn): Do not modify reg_last array of 
	a readonly context.  Likewise for reg_conditional_* regsets. 
	Do not handle post-call groups. 
	(deps_analyze_insn): Do not flush lists on jumps for 
	a readonly context.  Also, do not remember last function call;
	do not process libcalls.
	(init_deps_global, finish_deps_global): Kill #if 0'd code.
	* sel-sched-ir.h (struct _sel_insn_data): New field deps_context.
	(INSN_DEPS_CONTEXT, SUCC_ITER_EDGE): New accessor macros.
	(fallthru_bb_of_jump): Export.
	(inner_loop_header_p): Mark as inline.
	* sel-sched.c (moveup_rhs): Reformat conditions for moving up 
	a jump.
	(generate_bookkeeping_insn): Kill unneeded code.
	(move_cond_jump): Set EXPR_ORIG_BB_INDEX when moving an insn.
	(move_op): Tidy comments.  When merging expression data, do not 
	take into account bookkeeping insns.
	* sel-sched-ir.c (first_time_insn_init, 
	init_first_time_insn_data, free_first_time_insn_data): New.
	(init_global_and_expr_for_insn, finish_global_and_expr_insn,
	init_insn, init_simplejump): Use them.
	(fallthru_bb_of_jump): New.
	(sel_is_loop_preheader_p): Fix a merge thinko.  
	(has_dependence_p, tick_check_p): Tidy up.  Use readonly contexts
	when analyzing.	
Index: gcc/sel-sched.c
===================================================================
--- gcc/sel-sched.c	(revision 128952)
+++ gcc/sel-sched.c	(working copy)
@@ -1778,15 +1778,28 @@ moveup_rhs (rhs_t insn_to_move_up, insn_
       /* We can move jumps without side-effects or jumps that are
 	 mutually exculsive with instruction THROUGH_INSN (all in cases
 	 dependencies allow to do so and jump is not speculative).  */
-      if (control_flow_insn_p (insn)
-          && !(onlyjump_p (insn)
-	           && any_condjump_p (insn)
-               && !control_flow_insn_p (through_insn)
-               && !sel_insn_is_speculation_check (insn))
-          && !(sched_insns_conditions_mutex_p (insn, through_insn)
-               && !control_flow_insn_p (through_insn)
-               && !sel_insn_is_speculation_check (insn)))
-        return MOVEUP_RHS_NULL;
+      if (control_flow_insn_p (insn))
+        {
+          basic_block fallthru_bb;
+
+          /* Do not move checks and do not move jumps through other 
+             jumps.  */
+          if (control_flow_insn_p (through_insn)
+              || sel_insn_is_speculation_check (insn))
+            return MOVEUP_RHS_NULL;
+            
+          /* The jump should have a clear fallthru block, and 
+             this block should be in the current region.  */
+          if ((fallthru_bb = fallthru_bb_of_jump (insn)) == NULL
+              || ! in_current_region_p (fallthru_bb))
+            return MOVEUP_RHS_NULL;
+          
+          /* And it should be mutually exclusive with through_insn, or 
+             be an unconditional jump.  */
+          if (! any_uncondjump_p (insn)
+              && ! sched_insns_conditions_mutex_p (insn, through_insn))
+            return MOVEUP_RHS_NULL;
+        }
 
       if (CANT_MOVE (insn)
 	  && BLOCK_FOR_INSN (through_insn) != BLOCK_FOR_INSN (insn))
@@ -3533,6 +3546,8 @@ find_best_expr (av_set_t *av_vliw_ptr, b
 }
 
 
+/* Functions that implement the core of the scheduler.  */
+
 /* Emit an instruction from EXPR with SEQNO after PLACE_TO_INSERT.  */
 static insn_t
 gen_insn_from_expr_after (expr_t expr, int seqno, insn_t place_to_insert)
@@ -3572,8 +3587,6 @@ gen_insn_from_expr_after (expr_t expr, i
   }
 }
 
-/* Functions that implement the core of the scheduler.  */
-
 /* Generate a bookkeeping copy of "REG = CUR_RHS" insn at JOIN_POINT on the 
    ingoing path(s) to E2->dest, other than from E1->src (there could be some 
    empty blocks between E1->src and E2->dest).  If there is only one such path 
@@ -3774,17 +3787,6 @@ generate_bookkeeping_insn (rhs_t c_rhs, 
     copy_expr_onside (new_expr, c_rhs);
     change_vinsn_in_expr (new_expr, new_vinsn);
 
-    /* In preheader, make sure that the new insn is marked as not 
-       scheduled.  */
-    if (sel_is_loop_preheader_p (BLOCK_FOR_INSN (place_to_insert)))
-      EXPR_SCHED_TIMES (new_expr) = 0;
-    else
-      if (EXPR_SCHED_TIMES (new_expr)
-	>= PARAM_VALUE (PARAM_SELSCHED_MAX_SCHED_TIMES))
-      /* To make scheduling of this bookkeeping copy possible we decrease
-	 its scheduling counter.  */
-      --EXPR_SCHED_TIMES (new_expr);
-
     new_insn = gen_insn_from_expr_after (new_expr, new_seqno, place_to_insert);
     INSN_SCHED_TIMES (new_insn) = 0;
 
@@ -3907,6 +3909,7 @@ move_cond_jump (rtx insn, bnd_t bnd)
        link = NEXT_INSN (link))
     {
       set_block_for_insn (link, block_new);
+      EXPR_ORIG_BB_INDEX (INSN_EXPR (link)) = block_new->index;
       df_insn_change_bb (link);
     }
 
@@ -4678,9 +4681,9 @@ move_op (insn_t insn, av_set_t orig_ops,
 
       c_rhs_inited_p = false;
 
-	/* If we're scheduling separate rhs, in order to generate correct code
-	   we need to stop the search at bookkeeping code generated with the 
-	   same destination register or memory.  */
+      /* If we're scheduling separate rhs, in order to generate correct code
+         we need to stop the search at bookkeeping code generated with the 
+         same destination register or memory.  */
       if (lhs_of_insn_equals_to_dest_p (insn, dest))
 	av_set_clear (&orig_ops);
       else
@@ -4732,23 +4735,31 @@ move_op (insn_t insn, av_set_t orig_ops,
 		  c_rhs_inited_p = true;
 		}
 	      else
-		/* We must merge all found expressions to get reasonable
-		   EXPR_SPEC_DONE_DS () for the resulting insn.  If we don't
-		   do so then we can first find the expr with epsilon
-		   speculation success probability and only then with the
-		   good probability.  As a result the insn will get epsilon
-		   probability and will never be scheduled because of
-		   weakness_cutoff in find_best_expr.
+                {
+                  /* We must merge all found expressions to get reasonable
+                     EXPR_SPEC_DONE_DS for the resulting insn.  If we don't
+                     do so then we can first find the expr with epsilon
+                     speculation success probability and only then with the
+                     good probability.  As a result the insn will get epsilon
+                     probability and will never be scheduled because of
+                     weakness_cutoff in find_best_expr.
+                     
+                     We call merge_expr_data here instead of merge_expr 
+                     because due to speculation C_RHS and X may have the
+                     same insns with different speculation types.  And as of
+                     now such insns are considered non-equal.  
 
-		   We also workaround this in can_overcome_dep_p ()
-		   that consider low probability speculation success
-		   dependencies as hard ones.
+                     However, EXPR_SCHED_TIMES is different -- we must get 
+                     SCHED_TIMES from a real insn, not a bookkeeping copy.  
+                     We force this here.  Instead, we may consider merging
+                     SCHED_TIMES to the maximum instead of minimum in the 
+                     below function.  */
+                  int old_times = EXPR_SCHED_TIMES (c_rhs);
 
-		   We call merge_expr_data () here instead of merge_expr ()
-		   because due to speculation C_RHS and X may have the
-		   same insns with different speculation types.  And as of
-		   now such insns are considered non-correlable.  */
-		merge_expr_data (c_rhs, x);
+                  merge_expr_data (c_rhs, x);
+                  if (EXPR_SCHED_TIMES (x) == 0)
+                    EXPR_SCHED_TIMES (c_rhs) = old_times;
+                }
 
 	      clear_expr (x);
 	    }
Index: gcc/sel-sched-ir.c
===================================================================
--- gcc/sel-sched-ir.c	(revision 128952)
+++ gcc/sel-sched-ir.c	(working copy)
@@ -2041,6 +2041,39 @@ deps_init_id (idata_t id, insn_t insn, b
    an ASM or is within a SCHED_GROUP.  */
 
 static void init_invalid_av_set (basic_block);
+static void extend_insn (void);
+
+/* True when a "one-time init" data for INSN was already inited.  */
+static bool
+first_time_insn_init (insn_t insn)
+{
+  return INSN_ANALYZED_DEPS (insn) == NULL;
+}
+
+/* Init the s_i_d data for INSN which should be inited just once, when 
+   we first see the insn.  */
+static void
+init_first_time_insn_data (insn_t insn)
+{
+  /* This should not be set if this is the first time we init data for
+     insn.  */
+  gcc_assert (first_time_insn_init (insn));
+
+  INSN_ANALYZED_DEPS (insn) = BITMAP_ALLOC (NULL);
+  INSN_FOUND_DEPS (insn) = BITMAP_ALLOC (NULL);
+  init_deps (&INSN_DEPS_CONTEXT (insn));
+}
+
+/* Free the same data as above for INSN.  */
+static void
+free_first_time_insn_data (insn_t insn)
+{
+  gcc_assert (! first_time_insn_init (insn));
+
+  BITMAP_FREE (INSN_ANALYZED_DEPS (insn));
+  BITMAP_FREE (INSN_FOUND_DEPS (insn));
+  free_deps (&INSN_DEPS_CONTEXT (insn));
+}
 
 /* Initialize region-scope data structures for basic blocks.  */
 static void
@@ -2125,12 +2158,9 @@ init_global_and_expr_for_insn (insn_t in
 	       NULL, false);
   }
 
-  INSN_ANALYZED_DEPS (insn) = BITMAP_ALLOC (NULL);
-  INSN_FOUND_DEPS (insn) = BITMAP_ALLOC (NULL);
+  init_first_time_insn_data (insn);
 }
 
-static void extend_insn (void);
-
 /* Scan the region and initialize instruction data.  */
 void
 sel_init_global_and_expr (bb_vec_t bbs)
@@ -2168,8 +2198,7 @@ finish_global_and_expr_insn (insn_t insn
 
   if (INSN_LUID (insn) > 0)
     {
-      BITMAP_FREE (INSN_ANALYZED_DEPS (insn));
-      BITMAP_FREE (INSN_FOUND_DEPS (insn));
+      free_first_time_insn_data (insn);
 
       INSN_WS_LEVEL (insn) = 0;
 
@@ -2466,37 +2495,35 @@ sel_clear_has_dependence (void)
 ds_t
 has_dependence_p (rhs_t rhs, insn_t pred, ds_t **has_dep_pp)
 {
-  struct deps _dc;
   int i;
   ds_t ds;
+  struct deps *dc;
 
   if (INSN_SIMPLEJUMP_P (pred))
     /* Unconditional jump is just a transfer of control flow.
        Ignore it.  */
     return false;
 
-  has_dependence_data.dc = &_dc;
-  has_dependence_data.pro = NULL;
-
-  init_deps (has_dependence_data.dc);
-
-  /* Initialize empty dep context with information about PRED.  */
-  advance_deps_context (has_dependence_data.dc, pred);
+  dc = &INSN_DEPS_CONTEXT (pred);
+  if (!dc->readonly)
+    {
+      has_dependence_data.pro = NULL;
+      /* Initialize empty dep context with information about PRED.  */
+      advance_deps_context (dc, pred);
+      dc->readonly = 1;
+    }
 
   has_dependence_data.where = DEPS_IN_NOWHERE;
-
   has_dependence_data.pro = pred;
-
   has_dependence_data.con = RHS_VINSN (rhs);
+  has_dependence_data.dc = dc;
 
   sel_clear_has_dependence ();
 
   /* Now catch all dependencies that would be generated between PRED and
      INSN.  */
   setup_has_dependence_sched_deps_info ();
-  deps_analyze_insn (has_dependence_data.dc, RHS_INSN (rhs));
-
-  free_deps (has_dependence_data.dc);
+  deps_analyze_insn (dc, RHS_INSN (rhs));
   has_dependence_data.dc = NULL;
 
   *has_dep_pp = has_dependence_data.has_dep_p;
@@ -2621,22 +2648,18 @@ static struct sched_deps_info_def _tick_
 /* Returns true when VI's insn can be scheduled on the current cycle of 
    FENCE.  That is, all data from possible producers in DC_ORIG is ready.  */
 bool
-tick_check_p (rhs_t rhs, deps_t dc_orig, fence_t fence)
+tick_check_p (rhs_t rhs, deps_t dc, fence_t fence)
 {
-  struct deps _dc, *dc = &_dc;
-
   /* Initialize variables.  */
   tick_check_data.rhs = rhs;
   tick_check_data.cycle = 0;
   tick_check_data.seen_true_dep_p = false;
-
-  /* Calculate TICK_CHECK_CYCLE.  */
-  copy_deps_context (dc, dc_orig);
-
   sched_deps_info = &_tick_check_sched_deps_info;
+  
+  gcc_assert (!dc->readonly);
+  dc->readonly = 1;
   deps_analyze_insn (dc, RHS_INSN (rhs));
-
-  free_deps (dc);
+  dc->readonly = 0;
 
   return FENCE_CYCLE (fence) >= tick_check_data.cycle;
 }
@@ -3057,7 +3080,6 @@ static void
 init_insn (insn_t insn)
 {
   expr_t expr;
-  expr_t x;
   sel_insn_data_t ssid = insn_init_ssid;
 
   /* The fields mentioned below are special and hence are not being
@@ -3068,19 +3090,16 @@ init_insn (insn_t insn)
   gcc_assert (INSN_P (insn) && INSN_LUID (insn) > 0);
 
   expr = INSN_EXPR (insn);
-  x = &ssid->_expr;
-
-  copy_expr (expr, x);
+  copy_expr (expr, &ssid->_expr);
 
+  INSN_SEQNO (insn) = ssid->seqno;
   EXPR_ORIG_BB_INDEX (expr) = BLOCK_NUM (insn);
 
   if (insn_init_create_new_vinsn_p)
     change_vinsn_in_expr (expr, vinsn_create (insn, init_insn_force_unique_p));
-
-  INSN_SEQNO (insn) = ssid->seqno;
-
-  INSN_ANALYZED_DEPS (insn) = BITMAP_ALLOC (NULL);
-  INSN_FOUND_DEPS (insn) = BITMAP_ALLOC (NULL);
+  
+  if (first_time_insn_init (insn))
+    init_first_time_insn_data (insn);
 }
 
 /* This is used to initialize spurious jumps generated by
@@ -3093,8 +3112,7 @@ init_simplejump (insn_t insn)
 
   INSN_SEQNO (insn) = get_seqno_of_a_pred (insn);
 
-  INSN_ANALYZED_DEPS (insn) = BITMAP_ALLOC (NULL);
-  INSN_FOUND_DEPS (insn) = BITMAP_ALLOC (NULL);
+  init_first_time_insn_data (insn);
 }
 
 /* Perform deferred initialization of insns.  This is used to process 
@@ -3461,6 +3479,22 @@ in_current_region_p (basic_block bb)
   return CONTAINING_RGN (bb->index) == CONTAINING_RGN (BB_TO_BLOCK (0));
 }
 
+/* Return the block which is a fallthru bb of a conditional jump JUMP.  */
+basic_block
+fallthru_bb_of_jump (rtx jump)
+{
+  if (!JUMP_P (jump))
+    return NULL;
+
+  if (any_uncondjump_p (jump))
+    return single_succ (BLOCK_FOR_INSN (jump));
+
+  if (!any_condjump_p (jump))
+    return NULL;
+
+  return FALLTHRU_EDGE (BLOCK_FOR_INSN (jump))->dest;
+}
+
 /* Remove all notes from BB.  */
 static void
 init_bb (basic_block bb)
@@ -5147,21 +5181,21 @@ sel_add_loop_preheader (void)
   MARK_LOOP_FOR_PIPELINING (current_loop_nest);
 }
 
-/* While pipelining outer loops, returns TRUE if BB is a loop preheader.  */
+/* While pipelining outer loops, returns TRUE if BB is a loop preheader.  
+   Please note that the function should also work when pipelining_p is 
+   false, because it is used when deciding whether we should or should 
+   not reschedule pipelined code.  */
 bool
 sel_is_loop_preheader_p (basic_block bb)
 {
-  if (!pipelining_p)
-    return false;
-
-  /* Preheader is the first block in the region.  */
-  if (BLOCK_TO_BB (bb->index) == 0)
-    return true;
-
   if (current_loop_nest)
     {
       struct loop *outer;
 
+      /* Preheader is the first block in the region.  */
+      if (BLOCK_TO_BB (bb->index) == 0)
+        return true;
+
       /* We used to find a preheader with the topological information.
          Check that the above code is equivalent to what we did before.  */
 
Index: gcc/sel-sched-ir.h
===================================================================
--- gcc/sel-sched-ir.h	(revision 128952)
+++ gcc/sel-sched-ir.h	(working copy)
@@ -588,6 +588,9 @@ struct _sel_insn_data
      bitmap has its bit set.  */
   bitmap found_deps;
 
+  /* A context incapsulating this insn.  */
+  struct deps deps_context;
+
   /* Insn is an ASM.  */
   bool asm_p;
 
@@ -602,13 +605,13 @@ struct _sel_insn_data
      This is used for bundling.  */
   int sched_cycle;
 
+  /* Speculations that are being checked by this insn.  */
+  ds_t spec_checked_ds;
+
   /* True when an insn is scheduled after we've determined that a stall is
      required.
      This is used when emulating the Haifa scheduler for bundling.  */
   BOOL_BITFIELD after_stall_p : 1;
-
-  /* Speculations that are being checked by this insn.  */
-  ds_t spec_checked_ds;
 };
 
 typedef struct _sel_insn_data sel_insn_data_def;
@@ -627,6 +630,7 @@ extern sel_insn_data_def insn_sid (insn_
 #define INSN_SCHED_NEXT(INSN) (SID (INSN)->sched_next)
 #define INSN_ANALYZED_DEPS(INSN) (SID (INSN)->analyzed_deps)
 #define INSN_FOUND_DEPS(INSN) (SID (INSN)->found_deps) 
+#define INSN_DEPS_CONTEXT(INSN) (SID (INSN)->deps_context) 
 
 #define INSN_EXPR(INSN) (&SID (INSN)->_expr)
 #define INSN_VINSN(INSN) (RHS_VINSN (INSN_EXPR (INSN)))
@@ -929,10 +933,10 @@ extern insn_t sel_bb_head (basic_block);
 extern bool sel_bb_head_p (insn_t);
 extern insn_t sel_bb_end (basic_block);
 extern bool sel_bb_end_p (insn_t);
-
 extern bool sel_bb_empty_p (basic_block);
 
 extern bool in_current_region_p (basic_block);
+extern basic_block fallthru_bb_of_jump (rtx);
 
 extern void sel_init_bbs (bb_vec_t, basic_block);
 extern void sel_finish_bbs (void);
@@ -1008,7 +1012,7 @@ typedef struct
 
 
 /* True when BB is a header of the inner loop.  */
-static bool
+static inline bool
 inner_loop_header_p (basic_block bb)
 {
   struct loop *inner_loop; 
@@ -1391,6 +1395,9 @@ _eligible_successor_edge_p (edge e1, bas
 #define FOR_EACH_SUCC(SUCC, ITER, INSN) \
 FOR_EACH_SUCC_1 (SUCC, ITER, INSN, SUCCS_NORMAL)
 
+/* Return the current edge along which a successor was built.  */
+#define SUCC_ITER_EDGE(ITER) ((ITER)->e1)
+
 extern regset sel_all_regs;
 
 /* Return the next block of BB not running into inconsistencies.  */
Index: gcc/sched-deps.c
===================================================================
--- gcc/sched-deps.c	(revision 128952)
+++ gcc/sched-deps.c	(working copy)
@@ -427,7 +427,8 @@ static int cache_size;
 
 static int deps_may_trap_p (rtx);
 static void add_dependence_list (rtx, rtx, int, enum reg_note);
-static void add_dependence_list_and_free (rtx, rtx *, int, enum reg_note);
+static void add_dependence_list_and_free (struct deps *, rtx, 
+                                          rtx *, int, enum reg_note);
 static void delete_all_dependences (rtx);
 static void fixup_sched_groups (rtx);
 
@@ -1333,13 +1334,21 @@ add_dependence_list (rtx insn, rtx list,
     }
 }
 
-/* Similar, but free *LISTP at the same time.  */
+/* Similar, but free *LISTP at the same time, when the context 
+   is not readonly.  */
 
 static void
-add_dependence_list_and_free (rtx insn, rtx *listp, int uncond,
-			      enum reg_note dep_type)
+add_dependence_list_and_free (struct deps *deps, rtx insn, rtx *listp, 
+                              int uncond, enum reg_note dep_type)
 {
   rtx list, next;
+
+  if (deps->readonly)
+    {
+      add_dependence_list (insn, *listp, uncond, dep_type);
+      return;
+    }
+
   for (list = *listp, *listp = NULL; list ; list = next)
     {
       next = XEXP (list, 1);
@@ -1427,6 +1436,7 @@ add_insn_mem_dependence (struct deps *de
   rtx *mem_list;
   rtx link;
 
+  gcc_assert (!deps->readonly);
   if (read_p)
     {
       insn_list = &deps->pending_read_insns;
@@ -1462,21 +1472,29 @@ flush_pending_lists (struct deps *deps, 
 {
   if (for_write)
     {
-      add_dependence_list_and_free (insn, &deps->pending_read_insns, 1,
-				    REG_DEP_ANTI);
-      free_EXPR_LIST_list (&deps->pending_read_mems);
-      deps->pending_read_list_length = 0;
+      add_dependence_list_and_free (deps, insn, &deps->pending_read_insns, 
+                                    1, REG_DEP_ANTI);
+      if (!deps->readonly)
+        {
+          free_EXPR_LIST_list (&deps->pending_read_mems);
+          deps->pending_read_list_length = 0;
+        }
     }
 
-  add_dependence_list_and_free (insn, &deps->pending_write_insns, 1,
+  add_dependence_list_and_free (deps, insn, &deps->pending_write_insns, 1,
 				for_read ? REG_DEP_ANTI : REG_DEP_OUTPUT);
-  free_EXPR_LIST_list (&deps->pending_write_mems);
-  deps->pending_write_list_length = 0;
 
-  add_dependence_list_and_free (insn, &deps->last_pending_memory_flush, 1,
-				for_read ? REG_DEP_ANTI : REG_DEP_OUTPUT);
-  deps->last_pending_memory_flush = alloc_INSN_LIST (insn, NULL_RTX);
-  deps->pending_flush_length = 1;
+  add_dependence_list_and_free (deps, insn, 
+                                &deps->last_pending_memory_flush, 1,
+                                for_read ? REG_DEP_ANTI : REG_DEP_OUTPUT);
+  if (!deps->readonly)
+    {
+      free_EXPR_LIST_list (&deps->pending_write_mems);
+      deps->pending_write_list_length = 0;
+
+      deps->last_pending_memory_flush = alloc_INSN_LIST (insn, NULL_RTX);
+      deps->pending_flush_length = 1;
+    }
 }
 
 /* Instruction which dependencies we are analyzing.  */
@@ -1611,6 +1629,14 @@ extend_deps_reg_info (struct deps *deps,
   int max_regno = regno + 1;
 
   gcc_assert (!reload_completed);
+  
+  /* In a readonly context, it would not hurt to extend info,
+     but it should not be needed.  */
+  if (deps->readonly)
+    {
+      deps->max_reg = max_regno;
+      return;
+    }
       
   if (max_regno > deps->max_reg)
     {
@@ -1690,7 +1716,8 @@ sched_analyze_reg (struct deps *deps, in
 	 already cross one.  */
       if (REG_N_CALLS_CROSSED (regno) == 0)
 	{
-	  if (ref == USE)
+	  if (!deps->readonly 
+              && ref == USE)
 	    deps->sched_before_next_call
 	      = alloc_INSN_LIST (insn, deps->sched_before_next_call);
 	  else
@@ -1807,8 +1834,10 @@ sched_analyze_1 (struct deps *deps, rtx 
 	}
       t = canon_rtx (t);
 
-      if ((deps->pending_read_list_length + deps->pending_write_list_length)
-	  > MAX_PENDING_LIST_LENGTH)
+      /* Pending lists can't get larger with a readonly context.  */
+      if (!deps->readonly
+          && ((deps->pending_read_list_length + deps->pending_write_list_length)
+              > MAX_PENDING_LIST_LENGTH))
 	{
 	  /* Flush all pending reads and writes to prevent the pending lists
 	     from getting any larger.  Insn scheduling runs too slowly when
@@ -1850,7 +1879,8 @@ sched_analyze_1 (struct deps *deps, rtx 
 	  add_dependence_list (insn, deps->last_pending_memory_flush, 1,
 			       REG_DEP_ANTI);
 
-	  add_insn_mem_dependence (deps, false, insn, dest);
+          if (!deps->readonly)
+            add_insn_mem_dependence (deps, false, insn, dest);
 	}
       sched_analyze_2 (deps, XEXP (dest, 0), insn);
     }
@@ -2020,7 +2050,8 @@ sched_analyze_2 (struct deps *deps, rtx 
 
 	/* Always add these dependencies to pending_reads, since
 	   this insn may be followed by a write.  */
-	add_insn_mem_dependence (deps, true, insn, x);
+        if (!deps->readonly)
+          add_insn_mem_dependence (deps, true, insn, x);
 
 	/* Take advantage of tail recursion here.  */
 	sched_analyze_2 (deps, XEXP (x, 0), insn);
@@ -2232,8 +2263,12 @@ sched_analyze_insn (struct deps *deps, r
                   add_dependence_list (insn, reg_last->sets, 0, REG_DEP_ANTI);
                   add_dependence_list (insn, reg_last->clobbers, 0,
 				       REG_DEP_ANTI);
-                  reg_last->uses_length++;
-                  reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
+
+                  if (!deps->readonly)
+                    {
+                      reg_last->uses_length++;
+                      reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
+                    }
                 }
               IOR_REG_SET (reg_pending_sets, &tmp_sets);
 
@@ -2305,31 +2340,38 @@ sched_analyze_insn (struct deps *deps, r
 	  EXECUTE_IF_SET_IN_REG_SET (&deps->reg_last_in_use, 0, i, rsi)
 	    {
 	      struct deps_reg *reg_last = &deps->reg_last[i];
-	      add_dependence_list_and_free (insn, &reg_last->uses, 0,
+	      add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
 					    REG_DEP_ANTI);
 	      add_dependence_list_and_free
-		(insn, &reg_last->sets, 0,
+		(deps, insn, &reg_last->sets, 0,
 		 reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI);
 	      add_dependence_list_and_free
-		(insn, &reg_last->clobbers, 0,
+		(deps, insn, &reg_last->clobbers, 0,
 		 reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI);
-	      reg_last->uses_length = 0;
-	      reg_last->clobbers_length = 0;
+
+              if (!deps->readonly)
+                {
+                  reg_last->uses_length = 0;
+                  reg_last->clobbers_length = 0;
+                }
 	    }
 	}
 
-      for (i = 0; i < (unsigned)deps->max_reg; i++)
-	{
-	  struct deps_reg *reg_last = &deps->reg_last[i];
-	  reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
-	  SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
-	}
+      if (!deps->readonly)
+        for (i = 0; i < (unsigned)deps->max_reg; i++)
+          {
+            struct deps_reg *reg_last = &deps->reg_last[i];
+            reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
+            SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
+          }
 
       /* 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);
-      CLEAR_REG_SET (&deps->reg_conditional_sets);
+      
+      if (!deps->readonly)
+        CLEAR_REG_SET (&deps->reg_conditional_sets);
       reg_pending_barrier = NOT_A_BARRIER;
     }
   else
@@ -2343,16 +2385,24 @@ sched_analyze_insn (struct deps *deps, r
 	      struct deps_reg *reg_last = &deps->reg_last[i];
 	      add_dependence_list (insn, reg_last->sets, 0, REG_DEP_TRUE);
 	      add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_TRUE);
-	      reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
-	      reg_last->uses_length++;
+              
+              if (!deps->readonly)
+                {
+                  reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
+                  reg_last->uses_length++;
+                }
 	    }
 	  EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi)
 	    {
 	      struct deps_reg *reg_last = &deps->reg_last[i];
 	      add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
 	      add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
-	      reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers);
-	      reg_last->clobbers_length++;
+
+              if (!deps->readonly)
+                {
+                  reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers);
+                  reg_last->clobbers_length++;
+                }
 	    }
 	  EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi)
 	    {
@@ -2360,8 +2410,12 @@ sched_analyze_insn (struct deps *deps, r
 	      add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
 	      add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_OUTPUT);
 	      add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
-	      reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
-	      SET_REGNO_REG_SET (&deps->reg_conditional_sets, i);
+
+              if (!deps->readonly)
+                {
+                  reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
+                  SET_REGNO_REG_SET (&deps->reg_conditional_sets, i);
+                }
 	    }
 	}
       else
@@ -2371,8 +2425,12 @@ sched_analyze_insn (struct deps *deps, r
 	      struct deps_reg *reg_last = &deps->reg_last[i];
 	      add_dependence_list (insn, reg_last->sets, 0, REG_DEP_TRUE);
 	      add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_TRUE);
-	      reg_last->uses_length++;
-	      reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
+
+              if (!deps->readonly)
+                {
+                  reg_last->uses_length++;
+                  reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
+                }
 	    }
 	  EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi)
 	    {
@@ -2380,43 +2438,58 @@ sched_analyze_insn (struct deps *deps, r
 	      if (reg_last->uses_length > MAX_PENDING_LIST_LENGTH
 		  || reg_last->clobbers_length > MAX_PENDING_LIST_LENGTH)
 		{
-		  add_dependence_list_and_free (insn, &reg_last->sets, 0,
+		  add_dependence_list_and_free (deps, insn, &reg_last->sets, 0,
 					        REG_DEP_OUTPUT);
-		  add_dependence_list_and_free (insn, &reg_last->uses, 0,
+		  add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
 						REG_DEP_ANTI);
-		  add_dependence_list_and_free (insn, &reg_last->clobbers, 0,
+		  add_dependence_list_and_free (deps, insn, &reg_last->clobbers, 0,
 						REG_DEP_OUTPUT);
-		  reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
-		  reg_last->clobbers_length = 0;
-		  reg_last->uses_length = 0;
+
+                  if (!deps->readonly)
+                    {
+                      reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
+                      reg_last->clobbers_length = 0;
+                      reg_last->uses_length = 0;
+                    }
 		}
 	      else
 		{
 		  add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
 		  add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
 		}
-	      reg_last->clobbers_length++;
-	      reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers);
+
+              if (!deps->readonly)
+                {
+                  reg_last->clobbers_length++;
+                  reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers);
+                }
 	    }
 	  EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi)
 	    {
 	      struct deps_reg *reg_last = &deps->reg_last[i];
-	      add_dependence_list_and_free (insn, &reg_last->sets, 0,
+	      add_dependence_list_and_free (deps, insn, &reg_last->sets, 0,
 					    REG_DEP_OUTPUT);
-	      add_dependence_list_and_free (insn, &reg_last->clobbers, 0,
+	      add_dependence_list_and_free (deps, insn, &reg_last->clobbers, 0,
 					    REG_DEP_OUTPUT);
-	      add_dependence_list_and_free (insn, &reg_last->uses, 0,
+	      add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
 					    REG_DEP_ANTI);
-	      reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
-	      reg_last->uses_length = 0;
-	      reg_last->clobbers_length = 0;
-	      CLEAR_REGNO_REG_SET (&deps->reg_conditional_sets, i);
+
+              if (!deps->readonly)
+                {
+                  reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
+                  reg_last->uses_length = 0;
+                  reg_last->clobbers_length = 0;
+                  CLEAR_REGNO_REG_SET (&deps->reg_conditional_sets, i);
+                }
 	    }
 	}
 
-      IOR_REG_SET (&deps->reg_last_in_use, reg_pending_uses);
-      IOR_REG_SET (&deps->reg_last_in_use, reg_pending_clobbers);
-      IOR_REG_SET (&deps->reg_last_in_use, reg_pending_sets);
+      if (!deps->readonly)
+        {
+          IOR_REG_SET (&deps->reg_last_in_use, reg_pending_uses);
+          IOR_REG_SET (&deps->reg_last_in_use, reg_pending_clobbers);
+          IOR_REG_SET (&deps->reg_last_in_use, reg_pending_sets);
+        }
     }
 
   CLEAR_REG_SET (reg_pending_uses);
@@ -2476,7 +2549,8 @@ sched_analyze_insn (struct deps *deps, r
       if (src_regno < FIRST_PSEUDO_REGISTER
 	  || dest_regno < FIRST_PSEUDO_REGISTER)
 	{
-	  if (deps->in_post_call_group_p == post_call_initial)
+	  if (!deps->readonly
+              && 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) 
@@ -2488,7 +2562,8 @@ sched_analyze_insn (struct deps *deps, r
       else
 	{
 	end_call_group:
-	  deps->in_post_call_group_p = not_post_call;
+          if (!deps->readonly)
+            deps->in_post_call_group_p = not_post_call;
 	}
     }
 
@@ -2526,8 +2601,9 @@ deps_analyze_insn (struct deps *deps, rt
     {
       /* Make each JUMP_INSN (but not a speculative check) 
          a scheduling barrier for memory references.  */
-      if (JUMP_P (insn) && !(SEL_SCHED_P 
-                             && sel_insn_is_speculation_check (insn)))
+      if (!deps->readonly
+          && JUMP_P (insn) && !(SEL_SCHED_P 
+                                && sel_insn_is_speculation_check (insn)))
         {
           /* Keep the list a reasonable size.  */
           if (deps->pending_flush_length++ > MAX_PENDING_LIST_LENGTH)
@@ -2585,7 +2661,8 @@ deps_analyze_insn (struct deps *deps, rt
 
       /* For each insn which shouldn't cross a call, add a dependence
          between that insn and this call insn.  */
-      add_dependence_list_and_free (insn, &deps->sched_before_next_call, 1,
+      add_dependence_list_and_free (deps, insn, 
+                                    &deps->sched_before_next_call, 1,
                                     REG_DEP_ANTI);
 
       sched_analyze_insn (deps, PATTERN (insn), insn);
@@ -2605,14 +2682,17 @@ deps_analyze_insn (struct deps *deps, rt
          be passed a pointer to something we haven't written yet).  */
       flush_pending_lists (deps, insn, true, !CONST_OR_PURE_CALL_P (insn));
 
-      /* Remember the last function call for limiting lifetimes.  */
-      free_INSN_LIST_list (&deps->last_function_call);
-      deps->last_function_call = alloc_INSN_LIST (insn, NULL_RTX);
-
-      /* Before reload, begin a post-call group, so as to keep the
-         lifetimes of hard registers correct.  */
-      if (! reload_completed)
-        deps->in_post_call_group_p = post_call;
+      if (!deps->readonly)
+        {
+          /* Remember the last function call for limiting lifetimes.  */
+          free_INSN_LIST_list (&deps->last_function_call);
+          deps->last_function_call = alloc_INSN_LIST (insn, NULL_RTX);
+          
+          /* Before reload, begin a post-call group, so as to keep the
+             lifetimes of hard registers correct.  */
+          if (! reload_completed)
+            deps->in_post_call_group_p = post_call;
+        }
     }
 
   if (sched_deps_info->use_cselib)
@@ -2635,7 +2715,8 @@ deps_analyze_insn (struct deps *deps, rt
      As a side effect, we may get better code due to decreased register
      pressure as well as less chance of a foreign insn appearing in
      a libcall block.  */
-  if (!reload_completed
+  if (!deps->readonly
+      && !reload_completed
       /* Note we may have nested libcall sequences.  We only care about
          the outermost libcall sequence.  */
       && deps->libcall_block_tail_insn == 0
@@ -2660,7 +2741,8 @@ deps_analyze_insn (struct deps *deps, rt
 
   /* If we have reached the end of a libcall block, then close the
      block.  */
-  if (deps->libcall_block_tail_insn == insn)
+  if (!deps->readonly
+      && deps->libcall_block_tail_insn == insn)
     deps->libcall_block_tail_insn = 0;
 
   if (sched_deps_info->finish_insn)
@@ -2676,6 +2758,8 @@ deps_analyze_insn (struct deps *deps, rt
 void
 deps_start_bb (struct deps *deps, rtx head)
 {
+  gcc_assert (!deps->readonly);
+
   /* Before reload, if the previous block ended in a call, show that
      we are inside a post-call group, so as to keep the lifetimes of
      hard registers correct.  */
@@ -2799,6 +2883,7 @@ init_deps (struct deps *deps)
   deps->sched_before_next_call = 0;
   deps->in_post_call_group_p = not_post_call;
   deps->libcall_block_tail_insn = 0;
+  deps->readonly = 0;
 }
 
 /* Free insn lists found in DEPS.  */
@@ -2999,11 +3084,6 @@ init_deps_global (void)
       sched_deps_info->note_mem_dep = haifa_note_mem_dep;
       sched_deps_info->note_dep = haifa_note_dep;
    }
-  
-#if 0
-  if (SEL_SCHED_P && sched_deps_info->use_cselib)
-    cselib_init (true);
-#endif
 }
 
 /* Free everything used by the dependency analysis code.  */
@@ -3014,11 +3094,6 @@ finish_deps_global (void)
   FREE_REG_SET (reg_pending_sets);
   FREE_REG_SET (reg_pending_clobbers);
   FREE_REG_SET (reg_pending_uses);
-
-#if 0
-  if (SEL_SCHED_P && sched_deps_info->use_cselib)
-    cselib_finish ();
-#endif
 }
 
 /* Estimate the weakness of dependence between MEM1 and MEM2.  */
Index: gcc/sched-int.h
===================================================================
--- gcc/sched-int.h	(revision 128952)
+++ gcc/sched-int.h	(working copy)
@@ -514,6 +514,10 @@ struct deps
 
   /* Element N is set for each register that is conditionally set.  */
   regset_head reg_conditional_sets;
+
+  /* True when this context should be treated as a readonly by 
+     the analysis.  */
+  BOOL_BITFIELD readonly : 1;
 };
 
 typedef struct deps *deps_t;

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