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]

[3/4] SMS: Record moves in the partial schedule


This patch adds infrastructure that will be used by the final patch.
Specifically:

  - it splits the generation of register moves into two: schedule_reg_moves
    records moves in the partial schedule, while apply_reg_moves makes the
    register substitutions.

    This patch doesn't actually schedule the moves.  Instead, there's
    some throw-away code in apply_reg_moves to emit the moves in the
    same as we do now.  That's throw-away code that will be removed
    in the final patch.

  - schedule_reg_moves is allowed to fail.  We then try again with the
    next ii (subject to the usual ii limits).

    In this patch, schedule_reg_moves always returns true.

  - The partial schedule uses ids to represent register moves.
    The first register move has id g->num_nodes.

Richard


gcc/
	* modulo-sched.c (ps_insn): Adjust comment.
	(ps_reg_move_info): New structure.
	(partial_schedule): Add reg_moves field.
	(SCHED_PARAMS): Use node_sched_param_vec instead of node_sched_params.
	(node_sched_params): Turn first_reg_move into an identifier.
	(ps_reg_move): New function.
	(ps_rtl_insn): Cope with register moves.
	(ps_first_note): Adjust comment and assert that the instruction
	isn't a register move.
	(node_sched_params): Replace with...
	(node_sched_param_vec): ...this vector.
	(set_node_sched_params): Adjust accordingly.
	(print_node_sched_params): Take a partial schedule instead of a ddg.
	Use ps_rtl_insn and ps_reg_move.
	(generate_reg_moves): Rename to...
	(schedule_reg_moves): ...this.  Remove rescan parameter.  Record each
	move in the partial schedule, but don't emit it here.  Don't perform
	register substitutions here either.
	(apply_reg_moves): New function.
	(duplicate_insns_of_cycles): Use register indices directly,
	rather than finding instructions using PREV_INSN.  Use ps_reg_move.
	(sms_schedule): Call schedule_reg_moves before committing to
	a partial schedule.   Try the next ii if the schedule fails.
	Use apply_reg_moves instead of generate_reg_moves.  Adjust
	call to print_node_sched_params.  Free node_sched_param_vec
	instead of node_sched_params.
	(create_partial_schedule): Initialize reg_moves.
	(free_partial_schedule): Free reg_moves.

Index: gcc/modulo-sched.c
===================================================================
*** gcc/modulo-sched.c	2011-08-30 11:32:13.924908138 +0100
--- gcc/modulo-sched.c	2011-08-30 13:06:36.528669762 +0100
*************** #define PS_STAGE_COUNT(ps) (((partial_sc
*** 124,130 ****
  /* A single instruction in the partial schedule.  */
  struct ps_insn
  {
!   /* The number of the ddg node whose instruction is being scheduled.  */
    int id;
  
    /* The (absolute) cycle in which the PS instruction is scheduled.
--- 124,132 ----
  /* A single instruction in the partial schedule.  */
  struct ps_insn
  {
!   /* Identifies the instruction to be scheduled.  Values smaller than
!      the ddg's num_nodes refer directly to ddg nodes.  A value of
!      X - num_nodes refers to register move X.  */
    int id;
  
    /* The (absolute) cycle in which the PS instruction is scheduled.
*************** struct ps_insn
*** 137,142 ****
--- 139,170 ----
  
  };
  
+ /* Information about a register move that has been added to a partial
+    schedule.  */
+ struct ps_reg_move_info
+ {
+   /* The dependencies exist between the ps_insn with id DEF and the
+      ps_insns with the ids in USES.  */
+   int def;
+   sbitmap uses;
+ 
+   /* DEF's instruction defines OLD_REG.  The original form of
+      USES' instructions used it.  */
+   rtx old_reg;
+ 
+   /* USES's instructions must now use NEW_REG instead of OLD_REG.  */
+   rtx new_reg;
+ 
+   /* An instruction that sets NEW_REG to the correct value.  The first
+      move associated with DEF will have an rhs of OLD_REG; later moves
+      use the result of the previous move.  */
+   rtx insn;
+ };
+ 
+ typedef struct ps_reg_move_info ps_reg_move_info;
+ DEF_VEC_O (ps_reg_move_info);
+ DEF_VEC_ALLOC_O (ps_reg_move_info, heap);
+ 
  /* Holds the partial schedule as an array of II rows.  Each entry of the
     array points to a linked list of PS_INSNs, which represents the
     instructions that are scheduled for that row.  */
*************** struct partial_schedule
*** 148,153 ****
--- 176,185 ----
    /* rows[i] points to linked list of insns scheduled in row i (0<=i<ii).  */
    ps_insn_ptr *rows;
  
+   /* All the moves added for this partial schedule.  Index X has
+      a ps_insn id of X + g->num_nodes.  */
+   VEC (ps_reg_move_info, heap) *reg_moves;
+ 
    /*  rows_length[i] holds the number of instructions in the row.
        It is used only (as an optimization) to back off quickly from
        trying to schedule a node in a full row; that is, to avoid running
*************** static bool remove_node_from_ps (partial
*** 201,207 ****
  
  #define NODE_ASAP(node) ((node)->aux.count)
  
! #define SCHED_PARAMS(x) (&node_sched_params[x])
  #define SCHED_TIME(x) (SCHED_PARAMS (x)->time)
  #define SCHED_FIRST_REG_MOVE(x) (SCHED_PARAMS (x)->first_reg_move)
  #define SCHED_NREG_MOVES(x) (SCHED_PARAMS (x)->nreg_moves)
--- 233,239 ----
  
  #define NODE_ASAP(node) ((node)->aux.count)
  
! #define SCHED_PARAMS(x) VEC_index (node_sched_params, node_sched_param_vec, x)
  #define SCHED_TIME(x) (SCHED_PARAMS (x)->time)
  #define SCHED_FIRST_REG_MOVE(x) (SCHED_PARAMS (x)->first_reg_move)
  #define SCHED_NREG_MOVES(x) (SCHED_PARAMS (x)->nreg_moves)
*************** typedef struct node_sched_params
*** 214,227 ****
  {
    int time;	/* The absolute scheduling cycle (time >= asap).  */
  
!   /* The following field (first_reg_move) is a pointer to the first
       register-move instruction added to handle the modulo-variable-expansion
       of the register defined by this node.  This register-move copies the
       original register defined by the node.  */
!   rtx first_reg_move;
  
!   /* The number of register-move instructions added, immediately preceding
!      first_reg_move.  */
    int nreg_moves;
  
    int row;    /* Holds time % ii.  */
--- 246,258 ----
  {
    int time;	/* The absolute scheduling cycle (time >= asap).  */
  
!   /* The following field (first_reg_move) is the ps_insn id of the first
       register-move instruction added to handle the modulo-variable-expansion
       of the register defined by this node.  This register-move copies the
       original register defined by the node.  */
!   int first_reg_move;
  
!   /* The number of register-move instructions added.  */
    int nreg_moves;
  
    int row;    /* Holds time % ii.  */
*************** typedef struct node_sched_params
*** 232,237 ****
--- 263,271 ----
    int column;
  } *node_sched_params_ptr;
  
+ typedef struct node_sched_params node_sched_params;
+ DEF_VEC_O (node_sched_params);
+ DEF_VEC_ALLOC_O (node_sched_params, heap);
  
  /* The following three functions are copied from the current scheduler
     code in order to use sched_analyze() for computing the dependencies.
*************** static struct haifa_sched_info sms_sched
*** 280,299 ****
    0
  };
  
  /* Return the rtl instruction that is being scheduled by partial schedule
     instruction ID, which belongs to schedule PS.  */
  static rtx
  ps_rtl_insn (partial_schedule_ptr ps, int id)
  {
!   return ps->g->nodes[id].insn;
  }
  
! /* Return the first instruction in the original (unscheduled) loop that
!    was associated with ps_rtl_insn (PS, ID).  If the instruction had
!    some notes before it, this is the first of those notes.  */
  static rtx
  ps_first_note (partial_schedule_ptr ps, int id)
  {
    return ps->g->nodes[id].first_note;
  }
  
--- 314,348 ----
    0
  };
  
+ /* Partial schedule instruction ID in PS is a register move.  Return
+    information about it.  */
+ static struct ps_reg_move_info *
+ ps_reg_move (partial_schedule_ptr ps, int id)
+ {
+   gcc_checking_assert (id >= ps->g->num_nodes);
+   return VEC_index (ps_reg_move_info, ps->reg_moves, id - ps->g->num_nodes);
+ }
+ 
  /* Return the rtl instruction that is being scheduled by partial schedule
     instruction ID, which belongs to schedule PS.  */
  static rtx
  ps_rtl_insn (partial_schedule_ptr ps, int id)
  {
!   if (id < ps->g->num_nodes)
!     return ps->g->nodes[id].insn;
!   else
!     return ps_reg_move (ps, id)->insn;
  }
  
! /* Partial schedule instruction ID, which belongs to PS, occured in
!    the original (unscheduled) loop.  Return the first instruction
!    in the loop that was associated with ps_rtl_insn (PS, ID).
!    If the instruction had some notes before it, this is the first
!    of those notes.  */
  static rtx
  ps_first_note (partial_schedule_ptr ps, int id)
  {
+   gcc_assert (id < ps->g->num_nodes);
    return ps->g->nodes[id].first_note;
  }
  
*************** res_MII (ddg_ptr g)
*** 397,414 ****
  }
  
  
! /* Points to the array that contains the sched data for each node.  */
! static node_sched_params_ptr node_sched_params;
  
  /* Allocate sched_params for each node and initialize it.  */
  static void
  set_node_sched_params (ddg_ptr g)
  {
!   node_sched_params = XCNEWVEC (struct node_sched_params, g->num_nodes);
  }
  
  static void
! print_node_sched_params (FILE *file, int num_nodes, ddg_ptr g)
  {
    int i;
  
--- 446,465 ----
  }
  
  
! /* A vector that contains the sched data for each ps_insn.  */
! static VEC (node_sched_params, heap) *node_sched_param_vec;
  
  /* Allocate sched_params for each node and initialize it.  */
  static void
  set_node_sched_params (ddg_ptr g)
  {
!   VEC_truncate (node_sched_params, node_sched_param_vec, 0);
!   VEC_safe_grow_cleared (node_sched_params, heap,
! 			 node_sched_param_vec, g->num_nodes);
  }
  
  static void
! print_node_sched_params (FILE *file, int num_nodes, partial_schedule_ptr ps)
  {
    int i;
  
*************** print_node_sched_params (FILE *file, int
*** 417,435 ****
    for (i = 0; i < num_nodes; i++)
      {
        node_sched_params_ptr nsp = SCHED_PARAMS (i);
-       rtx reg_move = nsp->first_reg_move;
        int j;
  
        fprintf (file, "Node = %d; INSN = %d\n", i,
! 	       (INSN_UID (g->nodes[i].insn)));
!       fprintf (file, " asap = %d:\n", NODE_ASAP (&g->nodes[i]));
        fprintf (file, " time = %d:\n", nsp->time);
        fprintf (file, " nreg_moves = %d:\n", nsp->nreg_moves);
        for (j = 0; j < nsp->nreg_moves; j++)
  	{
  	  fprintf (file, " reg_move = ");
! 	  print_rtl_single (file, reg_move);
! 	  reg_move = PREV_INSN (reg_move);
  	}
      }
  }
--- 468,486 ----
    for (i = 0; i < num_nodes; i++)
      {
        node_sched_params_ptr nsp = SCHED_PARAMS (i);
        int j;
  
        fprintf (file, "Node = %d; INSN = %d\n", i,
! 	       INSN_UID (ps_rtl_insn (ps, i)));
!       fprintf (file, " asap = %d:\n", NODE_ASAP (&ps->g->nodes[i]));
        fprintf (file, " time = %d:\n", nsp->time);
        fprintf (file, " nreg_moves = %d:\n", nsp->nreg_moves);
        for (j = 0; j < nsp->nreg_moves; j++)
  	{
+ 	  ps_reg_move_info *move = ps_reg_move (ps, nsp->first_reg_move + j);
+ 
  	  fprintf (file, " reg_move = ");
! 	  print_rtl_single (file, move->insn);
  	}
      }
  }
*************** print_node_sched_params (FILE *file, int
*** 445,452 ****
     nreg_moves = ----------------------------------- + 1 - {   dependence.
                              ii                          { 1 if not.
  */
! static void
! generate_reg_moves (partial_schedule_ptr ps, bool rescan)
  {
    ddg_ptr g = ps->g;
    int ii = ps->ii;
--- 496,503 ----
     nreg_moves = ----------------------------------- + 1 - {   dependence.
                              ii                          { 1 if not.
  */
! static bool
! schedule_reg_moves (partial_schedule_ptr ps)
  {
    ddg_ptr g = ps->g;
    int ii = ps->ii;
*************** generate_reg_moves (partial_schedule_ptr
*** 457,465 ****
        ddg_node_ptr u = &g->nodes[i];
        ddg_edge_ptr e;
        int nreg_moves = 0, i_reg_move;
-       sbitmap *uses_of_defs;
-       rtx last_reg_move;
        rtx prev_reg, old_reg;
  
        /* Compute the number of reg_moves needed for u, by looking at life
  	 ranges started at u (excluding self-loops).  */
--- 508,515 ----
        ddg_node_ptr u = &g->nodes[i];
        ddg_edge_ptr e;
        int nreg_moves = 0, i_reg_move;
        rtx prev_reg, old_reg;
+       int first_move;
  
        /* Compute the number of reg_moves needed for u, by looking at life
  	 ranges started at u (excluding self-loops).  */
*************** generate_reg_moves (partial_schedule_ptr
*** 485,496 ****
        if (nreg_moves == 0)
  	continue;
  
        /* Every use of the register defined by node may require a different
  	 copy of this register, depending on the time the use is scheduled.
! 	 Set a bitmap vector, telling which nodes use each copy of this
! 	 register.  */
!       uses_of_defs = sbitmap_vector_alloc (nreg_moves, g->num_nodes);
!       sbitmap_vector_zero (uses_of_defs, nreg_moves);
        for (e = u->out; e; e = e->next_out)
  	if (e->type == TRUE_DEP && e->dest != e->src)
  	  {
--- 535,569 ----
        if (nreg_moves == 0)
  	continue;
  
+       /* Create NREG_MOVES register moves.  */
+       first_move = VEC_length (ps_reg_move_info, ps->reg_moves);
+       VEC_safe_grow_cleared (ps_reg_move_info, heap, ps->reg_moves,
+ 			     first_move + nreg_moves);
+ 
+       /* Record the moves associated with this node.  */
+       first_move += ps->g->num_nodes;
+       SCHED_FIRST_REG_MOVE (i) = first_move;
+       SCHED_NREG_MOVES (i) = nreg_moves;
+ 
+       /* Generate each move.  */
+       old_reg = prev_reg = SET_DEST (single_set (u->insn));
+       for (i_reg_move = 0; i_reg_move < nreg_moves; i_reg_move++)
+ 	{
+ 	  ps_reg_move_info *move = ps_reg_move (ps, first_move + i_reg_move);
+ 
+ 	  move->def = i;
+ 	  move->uses = sbitmap_alloc (g->num_nodes);
+ 	  move->old_reg = old_reg;
+ 	  move->new_reg = gen_reg_rtx (GET_MODE (prev_reg));
+ 	  move->insn = gen_move_insn (move->new_reg, copy_rtx (prev_reg));
+ 	  sbitmap_zero (move->uses);
+ 
+ 	  prev_reg = move->new_reg;
+ 	}
+ 
        /* Every use of the register defined by node may require a different
  	 copy of this register, depending on the time the use is scheduled.
! 	 Record which uses require which move results.  */
        for (e = u->out; e; e = e->next_out)
  	if (e->type == TRUE_DEP && e->dest != e->src)
  	  {
*************** generate_reg_moves (partial_schedule_ptr
*** 506,545 ****
  	      dest_copy--;
  
  	    if (dest_copy)
! 	      SET_BIT (uses_of_defs[dest_copy - 1], e->dest->cuid);
! 	  }
! 
!       /* Now generate the reg_moves, attaching relevant uses to them.  */
!       SCHED_NREG_MOVES (i) = nreg_moves;
!       old_reg = prev_reg = copy_rtx (SET_DEST (single_set (u->insn)));
!       /* Insert the reg-moves right before the notes which precede
!          the insn they relates to.  */
!       last_reg_move = u->first_note;
! 
!       for (i_reg_move = 0; i_reg_move < nreg_moves; i_reg_move++)
! 	{
! 	  unsigned int i_use = 0;
! 	  rtx new_reg = gen_reg_rtx (GET_MODE (prev_reg));
! 	  rtx reg_move = gen_move_insn (new_reg, prev_reg);
! 	  sbitmap_iterator sbi;
  
! 	  add_insn_before (reg_move, last_reg_move, NULL);
! 	  last_reg_move = reg_move;
  
! 	  if (!SCHED_FIRST_REG_MOVE (i))
! 	    SCHED_FIRST_REG_MOVE (i) = reg_move;
  
! 	  EXECUTE_IF_SET_IN_SBITMAP (uses_of_defs[i_reg_move], 0, i_use, sbi)
! 	    {
! 	      replace_rtx (g->nodes[i_use].insn, old_reg, new_reg);
! 	      if (rescan)
! 		df_insn_rescan (g->nodes[i_use].insn);
! 	    }
  
! 	  prev_reg = new_reg;
  	}
-       sbitmap_vector_free (uses_of_defs);
      }
  }
  
  /* Update the sched_params (time, row and stage) for node U using the II,
--- 579,617 ----
  	      dest_copy--;
  
  	    if (dest_copy)
! 	      {
! 		ps_reg_move_info *move;
  
! 		move = ps_reg_move (ps, first_move + dest_copy - 1);
! 		SET_BIT (move->uses, e->dest->cuid);
! 	      }
! 	  }
!     }
!   return true;
! }
  
! /* Emit the moves associatied with PS.  Apply the substitutions
!    associated with them.  */
! static void
! apply_reg_moves (partial_schedule_ptr ps)
! {
!   ps_reg_move_info *move;
!   int i;
  
!   FOR_EACH_VEC_ELT (ps_reg_move_info, ps->reg_moves, i, move)
!     {
!       unsigned int i_use;
!       sbitmap_iterator sbi;
  
!       EXECUTE_IF_SET_IN_SBITMAP (move->uses, 0, i_use, sbi)
! 	{
! 	  replace_rtx (ps->g->nodes[i_use].insn, move->old_reg, move->new_reg);
! 	  df_insn_rescan (ps->g->nodes[i_use].insn);
  	}
      }
+ 
+   FOR_EACH_VEC_ELT_REVERSE (ps_reg_move_info, ps->reg_moves, i, move)
+     add_insn_before (move->insn, ps_first_note (ps, move->def), NULL);
  }
  
  /* Update the sched_params (time, row and stage) for node U using the II,
*************** duplicate_insns_of_cycles (partial_sched
*** 856,863 ****
      for (ps_ij = ps->rows[row]; ps_ij; ps_ij = ps_ij->next_in_row)
        {
  	int u = ps_ij->id;
! 	int j, i_reg_moves;
! 	rtx reg_move = NULL_RTX;
  	rtx u_insn;
  
          /* Do not duplicate any insn which refers to count_reg as it
--- 928,934 ----
      for (ps_ij = ps->rows[row]; ps_ij; ps_ij = ps_ij->next_in_row)
        {
  	int u = ps_ij->id;
! 	int j, i_reg_moves, i_reg_move;
  	rtx u_insn;
  
          /* Do not duplicate any insn which refers to count_reg as it
*************** duplicate_insns_of_cycles (partial_sched
*** 881,892 ****
  	    i_reg_moves = MIN (i_reg_moves, SCHED_NREG_MOVES (u));
  
  	    /* The reg_moves start from the *first* reg_move backwards.  */
! 	    if (i_reg_moves)
! 	      {
! 		reg_move = SCHED_FIRST_REG_MOVE (u);
! 		for (j = 1; j < i_reg_moves; j++)
! 		  reg_move = PREV_INSN (reg_move);
! 	      }
  	  }
  	else /* It's for the epilog.  */
  	  {
--- 952,958 ----
  	    i_reg_moves = MIN (i_reg_moves, SCHED_NREG_MOVES (u));
  
  	    /* The reg_moves start from the *first* reg_move backwards.  */
! 	    i_reg_move = SCHED_FIRST_REG_MOVE (u) + (i_reg_moves - 1);
  	  }
  	else /* It's for the epilog.  */
  	  {
*************** duplicate_insns_of_cycles (partial_sched
*** 900,915 ****
  	    i_reg_moves = MIN (i_reg_moves, SCHED_NREG_MOVES (u));
  
  	    /* The reg_moves start from the *last* reg_move forwards.  */
! 	    if (i_reg_moves)
! 	      {
! 		reg_move = SCHED_FIRST_REG_MOVE (u);
! 		for (j = 1; j < SCHED_NREG_MOVES (u); j++)
! 		  reg_move = PREV_INSN (reg_move);
! 	      }
  	  }
  
! 	for (j = 0; j < i_reg_moves; j++, reg_move = NEXT_INSN (reg_move))
! 	  emit_insn (copy_rtx (PATTERN (reg_move)));
  	if (SCHED_STAGE (u) >= from_stage
  	    && SCHED_STAGE (u) <= to_stage)
  	  duplicate_insn_chain (ps_first_note (ps, u), u_insn);
--- 966,980 ----
  	    i_reg_moves = MIN (i_reg_moves, SCHED_NREG_MOVES (u));
  
  	    /* The reg_moves start from the *last* reg_move forwards.  */
! 	    i_reg_move = SCHED_FIRST_REG_MOVE (u) + (SCHED_NREG_MOVES (u) - 1);
  	  }
  
! 	for (j = 0; j < i_reg_moves; j++)
! 	  {
! 	    ps_reg_move_info *move = ps_reg_move (ps, i_reg_move - j);
! 
! 	    emit_insn (copy_rtx (PATTERN (move->insn)));
! 	  }
  	if (SCHED_STAGE (u) >= from_stage
  	    && SCHED_STAGE (u) <= to_stage)
  	  duplicate_insn_chain (ps_first_note (ps, u), u_insn);
*************** sms_schedule (void)
*** 1300,1308 ****
        rtx head, tail;
        rtx count_reg, count_init;
        int mii, rec_mii;
!       unsigned stage_count = 0;
        HOST_WIDEST_INT loop_count = 0;
!       bool opt_sc_p = false;
  
        if (! (g = g_arr[loop->num]))
          continue;
--- 1365,1373 ----
        rtx head, tail;
        rtx count_reg, count_init;
        int mii, rec_mii;
!       unsigned stage_count;
        HOST_WIDEST_INT loop_count = 0;
!       bool opt_sc_p;
  
        if (! (g = g_arr[loop->num]))
          continue;
*************** sms_schedule (void)
*** 1379,1432 ****
  	fprintf (dump_file, "SMS iis %d %d %d (rec_mii, mii, maxii)\n",
  		 rec_mii, mii, maxii);
  
!       set_node_sched_params (g);
! 
!       ps = sms_schedule_by_order (g, mii, maxii, node_order);
!       
!       if (ps)
  	{
! 	  /* Try to achieve optimized SC by normalizing the partial
! 	     schedule (having the cycles start from cycle zero).
! 	     The branch location must be placed in row ii-1 in the
! 	     final scheduling.	If failed, shift all instructions to
! 	     position the branch in row ii-1.  */
! 	  opt_sc_p = optimize_sc (ps, g);
! 	  if (opt_sc_p)
! 	    stage_count = calculate_stage_count (ps, 0);
! 	  else
  	    {
! 	      /* Bring the branch to cycle ii-1.  */
! 	      int amount = SCHED_TIME (g->closing_branch->cuid) - (ps->ii - 1);
! 	      
! 	      if (dump_file)
! 		fprintf (dump_file, "SMS schedule branch at cycle ii-1\n");
! 	      
! 	      stage_count = calculate_stage_count (ps, amount);
  	    }
! 	  
! 	  gcc_assert (stage_count >= 1);
! 	  PS_STAGE_COUNT (ps) = stage_count;
! 	}
!       
!       /* The default value of PARAM_SMS_MIN_SC is 2 as stage count of
! 	 1 means that there is no interleaving between iterations thus
! 	 we let the scheduling passes do the job in this case.  */
!       if (stage_count < (unsigned) PARAM_VALUE (PARAM_SMS_MIN_SC)
! 	  || (count_init && (loop_count <= stage_count))
! 	  || (flag_branch_probabilities && (trip_count <= stage_count)))
! 	{
! 	  if (dump_file)
  	    {
! 	      fprintf (dump_file, "SMS failed... \n");
! 	      fprintf (dump_file, "SMS sched-failed (stage-count=%d, loop-count=", stage_count);
! 	      fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, loop_count);
! 	      fprintf (dump_file, ", trip-count=");
! 	      fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, trip_count);
! 	      fprintf (dump_file, ")\n");
  	    }
! 	}
!       else
! 	{
            if (!opt_sc_p)
              {
  	      /* Rotate the partial schedule to have the branch in row ii-1.  */
--- 1444,1503 ----
  	fprintf (dump_file, "SMS iis %d %d %d (rec_mii, mii, maxii)\n",
  		 rec_mii, mii, maxii);
  
!       for (;;)
  	{
! 	  set_node_sched_params (g);
! 
! 	  stage_count = 0;
! 	  opt_sc_p = false;
! 	  ps = sms_schedule_by_order (g, mii, maxii, node_order);
! 
! 	  if (ps)
  	    {
! 	      /* Try to achieve optimized SC by normalizing the partial
! 		 schedule (having the cycles start from cycle zero).
! 		 The branch location must be placed in row ii-1 in the
! 		 final scheduling.	If failed, shift all instructions to
! 		 position the branch in row ii-1.  */
! 	      opt_sc_p = optimize_sc (ps, g);
! 	      if (opt_sc_p)
! 		stage_count = calculate_stage_count (ps, 0);
! 	      else
! 		{
! 		  /* Bring the branch to cycle ii-1.  */
! 		  int amount = (SCHED_TIME (g->closing_branch->cuid)
! 				- (ps->ii - 1));
! 
! 		  if (dump_file)
! 		    fprintf (dump_file, "SMS schedule branch at cycle ii-1\n");
! 
! 		  stage_count = calculate_stage_count (ps, amount);
! 		}
! 
! 	      gcc_assert (stage_count >= 1);
! 	      PS_STAGE_COUNT (ps) = stage_count;
  	    }
! 
! 	  /* The default value of PARAM_SMS_MIN_SC is 2 as stage count of
! 	     1 means that there is no interleaving between iterations thus
! 	     we let the scheduling passes do the job in this case.  */
! 	  if (stage_count < (unsigned) PARAM_VALUE (PARAM_SMS_MIN_SC)
! 	      || (count_init && (loop_count <= stage_count))
! 	      || (flag_branch_probabilities && (trip_count <= stage_count)))
  	    {
! 	      if (dump_file)
! 		{
! 		  fprintf (dump_file, "SMS failed... \n");
! 		  fprintf (dump_file, "SMS sched-failed (stage-count=%d,"
! 			   " loop-count=", stage_count);
! 		  fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, loop_count);
! 		  fprintf (dump_file, ", trip-count=");
! 		  fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, trip_count);
! 		  fprintf (dump_file, ")\n");
! 		}
! 	      break;
  	    }
! 
            if (!opt_sc_p)
              {
  	      /* Rotate the partial schedule to have the branch in row ii-1.  */
*************** sms_schedule (void)
*** 1438,1443 ****
--- 1509,1521 ----
  	  
  	  set_columns_for_ps (ps);
  
+ 	  if (!schedule_reg_moves (ps))
+ 	    {
+ 	      mii = ps->ii + 1;
+ 	      free_partial_schedule (ps);
+ 	      continue;
+ 	    }
+ 
  	  canon_loop (loop);
  
            if (dump_file)
*************** sms_schedule (void)
*** 1476,1490 ****
  	  /* The life-info is not valid any more.  */
  	  df_set_bb_dirty (g->bb);
  
! 	  generate_reg_moves (ps, true);
  	  if (dump_file)
! 	    print_node_sched_params (dump_file, g->num_nodes, g);
  	  /* Generate prolog and epilog.  */
            generate_prolog_epilog (ps, loop, count_reg, count_init);
  	}
  
        free_partial_schedule (ps);
!       free (node_sched_params);
        free (node_order);
        free_ddg (g);
      }
--- 1554,1569 ----
  	  /* The life-info is not valid any more.  */
  	  df_set_bb_dirty (g->bb);
  
! 	  apply_reg_moves (ps);
  	  if (dump_file)
! 	    print_node_sched_params (dump_file, g->num_nodes, ps);
  	  /* Generate prolog and epilog.  */
            generate_prolog_epilog (ps, loop, count_reg, count_init);
+ 	  break;
  	}
  
        free_partial_schedule (ps);
!       VEC_free (node_sched_params, heap, node_sched_param_vec);
        free (node_order);
        free_ddg (g);
      }
*************** create_partial_schedule (int ii, ddg_ptr
*** 2571,2576 ****
--- 2650,2656 ----
    partial_schedule_ptr ps = XNEW (struct partial_schedule);
    ps->rows = (ps_insn_ptr *) xcalloc (ii, sizeof (ps_insn_ptr));
    ps->rows_length = (int *) xcalloc (ii, sizeof (int));
+   ps->reg_moves = NULL;
    ps->ii = ii;
    ps->history = history;
    ps->min_cycle = INT_MAX;
*************** free_ps_insns (partial_schedule_ptr ps)
*** 2605,2612 ****
--- 2685,2700 ----
  static void
  free_partial_schedule (partial_schedule_ptr ps)
  {
+   ps_reg_move_info *move;
+   unsigned int i;
+ 
    if (!ps)
      return;
+ 
+   FOR_EACH_VEC_ELT (ps_reg_move_info, ps->reg_moves, i, move)
+     sbitmap_free (move->uses);
+   VEC_free (ps_reg_move_info, heap, ps->reg_moves);
+ 
    free_ps_insns (ps);
    free (ps->rows);
    free (ps->rows_length);


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