[new-ra] general infrastructure for RA

Michael Matz matz@suse.de
Wed Jul 2 12:45:00 GMT 2003


Hi,

this is the first of a series of patches for the new-ra branch.  They
evolved over time, and partly are constructed by hand from an overall
diff.  Roughly according to one functionality update, plus assorted fixes
for each patch if needed.  I do this to have the possibility to point
people to this and that gcc-patches message for reverting ;-)

This first patch adds some functionality to the non ra* files.  In
particular it makes it possible for cse's delete_trivially_dead_insn() to
update eventual df information; makes recog.c deal with stack pseudos
(which are accepted as MEMs); globalizes some functions and variables; and
adds some functions which I'll need later.

The branch itself doesn't bootstrap as in CVS, and also doesn't bootstrap
with the patch.  This is fixed by the next patch.  I guess that one could
be applied before this patch, but I've tested them in this order, so ...


Ciao,
Michael.
-- 

2003-06-23  Michael Matz  <matz@suse.de>
	* Makefile.in (ra-build.o): Depend on OBSTACK_H.
	(ra-rewrite.o): Depend on pre-reload.h.

	* caller-save.c (save_call_clobbered_regs): Handle uninitialized rmw
	regs.
	* cfgrtl.c (verify_flow_info): Barf again on missing REG_EH_REGION.
	(purge_dead_edges): Also ignore sibling calls.
	* cse.c (delete_trivially_dead_insns_1): Break out from ... plus
	updates a df structure.
	(delete_trivially_dead_insns): ... here.  Call the above.
	(delete_trivially_dead_insns_df): New.
	* df.c (df_uid_refs_remove): New.
	(df_refs_update): Handle deleted insns.
	* df.h (delete_trivially_dead_insns_df): Prototype.
	* jump.c (true_regnum): Avoid segfault.
	* loop.c (copy_cost_for_loop): Renamed from ...
	(copy_cost): ... this.  Updated all accesses.
	* pre-reload.c (prefer_swapped): New.
	(push_pre_reload): Don't subreg special reg rtx's.
	(scan_alternative): New arguments pfree and prej.  Use prefer_swapped.
	(collect_insn_info): Better heuristics for choosing alternative.
	Don't add reloads in later ra passes.
	* ra.c (newra_in_progress): New.
	(reg_alloc): Set/reset it.
	* recog.c (toplevel): Include ra.h.
	(insn_invalid_p): Check for newra_in_progress.
	(scratch_operand): Ditto, plus only accept non-spill pseudos.
	(does_contain_spill_pseudos): New.
	(constrain_operands): Call it.  Check newra_in_progress.  Accept
	stack pseudos where MEM is accepted.
	* reg-stack.c (move_for_stack_reg): Use delete_insn_and_edges.
	* regclass.c (may_move_in_cost, may_move_out_cost, copy_cost):
	Make global.
	* regs.h (may_move_in_cost, may_move_out_cost): Declare.
	* rtl.h (REG_OR_SUBREG_P): New.
	(note_uses_partial, newra_in_progress, copy_cost): Declare.
	* rtlanal.c (note_uses_1, note_uses_partial): New.
	(note_uses): Call note_uses_1.
	* version.c (version_string): Add "(new RA)" designator.

diff -urpN work-gcc.orig/gcc/Makefile.in work-gcc/gcc/Makefile.in
--- work-gcc.orig/gcc/Makefile.in	2003-01-23 16:47:03.000000000 +0100
+++ work-gcc/gcc/Makefile.in	2003-06-16 17:37:31.000000000 +0200
@@ -1566,7 +1566,7 @@ ra.o : ra.c $(CONFIG_H) $(SYSTEM_H) $(RT
    $(BASIC_BLOCK_H) df.h expr.h output.h toplev.h flags.h reload.h ra.h
 ra-build.o : ra-build.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_P_H) \
    insn-config.h $(RECOG_H) function.h $(REGS_H) hard-reg-set.h \
-   $(BASIC_BLOCK_H) df.h output.h ggc.h ra.h gt-ra-build.h reload.h
+   $(BASIC_BLOCK_H) df.h output.h ggc.h $(OBSTACK_H) ra.h gt-ra-build.h reload.h
 ra-colorize.o : ra-colorize.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_P_H) \
     function.h $(REGS_H) hard-reg-set.h $(BASIC_BLOCK_H) df.h output.h ra.h
 ra-debug.o : ra-debug.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H)  insn-config.h \
@@ -1574,7 +1574,7 @@ ra-debug.o : ra-debug.c $(CONFIG_H) $(SY
    $(TM_P_H)
 ra-rewrite.o : ra-rewrite.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_P_H) \
    function.h $(REGS_H) hard-reg-set.h $(BASIC_BLOCK_H) df.h expr.h \
-   output.h except.h ra.h reload.h insn-config.h
+   output.h except.h ra.h reload.h pre-reload.h insn-config.h
 reload.o : reload.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h output.h \
    $(EXPR_H) $(OPTABS_H) reload.h $(RECOG_H) hard-reg-set.h insn-config.h \
    $(REGS_H) pre-reload.h function.h real.h toplev.h $(TM_P_H)
diff -urpN work-gcc.orig/gcc/caller-save.c work-gcc/gcc/caller-save.c
--- work-gcc.orig/gcc/caller-save.c	2003-01-23 16:47:11.000000000 +0100
+++ work-gcc/gcc/caller-save.c	2003-06-16 17:37:31.000000000 +0200
@@ -399,6 +399,17 @@ save_call_clobbered_regs ()
 		{
 		  CLEAR_HARD_REG_SET (referenced_regs);
 		  mark_referenced_regs (PATTERN (insn));
+		  /* In the case of rmw regs, whose "read" part is
+		     uninitialized (this can happen if the was a
+		     (set (subreg:SMALL (reg:BIG))) just before calculating
+		     liveness; this doesn't fill the whole reg, and it
+		     happens that this pseudo is marked live over calls,
+		     where in reality (after changing it to hardregs) it
+		     isn't.  We simply detect such situations by also
+		     restoring before defines of saved hard regs.  */
+		  CLEAR_HARD_REG_SET (this_insn_sets);
+		  note_stores (PATTERN (insn), mark_set_regs, NULL);
+		  IOR_HARD_REG_SET (referenced_regs, this_insn_sets);
 		  AND_HARD_REG_SET (referenced_regs, hard_regs_saved);
 		}

diff -urpN work-gcc.orig/gcc/cfgrtl.c work-gcc/gcc/cfgrtl.c
--- work-gcc.orig/gcc/cfgrtl.c	2003-01-23 16:47:13.000000000 +0100
+++ work-gcc/gcc/cfgrtl.c	2003-06-16 17:37:31.000000000 +0200
@@ -1861,12 +1861,12 @@ verify_flow_info ()
 	  edge_checksum[e->dest->index + 2] += (size_t) e;
 	}

-      /*if (n_eh && GET_CODE (PATTERN (bb->end)) != RESX
+      if (n_eh && GET_CODE (PATTERN (bb->end)) != RESX
 	  && !find_reg_note (bb->end, REG_EH_REGION, NULL_RTX))
 	{
 	  error ("Missing REG_EH_REGION note in the end of bb %i", bb->index);
 	  err = 1;
-	}*/
+	}
       if (n_branch
 	  && (GET_CODE (bb->end) != JUMP_INSN
 	      || (n_branch > 1 && (any_uncondjump_p (bb->end)
@@ -2118,7 +2118,8 @@ purge_dead_edges (bb)
       else if (e->flags & EDGE_ABNORMAL_CALL)
 	{
 	  if (GET_CODE (bb->end) == CALL_INSN
-	      && (! (note = find_reg_note (insn, REG_EH_REGION, NULL))
+	      && (SIBLING_CALL_P (bb->end)
+		  || ! (note = find_reg_note (insn, REG_EH_REGION, NULL))
 		  || INTVAL (XEXP (note, 0)) >= 0))
 	    continue;
 	}
diff -urpN work-gcc.orig/gcc/cse.c work-gcc/gcc/cse.c
--- work-gcc.orig/gcc/cse.c	2003-01-23 16:47:20.000000000 +0100
+++ work-gcc/gcc/cse.c	2003-06-16 17:37:31.000000000 +0200
@@ -36,6 +36,7 @@ Software Foundation, 59 Temple Place - S
 #include "expr.h"
 #include "toplev.h"
 #include "output.h"
+#include "df.h"
 #include "ggc.h"
 #include "timevar.h"

@@ -701,6 +702,8 @@ static void flush_hash_table	PARAMS ((vo
 static bool insn_live_p		PARAMS ((rtx, int *));
 static bool set_live_p		PARAMS ((rtx, rtx, int *));
 static bool dead_libcall_p	PARAMS ((rtx, int *));
+static int delete_trivially_dead_insns_1 PARAMS ((rtx, int, struct df *));
+

 /* Dump the expressions in the equivalence class indicated by CLASSP.
    This function is used only for debugging.  */
@@ -7685,6 +7688,30 @@ delete_trivially_dead_insns (insns, nreg
      rtx insns;
      int nreg;
 {
+  return delete_trivially_dead_insns_1 (insns, nreg, NULL);
+}
+
+/* Like delete_trivially_dead_insns(), but update also the DF structure
+   plus automatically preserves basic blocks.  */
+
+void
+delete_trivially_dead_insns_df (insns, nreg, df)
+     rtx insns;
+     int nreg;
+     struct df *df;
+{
+  delete_trivially_dead_insns_1 (insns, nreg, df);
+}
+
+/* Subroutine of delete_trivially_dead_insns() and
+   delete_trivially_dead_insns_df() doing the real work.  */
+
+static int
+delete_trivially_dead_insns_1 (insns, nreg, df)
+     rtx insns;
+     int nreg;
+     struct df *df;
+{
   int *counts;
   rtx insn, prev;
   int in_libcall = 0, dead_libcall = 0;
@@ -7740,6 +7767,8 @@ delete_trivially_dead_insns (insns, nreg
 	    {
 	      count_reg_usage (insn, counts, NULL_RTX, -1);
 	      delete_insn_and_edges (insn);
+	      if (df && BLOCK_FOR_INSN (insn))
+		df_insn_modify (df, BLOCK_FOR_INSN (insn), insn);
 	      ndead++;
 	    }

diff -urpN work-gcc.orig/gcc/df.c work-gcc/gcc/df.c
--- work-gcc.orig/gcc/df.c	2003-02-21 00:12:31.000000000 +0100
+++ work-gcc/gcc/df.c	2003-06-16 17:37:31.000000000 +0200
@@ -200,6 +200,7 @@ static struct df_link *df_ref_unlink PAR
 static void df_def_unlink PARAMS((struct df *, struct ref *));
 static void df_use_unlink PARAMS((struct df *, struct ref *));
 static void df_insn_refs_mark_deleted PARAMS ((struct df *, basic_block, rtx));
+static void df_uid_refs_remove PARAMS ((struct df *, unsigned int));
 static void df_insn_refs_unlink PARAMS ((struct df *, basic_block, rtx));
 #if 0
 static void df_bb_refs_unlink PARAMS ((struct df *, basic_block));
@@ -903,7 +904,8 @@ df_ref_record (df, reg, loc, insn, ref_t
      (subreg:SI (reg:M A) N), with size(SImode) > size(Mmode).
      XXX Is that true?  We could also use the global word_mode variable.  */
   if (GET_CODE (reg) == SUBREG
-      && (GET_MODE_SIZE (GET_MODE (reg)) < GET_MODE_SIZE (word_mode)
+      /* && (GET_MODE_SIZE (GET_MODE (reg)) < GET_MODE_SIZE (word_mode) */
+      && (GET_MODE_SIZE (GET_MODE (reg)) < GET_MODE_SIZE (SImode)
 	  || GET_MODE_SIZE (GET_MODE (reg))
 	       >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (reg)))))
     {
@@ -2328,18 +2330,31 @@ df_refs_update (df)
      struct df *df;
 {
   basic_block bb;
+  bitmap b = BITMAP_XMALLOC ();
+  rtx insn;
   int count = 0;
+  unsigned int uid;

-  if ((unsigned int) max_reg_num () >= df->reg_size)
+  if ((unsigned int)max_reg_num () >= df->reg_size)
     df_reg_table_realloc (df, 0);

   df_refs_queue (df);
+
+  /* Collect insns which were really deleted from the chain, but at least
+     got marked in the modified bitmap.  */
+  bitmap_copy (b, df->insns_modified);
+  for (insn = get_insns(); insn; insn = NEXT_INSN (insn))
+    bitmap_clear_bit (b, INSN_UID (insn));
+  EXECUTE_IF_SET_IN_BITMAP (b, 0, uid,
+    df_uid_refs_remove (df, uid););

   FOR_EACH_BB_IN_BITMAP (df->bbs_modified, 0, bb,
     {
       count += df_bb_refs_update (df, bb);
     });

+  BITMAP_XFREE (b);
+
   df_refs_process (df);
   return count;
 }
@@ -2427,6 +2442,23 @@ df_finish (df)
   free (df);
 }

+/* Unlink all refs which are associated with UID.  This should
+   correspond to a deleted insn (which was removed from the chain).  */
+static void
+df_uid_refs_remove (df, uid)
+     struct df *df;
+     unsigned int uid;
+{
+  struct df_link *link;
+
+  for (link = df->insns[uid].defs; link; link = link->next)
+    df_def_unlink (df, link->ref);
+  for (link = df->insns[uid].uses; link; link = link->next)
+    df_use_unlink (df, link->ref);
+
+  df->insns[uid].defs = 0;
+  df->insns[uid].uses = 0;
+}

 /* Unlink INSN from its reference information.  */
 static void
diff -urpN work-gcc.orig/gcc/df.h work-gcc/gcc/df.h
--- work-gcc.orig/gcc/df.h	2003-02-20 23:37:37.000000000 +0100
+++ work-gcc/gcc/df.h	2003-06-16 17:37:31.000000000 +0200
@@ -348,3 +348,5 @@ extern void iterative_dataflow_bitmap PA
 					       enum df_confluence_op,
 					       transfer_function_bitmap,
 					       int *, void *));
+/* In cse.c  */
+extern void delete_trivially_dead_insns_df     PARAMS ((rtx, int, struct df *));
diff -urpN work-gcc.orig/gcc/jump.c work-gcc/gcc/jump.c
--- work-gcc.orig/gcc/jump.c	2003-01-23 16:47:36.000000000 +0100
+++ work-gcc/gcc/jump.c	2003-06-16 17:37:31.000000000 +0200
@@ -2395,7 +2395,8 @@ true_regnum (x)
 {
   if (GET_CODE (x) == REG)
     {
-      if (REGNO (x) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (x)] >= 0)
+      if (REGNO (x) >= FIRST_PSEUDO_REGISTER
+          && reg_renumber && reg_renumber[REGNO (x)] >= 0)
 	return reg_renumber[REGNO (x)];
       return REGNO (x);
     }
diff -urpN work-gcc.orig/gcc/loop.c work-gcc/gcc/loop.c
--- work-gcc.orig/gcc/loop.c	2003-01-23 16:47:37.000000000 +0100
+++ work-gcc/gcc/loop.c	2003-06-16 17:37:31.000000000 +0200
@@ -392,7 +392,7 @@ static int biv_elimination_giv_has_0_off

 /* Benefit penalty, if a giv is not replaceable, i.e. must emit an insn to
    copy the value of the strength reduced giv to its original register.  */
-static int copy_cost;
+static int copy_cost_for_loop;

 /* Cost of using a register, to normalize the benefits of a giv.  */
 static int reg_address_cost;
@@ -404,7 +404,7 @@ init_loop ()

   reg_address_cost = address_cost (reg, SImode);

-  copy_cost = COSTS_N_INSNS (1);
+  copy_cost_for_loop = COSTS_N_INSNS (1);
 }

 /* Compute the mapping from uids to luids.
@@ -4962,7 +4962,7 @@ loop_giv_reduce_benefit (loop, bl, v, te
      necessary.  */
   if (! v->replaceable && ! bl->eliminable
       && REG_USERVAR_P (v->dest_reg))
-    benefit -= copy_cost;
+    benefit -= copy_cost_for_loop;

   /* Decrease the benefit to count the add-insns that we will insert
      to increment the reduced reg for the giv.  ??? This can
@@ -7697,7 +7697,7 @@ restart:
 		 of finding replaceable giv's, and hence this code may no
 		 longer be necessary.  */
 	      if (! g2->replaceable && REG_USERVAR_P (g2->dest_reg))
-		g1_add_benefit -= copy_cost;
+		g1_add_benefit -= copy_cost_for_loop;

 	      /* To help optimize the next set of combinations, remove
 		 this giv from the benefits of other potential mates.  */
diff -urpN work-gcc.orig/gcc/pre-reload.c work-gcc/gcc/pre-reload.c
--- work-gcc.orig/gcc/pre-reload.c	2003-04-10 15:39:24.000000000 +0200
+++ work-gcc/gcc/pre-reload.c	2003-06-16 17:37:31.000000000 +0200
@@ -78,6 +78,7 @@ static int pseudo_clobbered_p    PARAMS
 					  int));
 static void pre_reload_collect   PARAMS ((struct ra_info *, bitmap));
 static int pre_operands_match_p  PARAMS ((rtx, rtx));
+static int prefer_swapped PARAMS ((rtx, rtx, rtx));
 static void collect_insn_info    PARAMS ((struct ra_info *, rtx,
 					  ra_ref **, ra_ref **,
 					  int *, int *));
@@ -1442,14 +1443,27 @@ push_pre_reload (in, out, inloc, outloc,
   if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG
       && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
       && ! dont_remove_subreg)
-    in = gen_rtx_REG (GET_MODE (in), subreg_regno (in));
+    {
+      rtx sub = SUBREG_REG (in);
+      /* But only do this, if this is not one of the special reg rtx's,
+         as elimination relies on them being there, instead of relying on
+	 the reg number.  */
+      if (sub != frame_pointer_rtx && sub != hard_frame_pointer_rtx
+	  && sub != arg_pointer_rtx && sub != stack_pointer_rtx)
+        in = gen_rtx_REG (GET_MODE (in), subreg_regno (in));
+    }

   /* Similarly for OUT.  */
   if (out != 0 && GET_CODE (out) == SUBREG
       && GET_CODE (SUBREG_REG (out)) == REG
       && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
       && ! dont_remove_subreg)
-    out = gen_rtx_REG (GET_MODE (out), subreg_regno (out));
+    {
+      rtx sub = SUBREG_REG (out);
+      if (sub != frame_pointer_rtx && sub != hard_frame_pointer_rtx
+	  && sub != arg_pointer_rtx && sub != stack_pointer_rtx)
+        out = gen_rtx_REG (GET_MODE (out), subreg_regno (out));
+    }

   /* Narrow down the class of register wanted if that is
      desirable on this machine for efficiency.  */
@@ -2102,6 +2116,39 @@ pre_operands_match_p (x, y)
   return operands_match_p (x, y);
 }

+/* OP0 and OP1 are two commutative operands in INSN, where OP0 has to
+   match a former operand.  Return non-zero if we would prefer the insn
+   with both operands swapped and then reloaded.  Currently this checks
+   for OP0 and OP1 being registers, and prefers swapping if OP1 dies
+   before OP0.  This avoids to create live ranges longer than necessary.
+   It also ensures, that the conflicts of the matching operand (after possibly
+   swapping) are a subset of the conflicts of the other one.  */
+
+static int
+prefer_swapped (insn, op0, op1)
+     rtx insn, op0, op1;
+{
+  basic_block bb = BLOCK_FOR_INSN (insn);
+  if (GET_CODE (op0) == SUBREG)
+    op0 = SUBREG_REG (op0);
+  if (GET_CODE (op1) == SUBREG)
+    op1 = SUBREG_REG (op1);
+  if (!bb || !REG_P (op0) || !REG_P (op1))
+    return 0;
+  while (insn && bb == BLOCK_FOR_INSN (insn))
+    {
+      /* The way it's written (first testing OP0, then OP1) ensures,
+         that we do not prefer swapping if both ops die in the same insn.  */
+      if (find_reg_note (insn, REG_DEAD, op0))
+        return 0;
+      if (find_reg_note (insn, REG_DEAD, op1))
+        return 1;
+      insn = NEXT_INSN (insn);
+    }
+  return 0;
+}
+
+extern int ra_pass;

 struct alternative_info
 {
@@ -2123,13 +2170,13 @@ static int scan_alternative PARAMS ((str
 				     enum reload_usage [], int [],
 				     char [MAX_RECOG_OPERANDS]
 				     [MAX_RECOG_OPERANDS],
-				     int, int *));
+				     int, int *, int *, int *));

 /* Scan one alternative and fill alternative info.  */

 static int
 scan_alternative (this_alt, constraints, modified, address_reloaded,
-		  operands_match, swapped, commut)
+		  operands_match, swapped, commut, pfree, prej)
      struct alternative_info this_alt[];
      char *constraints[];
      enum reload_usage modified[];
@@ -2137,6 +2184,8 @@ scan_alternative (this_alt, constraints,
      char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
      int swapped;
      int *commut;
+     int *pfree;
+     int *prej;
 {
   int i;
   int j;
@@ -2152,6 +2201,9 @@ scan_alternative (this_alt, constraints,
      ? counts three times here since we want the disparaging caused by
      a bad register class to only count 1/3 as much.  */
   int reject = 0;
+  /* Number of hardregs in the alternative, for those operands, which
+     accept registers.  */
+  int freeness = 0;
   enum machine_mode *operand_mode = recog_data.operand_mode;
   int commutative = *commut;

@@ -2396,6 +2448,13 @@ scan_alternative (this_alt, constraints,
 		      == op_alt->matches)
 		    badop = 1;

+              /* Possibly prefer the swapped variant, by slightly penalizing
+                 the non-swapped form.  */
+              if (!swapped && i == commutative
+                  && prefer_swapped (this_insn, operand,
+                                     recog_data.operand[i + 1]))
+                reject++;
+
 	      if (REG_P (operand))
 		{
 		  op_alt->reg = operand;
@@ -2664,8 +2723,8 @@ scan_alternative (this_alt, constraints,
 	     it will then win since we don't want to have a different
 	     alternative match then.  */
 	  if (! (REG_P (operand)
-		 && (0
-		     && REGNO (operand) >= FIRST_PSEUDO_REGISTER))
+		 /*&& (0
+		     && REGNO (operand) >= FIRST_PSEUDO_REGISTER)*/)
 	      && GET_CODE (operand) != SCRATCH
 	      && ! (const_to_mem && constmemok))
 	    reject += 2;
@@ -2676,6 +2735,7 @@ scan_alternative (this_alt, constraints,
 	      && GET_CODE (operand) != SCRATCH)
 	    reject++;
 	}
+      freeness += reg_class_size[op_alt->class];
     }

   /* Now see if any output operands that are marked "earlyclobber"
@@ -2760,8 +2820,11 @@ scan_alternative (this_alt, constraints,
      a register would be reloaded into a non-preferred class, discourages
      the use of this alternative for a reload goal.  REJECT is incremented
      by six for each ? and two for each non-preferred class.  */
-  losers = losers * 6 + reject;
+  if (losers)
+    losers = losers * 6 + reject;

+  *pfree = freeness;
+  *prej = reject;
   return bad ? -1 : losers;
 }

@@ -2810,6 +2873,8 @@ collect_insn_info (ra_info, insn, def_re
   int operand_reloadnum[MAX_RECOG_OPERANDS];
   int goal_alternative_swapped;
   int best;
+  int best_num_regs;
+  int best_reject;
   int commutative;
   char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
   rtx substed_operand[MAX_RECOG_OPERANDS];
@@ -3019,6 +3084,9 @@ collect_insn_info (ra_info, insn, def_re
      all the operands together against the register constraints.  */

   best = MAX_RECOG_OPERANDS * 2 + 600;
+  best_num_regs = 0;
+  best_reject = MAX_RECOG_OPERANDS * 2 + 600;
+

   swapped = 0;
   goal_alternative_swapped = 0;
@@ -3039,20 +3107,40 @@ collect_insn_info (ra_info, insn, def_re
       /* LOSERS counts those that don't fit this alternative
 	 and would require loading.  */

+      int reject = 0;
+      int freeness = 0;
       int losers = scan_alternative (this_alt, constraints, modified,
 				     address_reloaded, operands_match,
-				     swapped, &commutative);
+				     swapped, &commutative, &freeness, &reject);

       /* If this alternative can be made to work by reloading,
 	 and it needs less reloading than the others checked so far,
 	 record it as the chosen goal for reloading.  */
-      if (losers >= 0 && best > losers)
+      if (losers >= 0
+         && (best > losers
+             /* XXX Ugh.  Ugly hack to prefer the swapped variant of
+                an alternative if it's otherwise as good as the non-swapped
+                one.  This simulates behaviour in local-alloc when tieing
+                two regs, in a no-conflict block equivalent to a commutative
+                operation.  What we want here is select which of the two
+                operands to make matching based on how far the death of the
+                ops is away.  We want to make the one with the nearer dead
+                matching.  */
+             /* || (best == losers && swapped) */
+             /* If we have a strictly matching alternative which accepts a
+                wider range of hardregs, choose that.  But only if it's
+                reject value isn't larger than the last strictly matching
+                alternative.  */
+             || (losers == 0 && freeness > best_num_regs
+                 && reject <= best_reject)))
 	{
 	  for (i = 0; i < noperands; i++)
 	    memcpy (&goal_alt[i], &this_alt[i], sizeof (this_alt[0]));
 	  goal_alternative_swapped = swapped;
 	  goal_alternative_number = this_alternative_number;
 	  best = losers;
+          best_num_regs = freeness;
+          best_reject = reject;
 	}
     }

@@ -3125,6 +3213,12 @@ collect_insn_info (ra_info, insn, def_re
     for (i = 0; i < noperands; i++)
       goal_alt[i].win = 1;

+  /* In the later passes we don't want to create new reload insns, but just
+     record register classes.  */
+  if (ra_pass > 1)
+    for (i = 0; i < noperands; i++)
+      goal_alt[i].win = 1;
+
   /* If the best alternative is with operands 1 and 2 swapped,
      consider them swapped before reporting the reloads.  Update the
      operand numbers of any reloads already pushed.  */
@@ -3685,9 +3779,11 @@ ra_check_constraints (insn)
       /* LOSERS counts those that don't fit this alternative
 	 and would require loading.  */

+      int freeness = 0;
+      int reject = 0;
       int losers = scan_alternative (this_alt, constraints, modified,
 				     address_reloaded, operands_match,
-				     swapped, &commutative);
+				     swapped, &commutative, &freeness, &reject);

       if (losers == 0)
 	return 1;
diff -urpN work-gcc.orig/gcc/ra.c work-gcc/gcc/ra.c
--- work-gcc.orig/gcc/ra.c	2003-02-03 20:30:39.000000000 +0100
+++ work-gcc/gcc/ra.c	2003-06-16 17:37:31.000000000 +0200
@@ -100,6 +100,9 @@ static void init_ra PARAMS ((void));

 void reg_alloc PARAMS ((void));

+/* See rtl.h.  */
+int newra_in_progress;
+
 /* These global variables are "internal" to the register allocator.
    They are all documented at their declarations in ra.h.  */

@@ -948,6 +951,8 @@ reg_alloc ()
   if (flag_ra_pre_reload)
     ra_info = ra_info_init (max_reg_num ());

+  newra_in_progress = 1;
+
   /* This is the main loop, calling one_pass as long as there are still
      some spilled webs.  */
   do
@@ -1114,6 +1119,7 @@ reg_alloc ()
   /*compute_bb_for_insn ();*/
   /*store_motion ();*/
   no_new_pseudos = 1;
+  newra_in_progress = 0;
   rtl_dump_file = ra_dump_file;

   /* Some spill insns could've been inserted after trapping calls, i.e.
diff -urpN work-gcc.orig/gcc/recog.c work-gcc/gcc/recog.c
--- work-gcc.orig/gcc/recog.c	2003-01-23 16:47:42.000000000 +0100
+++ work-gcc/gcc/recog.c	2003-06-16 17:37:31.000000000 +0200
@@ -37,6 +37,7 @@ Software Foundation, 59 Temple Place - S
 #include "basic-block.h"
 #include "output.h"
 #include "reload.h"
+#include "ra.h"

 #ifndef STACK_PUSH_CODE
 #ifdef STACK_GROWS_DOWNWARD
@@ -58,6 +59,7 @@ static void validate_replace_rtx_1	PARAM
 static rtx *find_single_use_1		PARAMS ((rtx, rtx *));
 static void validate_replace_src_1 	PARAMS ((rtx *, void *));
 static rtx split_insn			PARAMS ((rtx));
+static int does_contain_spill_pseudos   PARAMS ((rtx));

 /* Nonzero means allow operands to be volatile.
    This should be 0 if you are generating rtl, such as if you are calling
@@ -268,7 +270,8 @@ insn_invalid_p (insn)
      clobbers.  */
   int icode = recog (pat, insn,
 		     (GET_CODE (pat) == SET
-		      && ! reload_completed && ! reload_in_progress)
+		      && ! reload_completed && ! reload_in_progress
+		      && ! newra_in_progress)
 		     ? &num_clobbers : 0);
   int is_asm = icode < 0 && asm_noperands (PATTERN (insn)) >= 0;

@@ -296,7 +299,7 @@ insn_invalid_p (insn)
     }

   /* After reload, verify that all constraints are satisfied.  */
-  if (reload_completed)
+  if (reload_completed || newra_in_progress)
     {
       extract_insn (insn);

@@ -1123,9 +1126,6 @@ pmode_register_operand (op, mode)
   return register_operand (op, Pmode);
 }

-/* Return 1 if OP should match a MATCH_SCRATCH, i.e., if it is a SCRATCH
-   or a hard register.  */
-
 /* XXX gross hack, because pre-reload also allocates SCRATCHes,
    which might make some clobbers, which only should be scratch_operands
    be registers (pseudos, which then got a hardreg, but were not substituted
@@ -1136,6 +1136,9 @@ pmode_register_operand (op, mode)
    This variable is 1 in that case.  */
 int while_newra = 0;

+/* Return 1 if OP should match a MATCH_SCRATCH, i.e., if it is a SCRATCH
+   or a hard register.  */
+
 int
 scratch_operand (op, mode)
      rtx op;
@@ -1146,7 +1149,8 @@ scratch_operand (op, mode)

   return (GET_CODE (op) == SCRATCH
 	  || (GET_CODE (op) == REG
-	      && (REGNO (op) < FIRST_PSEUDO_REGISTER || while_newra)));
+	      && (REGNO (op) < FIRST_PSEUDO_REGISTER || while_newra
+	          || (newra_in_progress && !SPILL_SLOT_P (REGNO (op))))));
 }

 /* Return 1 if OP is a valid immediate operand for mode MODE.
@@ -2074,6 +2078,32 @@ mode_independent_operand (op, mode)
  lose: ATTRIBUTE_UNUSED_LABEL
   return 0;
 }
+
+static int
+does_contain_spill_pseudos (x)
+     rtx x;
+{
+  int i;
+  const char *fmt;
+  if (GET_CODE (x) == REG && SPILL_SLOT_P (REGNO (x)))
+    return 1;
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    if (fmt[i] == 'e')
+      {
+	if (does_contain_spill_pseudos (XEXP (x, i)))
+	  return 1;
+      }
+    else if (fmt[i] == 'E')
+      {
+	int j;
+	for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+	  if (does_contain_spill_pseudos (XVECEXP (x, i, j)))
+	    return 1;
+      }
+  return 0;
+}
+

 /* Like extract_insn, but save insn extracted and don't extract again, when
    called again for the same insn expecting that recog_data still contain the
@@ -2496,10 +2526,14 @@ constrain_operands (strict)
 		/* p is used for address_operands.  When we are called by
 		   gen_reload, no one will have checked that the address is
 		   strictly valid, i.e., that all pseudos requiring hard regs
-		   have gotten them.  */
-		if (strict <= 0
-		    || (strict_memory_address_p (recog_data.operand_mode[opno],
-						 op)))
+                   have gotten them.  While the new ra is running pre reload
+                   will have ensured, that this is basically of a form of
+                   an address.  */
+		if (newra_in_progress && does_contain_spill_pseudos (op))
+		  ;
+		else if (strict <= 0 || newra_in_progress
+		         || (strict_memory_address_p (recog_data.operand_mode[opno],
+						      op)))
 		  win = 1;
 		break;

@@ -2511,7 +2545,7 @@ constrain_operands (strict)
 		if (strict < 0
 		    || GENERAL_REGS == ALL_REGS
 		    || GET_CODE (op) != REG
-		    || (reload_in_progress
+		    || ((reload_in_progress || newra_in_progress)
 			&& REGNO (op) >= FIRST_PSEUDO_REGISTER)
 		    || reg_fits_class_p (op, GENERAL_REGS, offset, mode))
 		  win = 1;
@@ -2530,7 +2564,11 @@ constrain_operands (strict)
 		    || (strict < 0 && CONSTANT_P (op))
 		    /* During reload, accept a pseudo  */
 		    || (reload_in_progress && GET_CODE (op) == REG
-			&& REGNO (op) >= FIRST_PSEUDO_REGISTER))
+                        && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+                    /* With the graph coloring allocator only accept stack
+                       pseudos, but not normal ones.  */
+                    || (newra_in_progress && GET_CODE (op) == REG
+                        && SPILL_SLOT_P (REGNO (op))))
 		  win = 1;
 		break;

@@ -2595,7 +2633,12 @@ constrain_operands (strict)

 	      case 'V':
 		if (GET_CODE (op) == MEM
-		    && ((strict > 0 && ! offsettable_memref_p (op))
+                    /* Bah.  We can't call the memref checkers if the addresses
+                       contain pseudos, which they do while the new ra is
+                       running.  */
+                    && ((newra_in_progress && !offsettable_nonstrict_memref_p (op))
+                        || (!newra_in_progress && strict > 0
+                            && ! offsettable_memref_p (op))
 			|| (strict < 0
 			    && !(CONSTANT_P (op) || GET_CODE (op) == MEM))
 			|| (reload_in_progress
@@ -2605,14 +2648,18 @@ constrain_operands (strict)
 		break;

 	      case 'o':
-		if ((strict > 0 && offsettable_memref_p (op))
+                if ((newra_in_progress && offsettable_nonstrict_memref_p (op))
+                    || (!newra_in_progress && strict > 0
+                        && offsettable_memref_p (op))
 		    || (strict == 0 && offsettable_nonstrict_memref_p (op))
 		    /* Before reload, accept what reload can handle.  */
 		    || (strict < 0
 			&& (CONSTANT_P (op) || GET_CODE (op) == MEM))
 		    /* During reload, accept a pseudo  */
 		    || (reload_in_progress && GET_CODE (op) == REG
-			&& REGNO (op) >= FIRST_PSEUDO_REGISTER))
+                        && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+                    || (newra_in_progress && GET_CODE (op) == REG
+                        && SPILL_SLOT_P (REGNO (op))))
 		  win = 1;
 		break;

@@ -2621,15 +2668,26 @@ constrain_operands (strict)
 		  enum reg_class class;

 		  class = (c == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (c));
+                  /* In the new ra handle all REGs first.  We accept all
+                     normal pseudos, but no stack pseudos, as they represent
+                     memory slots.  */
 		  if (class != NO_REGS)
 		    {
+                      /* If we accept any reg at all, then accept everything
+                         if we do extra lax checking, accept all pseudo regs
+                         and scratches if we do nonstrict checking, accept
+                         registers which fit the needed class, and if the new
+                         ra is running also accept non stack pseudos.  */
 		      if (strict < 0
 			  || (strict == 0
 			      && GET_CODE (op) == REG
 			      && REGNO (op) >= FIRST_PSEUDO_REGISTER)
 			  || (strict == 0 && GET_CODE (op) == SCRATCH)
 			  || (GET_CODE (op) == REG
-			      && reg_fits_class_p (op, class, offset, mode)))
+                              && ((newra_in_progress
+                                   && REGNO (op) >= FIRST_PSEUDO_REGISTER
+                                   && !SPILL_SLOT_P (REGNO (op)))
+                                  || reg_fits_class_p (op, class, offset, mode))))
 		        win = 1;
 		    }
 #ifdef EXTRA_CONSTRAINT
@@ -2677,13 +2735,15 @@ constrain_operands (strict)
 	  /* See if any earlyclobber operand conflicts with some other
 	     operand.  */

-	  if (strict > 0)
+	  if (strict > 0 && !newra_in_progress)
 	    for (eopno = 0; eopno < recog_data.n_operands; eopno++)
 	      /* Ignore earlyclobber operands now in memory,
 		 because we would often report failure when we have
 		 two memory operands, one of which was formerly a REG.  */
 	      if (earlyclobber[eopno]
-		  && GET_CODE (recog_data.operand[eopno]) == REG)
+                  && GET_CODE (recog_data.operand[eopno]) == REG
+                  && !(newra_in_progress
+                       && SPILL_SLOT_P (REGNO (recog_data.operand[eopno]))))
 		for (opno = 0; opno < recog_data.n_operands; opno++)
 		  if ((GET_CODE (recog_data.operand[opno]) == MEM
 		       || recog_data.operand_type[opno] != OP_OUT)
diff -urpN work-gcc.orig/gcc/reg-stack.c work-gcc/gcc/reg-stack.c
--- work-gcc.orig/gcc/reg-stack.c	2003-01-23 16:47:42.000000000 +0100
+++ work-gcc/gcc/reg-stack.c	2003-06-16 17:37:31.000000000 +0200
@@ -1095,7 +1095,11 @@ move_for_stack_reg (insn, regstack, pat)
 	    {
 	      emit_pop_insn (insn, regstack, src, EMIT_AFTER);

-	      delete_insn (insn);
+	      /*  There might still be some stray REG_EH_REGION notes
+		  on the insn, _although_ it can't possibly trap anymore
+		  (otherwise we wouldn't try to delete it).  Simply remove
+		  the edges then too.  */
+	      delete_insn_and_edges (insn);
 	      return;
 	    }

@@ -1104,7 +1108,7 @@ move_for_stack_reg (insn, regstack, pat)
 	  SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
 	  CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));

-	  delete_insn (insn);
+	  delete_insn_and_edges (insn);

 	  return;
 	}
@@ -1121,7 +1125,7 @@ move_for_stack_reg (insn, regstack, pat)
 	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
 	    emit_pop_insn (insn, regstack, dest, EMIT_AFTER);

-	  delete_insn (insn);
+	  delete_insn_and_edges (insn);
 	  return;
 	}

diff -urpN work-gcc.orig/gcc/regclass.c work-gcc/gcc/regclass.c
--- work-gcc.orig/gcc/regclass.c	2003-01-23 16:47:42.000000000 +0100
+++ work-gcc/gcc/regclass.c	2003-06-16 17:37:31.000000000 +0200
@@ -206,12 +206,12 @@ static int move_cost[MAX_MACHINE_MODE][N
 /* Similar, but here we don't have to move if the first index is a subset
    of the second so in that case the cost is zero.  */

-static int may_move_in_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
+int may_move_in_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];

 /* Similar, but here we don't have to move if the first index is a superset
    of the second so in that case the cost is zero.  */

-static int may_move_out_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
+int may_move_out_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];

 #ifdef FORBIDDEN_INC_DEC_CLASSES

@@ -858,8 +858,6 @@ static void dump_regclass	PARAMS ((FILE
 static void record_reg_classes	PARAMS ((int, int, rtx *, enum machine_mode *,
 				       const char **, rtx,
 				       struct costs *, struct reg_pref *));
-static int copy_cost		PARAMS ((rtx, enum machine_mode,
-				       enum reg_class, int));
 static void record_address_regs	PARAMS ((rtx, enum reg_class, int));
 #ifdef FORBIDDEN_INC_DEC_CLASSES
 static int auto_inc_dec_reg_p	PARAMS ((rtx, enum machine_mode));
@@ -1869,7 +1867,7 @@ record_reg_classes (n_alts, n_ops, ops,

    X must not be a pseudo.  */

-static int
+int
 copy_cost (x, mode, class, to_p)
      rtx x;
      enum machine_mode mode ATTRIBUTE_UNUSED;
diff -urpN work-gcc.orig/gcc/regs.h work-gcc/gcc/regs.h
--- work-gcc.orig/gcc/regs.h	2003-01-23 16:47:42.000000000 +0100
+++ work-gcc/gcc/regs.h	2003-06-16 17:37:31.000000000 +0200
@@ -169,6 +169,10 @@ extern const char * reg_names[FIRST_PSEU

 extern enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];

+/* From regclass.c.  */
+extern int may_move_in_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
+extern int may_move_out_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
+
 /* Vector indexed by regno; gives uid of first insn using that reg.
    This is computed by reg_scan for use by cse and loop.
    It is sometimes adjusted for subsequent changes during loop,
diff -urpN work-gcc.orig/gcc/rtl.h work-gcc/gcc/rtl.h
--- work-gcc.orig/gcc/rtl.h	2003-01-23 16:47:43.000000000 +0100
+++ work-gcc/gcc/rtl.h	2003-06-16 17:37:31.000000000 +0200
@@ -250,6 +250,11 @@ struct rtvec_def GTY(()) {
 /* Predicate yielding nonzero iff X is an rtl for a register.  */
 #define REG_P(X) (GET_CODE (X) == REG)

+/* Predicate yielding nonzero iff X is an rtl for a register or a subreg
+   of a register.  */
+#define REG_OR_SUBREG_P(X) (REG_P (X) || (GET_CODE (X) == SUBREG \
+                                          && REG_P (SUBREG_REG (X))))
+
 /* Predicate yielding nonzero iff X is a label insn.  */
 #define LABEL_P(X) (GET_CODE (X) == CODE_LABEL)

@@ -1614,6 +1619,9 @@ extern void note_stores			PARAMS ((rtx,
 extern void note_uses			PARAMS ((rtx *,
 						 void (*) (rtx *, void *),
 						 void *));
+extern void note_uses_partial          PARAMS ((rtx *,
+                                                void (*) (rtx *, void *),
+                                                void *));
 extern rtx reg_set_last			PARAMS ((rtx, rtx));
 extern int dead_or_set_p		PARAMS ((rtx, rtx));
 extern int dead_or_set_regno_p		PARAMS ((rtx, unsigned int));
@@ -1883,6 +1891,12 @@ extern int reload_completed;

 extern int reload_in_progress;

+/* Set to 1 while the graph coloring register allocator is in progress.
+   In that case only certain pseudo register can be replaced by stack
+   references.  */
+
+extern int newra_in_progress;
+
 /* If this is nonzero, we do not bother generating VOLATILE
    around volatile memory references, and we are willing to
    output indirect addresses.  If cse is to follow, we reject
@@ -2110,6 +2124,8 @@ extern void regclass			PARAMS ((rtx, int
 extern void reg_scan			PARAMS ((rtx, unsigned int, int));
 extern void reg_scan_update		PARAMS ((rtx, rtx, unsigned int));
 extern void fix_register		PARAMS ((const char *, int, int));
+extern int copy_cost                   PARAMS ((rtx, enum machine_mode,
+                                                enum reg_class, int));
 #ifdef HARD_CONST
 extern void cannot_change_mode_set_regs PARAMS ((HARD_REG_SET *,
 						 enum machine_mode,
diff -urpN work-gcc.orig/gcc/rtlanal.c work-gcc/gcc/rtlanal.c
--- work-gcc.orig/gcc/rtlanal.c	2003-01-23 16:47:43.000000000 +0100
+++ work-gcc/gcc/rtlanal.c	2003-06-16 17:37:31.000000000 +0200
@@ -40,6 +40,7 @@ static int computed_jump_p_1	PARAMS ((rt
 static void parms_set 		PARAMS ((rtx, rtx, void *));
 static bool hoist_test_store		PARAMS ((rtx, rtx, regset));
 static void hoist_update_store		PARAMS ((rtx, rtx *, rtx, rtx));
+static void note_uses_1         PARAMS ((rtx *, void (*fun) PARAMS ((rtx *, void*)), void *, int));

 /* Bit flags that specify the machine subtype we are compiling for.
    Bits are tested using macros TARGET_... defined in the tm.h file
@@ -1657,6 +1658,25 @@ note_uses (pbody, fun, data)
      void (*fun) PARAMS ((rtx *, void *));
      void *data;
 {
+  note_uses_1 (pbody, fun, data, 0);
+}
+
+void
+note_uses_partial (pbody, fun, data)
+     rtx *pbody;
+     void (*fun) PARAMS ((rtx *, void *));
+     void *data;
+{
+  note_uses_1 (pbody, fun, data, 1);
+}
+
+static void
+note_uses_1 (pbody, fun, data, partial)
+     rtx *pbody;
+     void (*fun) PARAMS ((rtx *, void *));
+     void *data;
+     int partial;
+{
   rtx body = *pbody;
   int i;

@@ -1703,6 +1723,7 @@ note_uses (pbody, fun, data)
     case SET:
       {
 	rtx dest = SET_DEST (body);
+	rtx *loc = NULL;

 	/* For sets we replace everything in source plus registers in memory
 	   expression in store and operands of a ZERO_EXTRACT.  */
@@ -1710,15 +1731,22 @@ note_uses (pbody, fun, data)

 	if (GET_CODE (dest) == ZERO_EXTRACT)
 	  {
+	    loc = &XEXP (dest, 0);
 	    (*fun) (&XEXP (dest, 1), data);
 	    (*fun) (&XEXP (dest, 2), data);
 	  }

 	while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART)
-	  dest = XEXP (dest, 0);
+          {
+            if (!loc && GET_CODE (dest) == STRICT_LOW_PART)
+              loc = &XEXP (dest, 0);
+            dest = XEXP (dest, 0);
+          }

 	if (GET_CODE (dest) == MEM)
 	  (*fun) (&XEXP (dest, 0), data);
+        else if (partial && loc)
+          (*fun) (loc, data);
       }
       return;

diff -urpN work-gcc.orig/gcc/version.c work-gcc/gcc/version.c
--- work-gcc.orig/gcc/version.c	2003-01-23 16:47:50.000000000 +0100
+++ work-gcc/gcc/version.c	2003-06-16 17:37:31.000000000 +0200
@@ -6,7 +6,7 @@
    please modify this string to indicate that, e.g. by putting your
    organization's name in parentheses at the end of the string.  */

-const char version_string[] = "3.3 20021119 (experimental)";
+const char version_string[] = "3.3 20021119 (experimental) (new RA)";

 /* This is the location of the online document giving instructions for
    reporting bugs.  If you distribute a modified version of GCC,



More information about the Gcc-patches mailing list