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]

Regclass propagation patch 2



Hi

Here is the propagation patch. It makes regclass to use as many passes as
necessary to propagate all the changes. Effect can be seen for example when
compiling:

double n=1;
main()
{
    double a=1,b,c;
    asm("%0 %1":"=f,r"(b):"f,r"(a));
    asm("%0 %1":"=f,r"(c):"f,r"(b));
    asm("%0"::"r"(c));
}

Where original the a got FLOAT_INT_REGS preferrence, but now it gets
GENERAL_REGS. Soon I would like to follow up this patch by making local
alloc and global alloc prpagating the changes back into prefferences, thats
why I am taking quite a lot of care here to optimize the handling of insns.

Basically I just set up bitmaps of all insns that may change preferrences if
given register changes the prefclass and then do propagation only on those
insns using this info.

Result is that regclass is still linear even in the worst case. The amout of
memory required is also linear in program size because of sparse bitmaps used.
Interestingly enought I've even measured small speedups in optimizing
compilation maybe because notes and similar insns are not scanned anymore in
the second pass.

Note that I've removed the two-address insn optimization. I've sent
patch for this previously explaining why I believe it can never match
with sane machine description. If it is still important, I can send
the patch to move it into regmove, where it belongs.

Sat Jan  1 17:51:10 CET 2000  Jan Hubicka  <hubicka@freesoft.cz>
	* regclass.c: Include bitmap.h
	(old_reg_pref, old_reg_pref_buffer, insns_mentioning_reg, changed_costs,
	 insn_rec): New global variables.
	(record_operand_costs): Initialize insns_mentioning_reg.
	(update_costs): New function.
	(scan_one_insn): Take insn_no as parameter, don't verify that
	insn is relevant for reg_class; remove two address insn optimization.
	(calc_reg_preferrences): Break out from...
	(regclass): Here; initialize the bitmaps and insn_rec, do the propagation,
	handle old_reg_pref_buffer updating.
	(allocate_reg_info): Allocate old_reg_pref_buffer.
	(free_reg_info): Free old_reg_pref_buffer.

*** regclass.c.pref1	Sat Jan  1 15:55:46 2000
--- regclass.c	Sat Jan  1 17:52:54 2000
*************** Boston, MA 02111-1307, USA.  */
*** 39,44 ****
--- 39,45 ----
  #include "toplev.h"
  #include "output.h"
  #include "ggc.h"
+ #include "bitmap.h"
  
  #ifndef REGISTER_MOVE_COST
  #define REGISTER_MOVE_COST(x, y) 2
*************** static struct costs init_cost;
*** 706,724 ****
  /* Record preferrences of each pseudo.
     This is available after `regclass' is run.  */
  
! static struct reg_pref *reg_pref;
  
  /* Allocated buffers for reg_pref. */
  
! static struct reg_pref *reg_pref_buffer;
  
  /* Account for the fact that insns within a loop are executed very commonly,
     but don't keep doing this as loops go too deep.  */
  
  static int loop_cost;
  
! static rtx scan_one_insn	PROTO((rtx, int));
! static void record_operand_costs PROTO((rtx, struct costs *, struct reg_pref *));
  static void dump_regclass	PROTO((FILE *));
  static void record_reg_classes	PROTO((int, int, rtx *, enum machine_mode *,
  				       char *, const char **, rtx,
--- 707,742 ----
  /* Record preferrences of each pseudo.
     This is available after `regclass' is run.  */
  
! static struct reg_pref *reg_pref, *old_reg_pref;
  
  /* Allocated buffers for reg_pref. */
  
! static struct reg_pref *reg_pref_buffer, *old_reg_pref_buffer;
  
  /* Account for the fact that insns within a loop are executed very commonly,
     but don't keep doing this as loops go too deep.  */
  
  static int loop_cost;
  
! /* Indexed by REGNO.  Keep track of insns mentioning given register in the operands
!    (not addresses).  Cost of the operands might change when prefferencing of REG is
!    changed, so we use it to recalculate only insns mentioning given reg.  */
! bitmap *insns_mentioning_reg;
! 
! /* Set for REGNOS where costs was changed by update_costs.  */
! bitmap changed_costs;
! 
! /* Every insn relevant to the register prefferencing is stored in this array.
!    We use indexes to this array in insns_mentioning_reg.  */
! struct insn_rec 
! {
!   rtx insn;
!   int loop_cost;
! } *insn_rec;
! 
! static rtx scan_one_insn	PROTO((int, int));
! static rtx update_costs		PROTO((int));
! static void record_operand_costs PROTO((int, struct costs *, struct reg_pref *, int));
  static void dump_regclass	PROTO((FILE *));
  static void record_reg_classes	PROTO((int, int, rtx *, enum machine_mode *,
  				       char *, const char **, rtx,
*************** static void record_reg_classes	PROTO((in
*** 726,731 ****
--- 744,750 ----
  static int copy_cost		PROTO((rtx, enum machine_mode, 
  				       enum reg_class, int));
  static void record_address_regs	PROTO((rtx, enum reg_class, int));
+ static int calc_reg_preferrences PROTO((int, FILE *));
  #ifdef FORBIDDEN_INC_DEC_CLASSES
  static int auto_inc_dec_reg_p	PROTO((rtx, enum machine_mode));
  #endif
*************** dump_regclass (dump)
*** 795,808 ****
  }
  
  
! /* Calculate the costs of insn operands.  */
  
  static void
! record_operand_costs (insn, op_costs, reg_pref)
!      rtx insn;
       struct costs *op_costs;
       struct reg_pref *reg_pref;
  {
    const char *constraints[MAX_RECOG_OPERANDS];
    enum machine_mode modes[MAX_RECOG_OPERANDS];
    char subreg_changes_size[MAX_RECOG_OPERANDS];
--- 814,830 ----
  }
  
  
! /* Calculate the costs of insn operands.
!    Initialize the insns_mentioning_reg when INIT is set.  */
  
  static void
! record_operand_costs (insn_no, op_costs, reg_pref, init)
!      int insn_no;
       struct costs *op_costs;
       struct reg_pref *reg_pref;
+      int init;
  {
+   rtx insn = insn_rec[insn_no].insn;
    const char *constraints[MAX_RECOG_OPERANDS];
    enum machine_mode modes[MAX_RECOG_OPERANDS];
    char subreg_changes_size[MAX_RECOG_OPERANDS];
*************** record_operand_costs (insn, op_costs, re
*** 867,872 ****
--- 889,911 ----
    record_reg_classes (recog_data.n_alternatives, recog_data.n_operands,
  		      recog_data.operand, modes, subreg_changes_size,
  		      constraints, insn, op_costs, reg_pref);
+ 
+   /* Initialize the insns_mentioning_reg bitmap.  We set only for
+      operands that may change preferrences of other operands mentioned in the
+      insn.  This may happen with multiple alternative operands as well as with
+      operands matched by others.  We don't handle the second case correctly
+      yet so for now we insert only operands of multiple alternative insns.  */
+ 
+   if (init && recog_data.n_alternatives)
+     {
+       for (i = 0; i < recog_data.n_operands; i++)
+ 	{
+ 	  if (REG_P (recog_data.operand[i])
+ 	      && REGNO (recog_data.operand[i]) >= FIRST_PSEUDO_REGISTER)
+ 	    bitmap_set_bit (insns_mentioning_reg[REGNO (recog_data.operand[i])],
+ 			    insn_no);
+ 	}
+     }
  }
  
  /* Subroutine of regclass, processes one insn INSN.  Scan it and record each
*************** record_operand_costs (insn, op_costs, re
*** 877,903 ****
     there.  */
  
  static rtx
! scan_one_insn (insn, pass)
!      rtx insn;
       int pass;
  {
!   enum rtx_code code = GET_CODE (insn);
!   enum rtx_code pat_code;
    rtx set, note;
    int i, j;
  
    struct costs op_costs[MAX_RECOG_OPERANDS];
  
-   if (GET_RTX_CLASS (code) != 'i')
-     return insn;
- 
-   pat_code = GET_CODE (PATTERN (insn));
-   if (pat_code == USE
-       || pat_code == CLOBBER
-       || pat_code == ADDR_VEC
-       || pat_code == ADDR_DIFF_VEC)
-     return insn;
- 
    set = single_set (insn);
    extract_insn (insn);
  
--- 916,931 ----
     there.  */
  
  static rtx
! scan_one_insn (insn_no, pass)
!      int insn_no;
       int pass;
  {
!   rtx insn = insn_rec[insn_no].insn;
    rtx set, note;
    int i, j;
  
    struct costs op_costs[MAX_RECOG_OPERANDS];
  
    set = single_set (insn);
    extract_insn (insn);
  
*************** scan_one_insn (insn, pass)
*** 918,978 ****
  	    * loop_cost);
      }
  
!   /* Improve handling of two-address insns such as
!      (set X (ashift CONST Y)) where CONST must be made to
!      match X. Change it into two insns: (set X CONST)
!      (set X (ashift X Y)).  If we left this for reloading, it
!      would probably get three insns because X and Y might go
!      in the same place. This prevents X and Y from receiving
!      the same hard reg.
! 
!      We can only do this if the modes of operands 0 and 1
!      (which might not be the same) are tieable and we only need
!      do this during our first pass.  */
! 
!   if (pass == 0 && optimize
!       && recog_data.n_operands >= 3
!       && recog_data.constraints[1][0] == '0'
!       && recog_data.constraints[1][1] == 0
!       && CONSTANT_P (recog_data.operand[1])
!       && ! rtx_equal_p (recog_data.operand[0], recog_data.operand[1])
!       && ! rtx_equal_p (recog_data.operand[0], recog_data.operand[2])
!       && GET_CODE (recog_data.operand[0]) == REG
!       && MODES_TIEABLE_P (GET_MODE (recog_data.operand[0]),
! 			  recog_data.operand_mode[1]))
!     {
!       rtx previnsn = prev_real_insn (insn);
!       rtx dest
! 	= gen_lowpart (recog_data.operand_mode[1],
! 		       recog_data.operand[0]);
!       rtx newinsn
! 	= emit_insn_before (gen_move_insn (dest, recog_data.operand[1]), insn);
! 
!       /* If this insn was the start of a basic block,
! 	 include the new insn in that block.
! 	 We need not check for code_label here;
! 	 while a basic block can start with a code_label,
! 	 INSN could not be at the beginning of that block.  */
!       if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN)
! 	{
! 	  int b;
! 	  for (b = 0; b < n_basic_blocks; b++)
! 	    if (insn == BLOCK_HEAD (b))
! 	      BLOCK_HEAD (b) = newinsn;
! 	}
! 
!       /* This makes one more setting of new insns's dest.  */
!       REG_N_SETS (REGNO (recog_data.operand[0]))++;
! 
!       *recog_data.operand_loc[1] = recog_data.operand[0];
!       for (i = recog_data.n_dups - 1; i >= 0; i--)
! 	if (recog_data.dup_num[i] == 1)
! 	  *recog_data.dup_loc[i] = recog_data.operand[0];
! 
!       return PREV_INSN (newinsn);
!     }
! 
!   record_operand_costs(insn, op_costs, reg_pref);
  
    /* Now add the cost for each operand to the total costs for
       its register.  */
--- 946,952 ----
  	    * loop_cost);
      }
  
!   record_operand_costs(insn_no, op_costs, reg_pref, pass == 1);
  
    /* Now add the cost for each operand to the total costs for
       its register.  */
*************** scan_one_insn (insn, pass)
*** 992,997 ****
--- 966,1093 ----
    return insn;
  }
  
+ /* Update the costs contributed by this insn after old_reg_pref was changed
+    to reg_pref.  We do this by calculating the old prices and new prices and
+    adding the delta.  Other approach can be to save the costs calculated
+    earlier, but it would require extreme amounts of memory.  */
+ static rtx
+ update_costs (insn_no)
+      int insn_no;
+ {
+   rtx insn = insn_rec[insn_no].insn;
+   int i, j;
+   struct costs op_costs[MAX_RECOG_OPERANDS];
+   struct costs old_op_costs[MAX_RECOG_OPERANDS];
+ 
+   extract_insn (insn);
+   record_operand_costs(insn_no, op_costs, reg_pref, 0);
+   record_operand_costs(insn_no, old_op_costs, old_reg_pref, 0);
+ 
+   for (i = 0; i < recog_data.n_operands; i++)
+     if (GET_CODE (recog_data.operand[i]) == REG
+ 	&& REGNO (recog_data.operand[i]) >= FIRST_PSEUDO_REGISTER)
+       {
+ 	int regno = REGNO (recog_data.operand[i]);
+ 	struct costs *p = &costs[regno], *q = &op_costs[i];
+ 	struct costs *q_old = &old_op_costs[i];
+ 	int changed = 0;
+ 
+ 	if (q->mem_cost != q_old->mem_cost)
+ 	  p->mem_cost += (q->mem_cost - q_old->mem_cost) * loop_cost,
+ 	  changed = 1;
+ 	for (j = 0; j < N_REG_CLASSES; j++)
+ 	  if (q->cost[j] != q_old->cost[j])
+ 	    p->cost[j] += (q->cost[j] - q_old->mem_cost) * loop_cost,
+ 	    changed = 1;
+ 	    
+ 	if (changed)
+ 	  bitmap_set_bit (changed_costs, regno);
+       }
+   return insn;
+ }
+ 
+ /* Caluclate the preferred and alternative class for register number I.  */
+ static int
+ calc_reg_preferrences (i, dump)
+      int i;
+      FILE *dump;
+ {
+   register int best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
+   enum reg_class best = ALL_REGS, alt = NO_REGS;
+   /* This is an enum reg_class, but we call it an int
+      to save lots of casts.  */
+   register int class;
+   register struct costs *p = &costs[i];
+   int changed = 0;
+ 
+   if (!REG_N_REFS (i))
+     return 0;
+ 
+   for (class = (int) ALL_REGS - 1; class > 0; class--)
+     {
+       /* Ignore classes that are too small for this operand or
+          invalid for a operand that was auto-incremented.  */
+       if (CLASS_MAX_NREGS (class, PSEUDO_REGNO_MODE (i))
+ 	  > reg_class_size[class]
+ #ifdef FORBIDDEN_INC_DEC_CLASSES
+ 	  || (in_inc_dec[i] && forbidden_inc_dec_class[class])
+ #endif
+ 	)
+ 	;
+       else if (p->cost[class] < best_cost)
+ 	{
+ 	  best_cost = p->cost[class];
+ 	  best = (enum reg_class) class;
+ 	}
+       else if (p->cost[class] == best_cost)
+ 	best = reg_class_subunion[(int) best][class];
+     }
+ 
+   /* Record the alternate register class; i.e., a class for which
+      every register in it is better than using memory.  If adding a
+      class would make a smaller class (i.e., no union of just those
+      classes exists), skip that class.  The major unions of classes
+      should be provided as a register class.  Don't do this if we
+      will be doing it again later.  */
+ 
+   for (class = 0; class < N_REG_CLASSES; class++)
+     if (p->cost[class] < p->mem_cost
+ 	&& (reg_class_size[(int) reg_class_subunion[(int) alt][class]]
+ 	    > reg_class_size[(int) alt])
+ #ifdef FORBIDDEN_INC_DEC_CLASSES
+ 	&& !(in_inc_dec[i] && forbidden_inc_dec_class[class])
+ #endif
+       )
+       alt = reg_class_subunion[(int) alt][class];
+ 
+   /* If we don't add any classes, nothing to try.  */
+   if (alt == best)
+     alt = NO_REGS;
+ 
+   if ((reg_pref[i].prefclass != (int) best || reg_pref[i].altclass != (int) alt))
+     {
+       changed = 1;
+       if (dump)
+ 	{
+ 	  static const char *const reg_class_names[] = REG_CLASS_NAMES;
+ 	  fprintf (dump, "  Register %i", i);
+ 	  if (alt == ALL_REGS || best == ALL_REGS)
+ 	    fprintf (dump, " pref %s\n", reg_class_names[(int) best]);
+ 	  else if (alt == NO_REGS)
+ 	    fprintf (dump, " pref %s or none\n", reg_class_names[(int) best]);
+ 	  else
+ 	    fprintf (dump, " pref %s, else %s\n",
+ 		     reg_class_names[(int) best],
+ 		     reg_class_names[(int) alt]);
+ 	}
+     }
+   /* We cast to (int) because (char) hits bugs in some compilers.  */
+   reg_pref[i].prefclass = (int) best;
+   reg_pref[i].altclass = (int) alt;
+ 
+   return changed;
+ }
+ 
  /* This is a pass of the compiler that scans all instructions
     and calculates the preferred class for each pseudo-register.
     This information can be accessed later by calling `reg_preferred_class'.
*************** regclass (f, nregs, dump)
*** 1005,1016 ****
--- 1101,1168 ----
  {
    register rtx insn;
    register int i;
+   int n_insns;
    int pass;
+   int index;
+   bitmap changed_regs = BITMAP_ALLOCA();
+   bitmap changed_insns = BITMAP_ALLOCA();
  
    init_recog ();
  
    costs = (struct costs *) xmalloc (nregs * sizeof (struct costs));
  
+   if (flag_expensive_optimizations)
+     {
+       /* Allocate bitmaps only.  Initialize them later in pass 1 to
+ 	 avoid unnecesary extracting of insns.  */
+ 
+       insns_mentioning_reg = (bitmap *) xmalloc (nregs * sizeof (bitmap));
+       insn_rec = (struct insn_rec *) xmalloc (get_max_uid () * sizeof (struct insn_rec));
+       changed_costs = BITMAP_ALLOCA();
+ 
+       for (i = FIRST_PSEUDO_REGISTER ; i < nregs ; i++)
+ 	if (REG_N_REFS (i))
+ 	  insns_mentioning_reg[i] = BITMAP_XMALLOC();
+ 
+       n_insns = 0;
+ 
+       /* Scan for insns interesting for regclass and store them
+ 	 into insn_rec array.  */
+       for (index = 0; index < n_basic_blocks; index++)
+        {
+ 	 basic_block bb = BASIC_BLOCK (index);
+ 
+ 	 /* Show that an insn inside a loop is likely to be executed four
+ 	    times more than insns outside a loop.  This is much more aggressive
+ 	    than the assumptions made elsewhere and is being tried as an
+ 	    experiment.  */
+ 
+ 	 loop_cost = 1 << (2 * MIN (bb->loop_depth - 1, 5));
+ 
+ 	 for (insn = bb->head; ; insn = NEXT_INSN (insn))
+ 	   {
+ 	      register enum rtx_code code = GET_CODE (insn);
+ 	      register enum rtx_code pat_code;
+ 
+ 	      if (GET_RTX_CLASS (code) == 'i')
+ 		{
+ 		  pat_code = GET_CODE (PATTERN (insn));
+ 		  if (pat_code != USE
+ 		      && pat_code != CLOBBER
+ 		      && pat_code != ADDR_VEC
+ 		      && pat_code != ADDR_DIFF_VEC)
+ 		    {
+ 		      insn_rec[n_insns].insn = insn;
+ 		      insn_rec[n_insns++].loop_cost = loop_cost;
+ 		    }
+ 		}
+ 
+ 	      if (insn == bb->end)
+ 		break;
+ 	    }
+        }
+     }
+ 
  #ifdef FORBIDDEN_INC_DEC_CLASSES
  
    in_inc_dec = (char *) xmalloc (nregs);
*************** regclass (f, nregs, dump)
*** 1064,1197 ****
      }
  #endif /* FORBIDDEN_INC_DEC_CLASSES */
  
!   /* Normally we scan the insns once and determine the best class to use for
!      each register.  However, if -fexpensive_optimizations are on, we do so
!      twice, the second time using the tentative best classes to guide the
!      selection.  */
! 
!   for (pass = 0; pass <= flag_expensive_optimizations; pass++)
      {
!       int index;
  
!       if (dump)
!         fprintf (dump, "\n\nPass %i\n\n",pass);
!       /* Zero out our accumulation of the cost of each class for each reg.  */
  
!       bzero ((char *) costs, nregs * sizeof (struct costs));
  
  #ifdef FORBIDDEN_INC_DEC_CLASSES
!       bzero (in_inc_dec, nregs);
  #endif
  
!       /* Scan the instructions and record each time it would
! 	 save code to put a certain register in a certain class.  */
  
!       for (index = 0; index < n_basic_blocks; index++)
!        {
! 	 basic_block bb = BASIC_BLOCK (index);
! 
! 	 /* Show that an insn inside a loop is likely to be executed four
! 	    times more than insns outside a loop.  This is much more aggressive
! 	    than the assumptions made elsewhere and is being tried as an
! 	    experiment.  */
! 
! 	 loop_cost = 1 << (2 * MIN (bb->loop_depth - 1, 5));
  
! 	 for (insn = bb->head; ; insn = NEXT_INSN (insn))
! 	   {
! 	      if (!insn)
! 		abort();
! 	      insn = scan_one_insn (insn, pass);
! 	      if (insn == bb->end)
! 		break;
  	    }
-        }
-       
-       /* Now for each register look at how desirable each class is
- 	 and find which class is preferred.  Store that in
- 	 `prefclass'.  Record in `altclass' the largest register
- 	 class any of whose registers is better than memory.  */
-     
-       if (pass == 0)
- 	reg_pref = reg_pref_buffer;
  
!       if (dump)
!         {
! 	  dump_regclass (dump);
! 	  fprintf(dump,"\n");
  	}
!       for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
  	{
! 	  register int best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
! 	  enum reg_class best = ALL_REGS, alt = NO_REGS;
! 	  /* This is an enum reg_class, but we call it an int
! 	     to save lots of casts.  */
! 	  register int class;
! 	  register struct costs *p = &costs[i];
  
! 	  if (!REG_N_REFS (i))
! 	    continue;
  
! 	  for (class = (int) ALL_REGS - 1; class > 0; class--)
! 	    {
! 	      /* Ignore classes that are too small for this operand or
! 		 invalid for a operand that was auto-incremented.  */
! 	      if (CLASS_MAX_NREGS (class, PSEUDO_REGNO_MODE (i))
! 		  > reg_class_size[class]
! #ifdef FORBIDDEN_INC_DEC_CLASSES
! 		  || (in_inc_dec[i] && forbidden_inc_dec_class[class])
! #endif
! 		  )
! 		;
! 	      else if (p->cost[class] < best_cost)
! 		{
! 		  best_cost = p->cost[class];
! 		  best = (enum reg_class) class;
! 		}
! 	      else if (p->cost[class] == best_cost)
! 		best = reg_class_subunion[(int)best][class];
! 	    }
  
! 	  /* Record the alternate register class; i.e., a class for which
! 	     every register in it is better than using memory.  If adding a
! 	     class would make a smaller class (i.e., no union of just those
! 	     classes exists), skip that class.  The major unions of classes
! 	     should be provided as a register class.  Don't do this if we
! 	     will be doing it again later.  */
  
! 	  if ((pass == 1  || dump) || ! flag_expensive_optimizations)
! 	    for (class = 0; class < N_REG_CLASSES; class++)
! 	      if (p->cost[class] < p->mem_cost
! 		  && (reg_class_size[(int) reg_class_subunion[(int) alt][class]]
! 		      > reg_class_size[(int) alt])
! #ifdef FORBIDDEN_INC_DEC_CLASSES
! 		  && ! (in_inc_dec[i] && forbidden_inc_dec_class[class])
! #endif
! 		  )
! 		alt = reg_class_subunion[(int) alt][class];
! 	  
! 	  /* If we don't add any classes, nothing to try.  */
! 	  if (alt == best)
! 	    alt = NO_REGS;
  
! 	  if (dump 
! 	      && (reg_pref[i].prefclass != (int) best || reg_pref[i].altclass != (int) alt))
! 	    {
! 	      static const char *const reg_class_names[] = REG_CLASS_NAMES;
! 	      fprintf(dump, "  Register %i", i);
! 	      if (alt == ALL_REGS || best == ALL_REGS)
! 		fprintf (dump, " pref %s\n", reg_class_names[(int) best]);
! 	      else if (alt == NO_REGS)
! 		fprintf (dump, " pref %s or none\n", reg_class_names[(int) best]);
! 	      else
! 		fprintf (dump, " pref %s, else %s\n",
! 			 reg_class_names[(int) best],
! 			 reg_class_names[(int) alt]);
! 	    }
! 	  /* We cast to (int) because (char) hits bugs in some compilers.  */
! 	  reg_pref[i].prefclass = (int) best;
! 	  reg_pref[i].altclass = (int) alt;
  	}
      }
  
  #ifdef FORBIDDEN_INC_DEC_CLASSES
--- 1216,1364 ----
      }
  #endif /* FORBIDDEN_INC_DEC_CLASSES */
  
!   if (flag_expensive_optimizations)
      {
!       /* Normally we scan the insns once and determine the best class to use for
! 	 each register.  However, if -fexpensive_optimizations are on, we do so
! 	 twice, the second time using the tentative best classes to guide the
! 	 selection.  */
  
!       for (pass = 0; pass <= flag_expensive_optimizations; pass++)
! 	{
! 
! 	  if (dump)
! 	    fprintf (dump, "\n\nPass %i\n\n",pass);
! 	  /* Zero out our accumulation of the cost of each class for each reg.
! 	     */
  
! 	  bzero ((char *) costs, nregs * sizeof (struct costs));
  
  #ifdef FORBIDDEN_INC_DEC_CLASSES
! 	  bzero (in_inc_dec, nregs);
  #endif
  
! 	  /* Scan the instructions and record each time it would
! 	     save code to put a certain register in a certain class.  */
  
! 	  if (optimize)
! 	    for (i = 0; i < n_insns ; i++)
! 	      {
! 		loop_cost = insn_rec[i].loop_cost;
! 		scan_one_insn (i, pass);
! 	      }
! 	  else
! 	    {
! 	      loop_cost = 1;
! 	      for (insn = f; insn; insn = NEXT_INSN (insn))
! 	       {
! 		  register enum rtx_code code = GET_CODE (insn);
! 		  register enum rtx_code pat_code;
  
! 		  if (GET_RTX_CLASS (code) == 'i')
! 		    {
! 		      pat_code = GET_CODE (PATTERN (insn));
! 		      if (pat_code != USE
! 			  && pat_code != CLOBBER
! 			  && pat_code != ADDR_VEC
! 			  && pat_code != ADDR_DIFF_VEC)
! 			{
! 			  insn_rec[n_insns].insn = insn;
! 			  insn_rec[n_insns++].loop_cost = loop_cost;
! 			}
! 		    }
! 		}
! 	    }
! 	  
! 	  /* Now for each register look at how desirable each class is
! 	     and find which class is preferred.  Store that in
! 	     `prefclass'.  Record in `altclass' the largest register
! 	     class any of whose registers is better than memory.  */
! 	
! 	  if (pass == 0)
! 	    reg_pref = reg_pref_buffer;
! 	  else
! 	    {
! 	      old_reg_pref = old_reg_pref_buffer;
! 	      memcpy (old_reg_pref, reg_pref,
! 		      sizeof (struct reg_pref) * nregs);
  	    }
  
! 	  if (dump)
! 	    {
! 	      dump_regclass (dump);
! 	      fprintf(dump,"\n");
! 	    }
! 	  for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
! 	    {
! 	      if (calc_reg_preferrences (i, dump) && pass)
! 		bitmap_set_bit (changed_regs, i);
! 	    }
  	}
! 
!       /* Now do the propagation of the changes until preferrences converge.
! 	 Because we ought to change every register only once and every change
! 	 requires re-scaning of only insns mentioning that register, this ought
! 	 to converge in linear time.  */
! 
!       while (1)
  	{
! 	  int n, changed = 0;
! 	  bitmap_clear (changed_insns);
  
! 	  /* Find insns that needs to be re-scaned.
  
! 	     Ideally we would use sorted lists here and do merging using heaps,
! 	     but hope that this will not be performance problem.  */
! 	  EXECUTE_IF_SET_IN_BITMAP (changed_regs, 0, n,
! 	   {
! 	     changed = 1;
! 	     bitmap_operation (changed_insns, changed_insns,
! 			       insns_mentioning_reg[n], BITMAP_IOR);
! 	   });
  
! 	  if (!changed) break;
  
! 	  if (dump)
! 	    fprintf (dump, "\n\nPass %i\n\n",pass);
  
! 	  bitmap_clear (changed_regs);
! 	  bitmap_clear (changed_costs);
! 
! 	  /* Re-scan all selected insns.  */
! 	  EXECUTE_IF_SET_IN_BITMAP (changed_insns, 0, n,
! 	   {
! 	     if (dump)
! 	       fprintf(dump, "  Scanning insn %i\n",INSN_UID (insn_rec[n].insn));
! 	     changed = 1;
! 	     loop_cost = insn_rec[n].loop_cost;
! 	     update_costs (n);
! 	   });
! 
! 	  if (dump)
! 	    dump_regclass (dump);
! 
! 	  memcpy (old_reg_pref, reg_pref,
! 		  sizeof (struct reg_pref) * nregs);
! 
! 	  /* Re calculate prefferences for all registers where
! 	     cost were changed.  */
! 	  EXECUTE_IF_SET_IN_BITMAP (changed_costs, 0, n,
! 	   {
! 	     if (calc_reg_preferrences (n, dump))
! 	       bitmap_set_bit (changed_regs, n);
! 	   });
! 	  pass++;
  	}
+ 
+       for (i = FIRST_PSEUDO_REGISTER ; i < nregs ; i++)
+ 	if (REG_N_REFS (i))
+ 	  BITMAP_FREE (insns_mentioning_reg[i]);
+ 
+       BITMAP_FREE (changed_regs);
+       BITMAP_FREE (changed_insns);
+       BITMAP_FREE (changed_costs);
+       free (insns_mentioning_reg);
+       free (insn_rec);
      }
  
  #ifdef FORBIDDEN_INC_DEC_CLASSES
*************** allocate_reg_info (num_regs, new_p, renu
*** 2036,2041 ****
--- 2203,2210 ----
  	  renumber = (short *) xmalloc (size_renumber);
  	  reg_pref_buffer = (struct reg_pref *) xmalloc (regno_allocated 
  					      * sizeof (struct reg_pref));
+ 	  old_reg_pref_buffer = (struct reg_pref *) xmalloc (regno_allocated 
+ 					      * sizeof (struct reg_pref));
  	}
  
        else
*************** allocate_reg_info (num_regs, new_p, renu
*** 2049,2054 ****
--- 2218,2225 ----
  	      renumber = (short *) xmalloc (size_renumber);
  	      reg_pref_buffer = (struct reg_pref *) xmalloc (regno_allocated 
  						  * sizeof (struct reg_pref));
+ 	      old_reg_pref_buffer = (struct reg_pref *) xmalloc (regno_allocated 
+ 						  * sizeof (struct reg_pref));
  	    }
  
  	  else
*************** allocate_reg_info (num_regs, new_p, renu
*** 2057,2062 ****
--- 2228,2236 ----
  	      reg_pref_buffer = (struct reg_pref *) xrealloc ((char *)reg_pref_buffer,
  						   regno_allocated 
  						   * sizeof (struct reg_pref));
+ 	      old_reg_pref_buffer = (struct reg_pref *) xrealloc ((char *)reg_pref_buffer,
+ 						   regno_allocated 
+ 						   * sizeof (struct reg_pref));
  	    }
  	}
  
*************** allocate_reg_info (num_regs, new_p, renu
*** 2110,2115 ****
--- 2284,2291 ----
       the newly realloced ones.  */
    if (reg_pref)
      reg_pref = reg_pref_buffer;
+   if (old_reg_pref)
+     old_reg_pref = old_reg_pref_buffer;
  
    if (renumber_p)
      reg_renumber = renumber;
*************** free_reg_info ()
*** 2135,2141 ****
--- 2311,2319 ----
  	}
  
        free (reg_pref_buffer);
+       free (old_reg_pref_buffer);
        reg_pref_buffer = (struct reg_pref *)0;
+       old_reg_pref_buffer = (struct reg_pref *)0;
        reg_info_head = (struct reg_info_data *)0;
        renumber = (short *)0;
      }

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