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]

FOR_EACH_RTX usage



Hi
This patch makes some of rtx walking functions that are top on non-optimizing
profiles to use FOR_EACH_RTX.  I've measured savings in the range of 1-10% of
the compilation time without optimization.

Honza

Wed Sep 20 21:22:33 CEST 2000  Jan Hubicka  <jh@suse.cz>
	* emit_rtl.c (copy_rtx_if_shared):  Revamp to use FOR_EACH_RTX.
	(reset_used_flags): Likewise.
	* function.c (insns_for_mem_walk): Merge to ...
	(compute_insns_for_mem) ... here; Use FOR_EACH_RTX.
	(insns_for_mem_walk_info): Remove.
	* jump.c (mark_ref_label): Split out from ...
	(mark_jump_label): .... here; use FOR_EACH_RTX.
	* regclass.c (reg_scan_mark_refs): Use FOR_EACH_RTX.
	* reload1.c (elimination_effects): Likewise.
	* rtlanal.c (for_each_rtx): Likewise.

*** ../../egcs-20000918.orig/gcc/./emit-rtl.c	Wed Sep 20 11:17:54 2000
--- ./emit-rtl.c	Wed Sep 20 16:46:43 2000
*************** rtx
*** 1841,2017 ****
  copy_rtx_if_shared (orig)
       rtx orig;
  {
!   register rtx x = orig;
!   register int i;
!   register enum rtx_code code;
!   register const char *format_ptr;
!   int copied = 0;
! 
!   if (x == 0)
!     return 0;
! 
!   code = GET_CODE (x);
! 
!   /* These types may be freely shared.  */
! 
!   switch (code)
!     {
!     case REG:
!     case QUEUED:
!     case CONST_INT:
!     case CONST_DOUBLE:
!     case SYMBOL_REF:
!     case CODE_LABEL:
!     case PC:
!     case CC0:
!     case SCRATCH:
!       /* SCRATCH must be shared because they represent distinct values.  */
!       return x;
! 
!     case CONST:
!       /* CONST can be shared if it contains a SYMBOL_REF.  If it contains
! 	 a LABEL_REF, it isn't sharable.  */
!       if (GET_CODE (XEXP (x, 0)) == PLUS
! 	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
! 	  && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
! 	return x;
!       break;
! 
!     case INSN:
!     case JUMP_INSN:
!     case CALL_INSN:
!     case NOTE:
!     case BARRIER:
!       /* The chain of insns is not being copied.  */
!       return x;
! 
!     case MEM:
!       /* A MEM is allowed to be shared if its address is constant.
! 
! 	 We used to allow sharing of MEMs which referenced 
! 	 virtual_stack_vars_rtx or virtual_incoming_args_rtx, but
! 	 that can lose.  instantiate_virtual_regs will not unshare
! 	 the MEMs, and combine may change the structure of the address
! 	 because it looks safe and profitable in one context, but
! 	 in some other context it creates unrecognizable RTL.  */
!       if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
! 	return x;
! 
!       break;
! 
!     default:
!       break;
!     }
! 
!   /* This rtx may not be shared.  If it has already been seen,
!      replace it with a copy of itself.  */
! 
!   if (x->used)
!     {
!       register rtx copy;
! 
!       copy = rtx_alloc (code);
!       bcopy ((char *) x, (char *) copy,
! 	     (sizeof (*copy) - sizeof (copy->fld)
! 	      + sizeof (copy->fld[0]) * GET_RTX_LENGTH (code)));
!       x = copy;
!       copied = 1;
!     }
!   x->used = 1;
! 
!   /* Now scan the subexpressions recursively.
!      We can store any replaced subexpressions directly into X
!      since we know X is not shared!  Any vectors in X
!      must be copied if X was copied.  */
! 
!   format_ptr = GET_RTX_FORMAT (code);
! 
!   for (i = 0; i < GET_RTX_LENGTH (code); i++)
!     {
!       switch (*format_ptr++)
! 	{
! 	case 'e':
! 	  XEXP (x, i) = copy_rtx_if_shared (XEXP (x, i));
! 	  break;
! 
! 	case 'E':
! 	  if (XVEC (x, i) != NULL)
! 	    {
! 	      register int j;
! 	      int len = XVECLEN (x, i);
! 
! 	      if (copied && len > 0)
! 		XVEC (x, i) = gen_rtvec_v (len, XVEC (x, i)->elem);
! 	      for (j = 0; j < len; j++)
! 		XVECEXP (x, i, j) = copy_rtx_if_shared (XVECEXP (x, i, j));
! 	    }
! 	  break;
! 	}
!     }
!   return x;
  }
  
  /* Clear all the USED bits in X to allow copy_rtx_if_shared to be used
     to look for shared sub-parts.  */
  
  void
! reset_used_flags (x)
!      rtx x;
  {
!   register int i, j;
!   register enum rtx_code code;
!   register const char *format_ptr;
! 
!   if (x == 0)
!     return;
! 
!   code = GET_CODE (x);
! 
!   /* These types may be freely shared so we needn't do any resetting
!      for them.  */
! 
!   switch (code)
!     {
!     case REG:
!     case QUEUED:
!     case CONST_INT:
!     case CONST_DOUBLE:
!     case SYMBOL_REF:
!     case CODE_LABEL:
!     case PC:
!     case CC0:
!       return;
! 
!     case INSN:
!     case JUMP_INSN:
!     case CALL_INSN:
!     case NOTE:
!     case LABEL_REF:
!     case BARRIER:
!       /* The chain of insns is not being copied.  */
!       return;
!       
!     default:
!       break;
!     }
! 
!   x->used = 0;
! 
!   format_ptr = GET_RTX_FORMAT (code);
!   for (i = 0; i < GET_RTX_LENGTH (code); i++)
!     {
!       switch (*format_ptr++)
! 	{
! 	case 'e':
! 	  reset_used_flags (XEXP (x, i));
! 	  break;
! 
! 	case 'E':
! 	  for (j = 0; j < XVECLEN (x, i); j++)
! 	    reset_used_flags (XVECEXP (x, i, j));
! 	  break;
! 	}
!     }
  }
  
  /* Copy X if necessary so that it won't be altered by changes in OTHER.
--- 1841,2009 ----
  copy_rtx_if_shared (orig)
       rtx orig;
  {
!   rtx exp = orig;
!   enum rtx_code code;
!   int copy, recurse;
!   const char *format_ptr;
!   FOR_EACH_RTXP
!     (&exp, x, 
!       {
! 	recurse = 1;
! 	if (*x != 0)
! 	  {
! 	     code = GET_CODE (*x);
! 	     /* These types may be freely shared.  */
! 	     copy = 1;
! 
! 	     switch (code)
! 	       {
! 	       case REG:
! 	       case QUEUED:
! 	       case CONST_INT:
! 	       case CONST_DOUBLE:
! 	       case SYMBOL_REF:
! 	       case CODE_LABEL:
! 	       case PC:
! 	       case CC0:
! 	       case SCRATCH:
! 		 /* SCRATCH must be shared because they represent distinct
! 		    values.  */
! 	       case INSN:
! 	       case JUMP_INSN:
! 	       case CALL_INSN:
! 	       case NOTE:
! 	       case BARRIER:
! 		 /* The chain of insns is not being copied.  */
! 	         recurse = 0;
! 		 copy = 0;
! 		 break;
! 
! 	       case CONST:
! 		 /* CONST can be shared if it contains a SYMBOL_REF.  If it
! 		    contains a LABEL_REF, it isn't sharable.  */
! 		 if (GET_CODE (XEXP (*x, 0)) == PLUS
! 		     && GET_CODE (XEXP (XEXP (*x, 0), 0)) == SYMBOL_REF
! 		     && GET_CODE (XEXP (XEXP (*x, 0), 1)) == CONST_INT)
! 		   {
! 		      copy = 0;
! 		      recurse = 0;
! 		   }
! 		 break;
! 
! 	       case MEM:
! 		 /* A MEM is allowed to be shared if its address is constant.
! 
! 		    We used to allow sharing of MEMs which referenced 
! 		    virtual_stack_vars_rtx or virtual_incoming_args_rtx, but
! 		    that can lose.  instantiate_virtual_regs will not unshare
! 		    the MEMs, and combine may change the structure of the
! 		    address because it looks safe and profitable in one
! 		    context, but in some other context it creates
! 		    unrecognizable RTL.  */
! 		 if (CONSTANT_ADDRESS_P (XEXP (*x, 0)))
! 		   {
! 		      copy = 0;
! 		      recurse = 0;
! 		   }
! 		 break;
! 
! 	       default:
! 		 break;
! 	       }
! 
! 	     /* This rtx may not be shared.  If it has already been seen,
! 		replace it with a copy of itself.  */
! 
! 	     if (copy)
! 	       {
! 		 if ((*x)->used)
! 		   {
! 		     rtx copy;
! 		     int i;
! 
! 		     copy = rtx_alloc (code);
! 		     bcopy ((char *) *x, (char *) copy,
! 			    (sizeof (*copy) - sizeof (copy->fld)
! 			     + sizeof (copy->fld[0]) * GET_RTX_LENGTH (code)));
! 		     *x = copy;
! 
! 		     /*  Any vectors in X must be copied if X was copied.  */
! 		     format_ptr = GET_RTX_FORMAT (code);
! 		     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
! 		       {
! 			 if (format_ptr[i] == 'E')
! 			   {
! 			     if (XVEC (*x, i) != NULL)
! 			       {
! 				 int j;
! 				 int len = XVECLEN (*x, i);
! 
! 				 if (len > 0)
! 				   {
! 				     rtvec oldvec = XVEC (*x, i);
! 				     XVEC (*x, i) = gen_rtvec_v (len, oldvec->elem);
! 				     memcpy (&XVECEXP (*x, i, 0), oldvec->elem,
! 				             sizeof (oldvec->elem) * len);
! 				   }
! 			       }
! 			   }
! 		       }
! 		   }
! 		 (*x)->used = 1;
! 	       }
! 	  }
!       },
!     recurse);
!   return exp;
  }
  
  /* Clear all the USED bits in X to allow copy_rtx_if_shared to be used
     to look for shared sub-parts.  */
  
  void
! reset_used_flags (exp)
!      rtx exp;
  {
!   enum rtx_code code;
!   int copy, recurse;
!   FOR_EACH_RTX
!     (exp, x, 
!       {
! 	recurse = 1;
! 	if (x != 0)
! 	  {
! 	     code = GET_CODE (x);
! 	     /* These types may be freely shared.  */
! 	     copy = 1;
! 
! 	     switch (code)
! 	       {
! 	       case REG:
! 	       case QUEUED:
! 	       case CONST_INT:
! 	       case CONST_DOUBLE:
! 	       case SYMBOL_REF:
! 	       case CODE_LABEL:
! 	       case PC:
! 	       case CC0:
! 
! 	       case INSN:
! 	       case JUMP_INSN:
! 	       case CALL_INSN:
! 	       case NOTE:
! 	       case LABEL_REF:
! 	       case BARRIER:
! 	         recurse = 0;
! 		 break;
! 
! 	       default:
! 		 x->used = 0;
! 		 break;
! 	       }
! 
! 	  }
!       },
!     recurse);
  }
  
  /* Copy X if necessary so that it won't be altered by changes in OTHER.
*** ../../egcs-20000918.orig/gcc/./function.c	Wed Sep 20 11:18:03 2000
--- ./function.c	Wed Sep 20 10:02:48 2000
*************** static struct hash_entry *insns_for_mem_
*** 304,310 ****
  							 hash_table_key));
  static unsigned long insns_for_mem_hash PARAMS ((hash_table_key));
  static boolean insns_for_mem_comp PARAMS ((hash_table_key, hash_table_key));
- static int insns_for_mem_walk   PARAMS ((rtx *, void *));
  static void compute_insns_for_mem PARAMS ((rtx, rtx, struct hash_table *));
  static void mark_temp_slot PARAMS ((struct temp_slot *));
  static void mark_function_status PARAMS ((struct function *));
--- 304,309 ----
*************** insns_for_mem_comp (k1, k2)
*** 3240,3301 ****
    return k1 == k2;
  }
  
- struct insns_for_mem_walk_info {
-   /* The hash table that we are using to record which INSNs use which
-      MEMs.  */
-   struct hash_table *ht;
- 
-   /* The INSN we are currently proessing.  */
-   rtx insn;
- 
-   /* Zero if we are walking to find ADDRESSOFs, one if we are walking
-      to find the insns that use the REGs in the ADDRESSOFs.  */
-   int pass;
- };
- 
- /* Called from compute_insns_for_mem via for_each_rtx.  If R is a REG
-    that might be used in an ADDRESSOF expression, record this INSN in
-    the hash table given by DATA (which is really a pointer to an
-    insns_for_mem_walk_info structure).  */
- 
- static int
- insns_for_mem_walk (r, data)
-      rtx *r;
-      void *data;
- {
-   struct insns_for_mem_walk_info *ifmwi
-     = (struct insns_for_mem_walk_info *) data;
- 
-   if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF
-       && GET_CODE (XEXP (*r, 0)) == REG)
-     hash_lookup (ifmwi->ht, XEXP (*r, 0), /*create=*/1, /*copy=*/0);
-   else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG)
-     {
-       /* Lookup this MEM in the hashtable, creating it if necessary.  */
-       struct insns_for_mem_entry *ifme
- 	= (struct insns_for_mem_entry *) hash_lookup (ifmwi->ht,
- 						      *r,
- 						      /*create=*/0,
- 						      /*copy=*/0);
- 
-       /* If we have not already recorded this INSN, do so now.  Since
- 	 we process the INSNs in order, we know that if we have
- 	 recorded it it must be at the front of the list.  */
-       if (ifme && (!ifme->insns || XEXP (ifme->insns, 0) != ifmwi->insn))
- 	{
- 	  /* We do the allocation on the same obstack as is used for
- 	     the hash table since this memory will not be used once
- 	     the hash table is deallocated.  */
- 	  push_obstacks (&ifmwi->ht->memory, &ifmwi->ht->memory);
- 	  ifme->insns = gen_rtx_EXPR_LIST (VOIDmode, ifmwi->insn,
- 					   ifme->insns);
- 	  pop_obstacks ();
- 	}
-     }
- 
-   return 0;
- }
- 
  /* Walk the INSNS, until we reach LAST_INSN, recording which INSNs use
     which REGs in HT.  */
  
--- 3239,3244 ----
*************** compute_insns_for_mem (insns, last_insn,
*** 3306,3321 ****
       struct hash_table *ht;
  {
    rtx insn;
!   struct insns_for_mem_walk_info ifmwi;
!   ifmwi.ht = ht;
  
!   for (ifmwi.pass = 0; ifmwi.pass < 2; ++ifmwi.pass)
!     for (insn = insns; insn != last_insn; insn = NEXT_INSN (insn))
!       if (INSN_P (insn))
! 	{
! 	  ifmwi.insn = insn;
! 	  for_each_rtx (&insn, insns_for_mem_walk, &ifmwi);
! 	}
  }
  
  /* Helper function for purge_addressof called through for_each_rtx.
--- 3249,3303 ----
       struct hash_table *ht;
  {
    rtx insn;
!   int pass;
  
!   /* If R is a REG that might be used in an ADDRESSOF expression,
!      record this INSN in the hash table given by DATA (which is
!      really a pointer to an insns_for_mem_walk_info structure).  */
!   for (insn = insns; insn != last_insn; insn = NEXT_INSN (insn))
!     if (INSN_P (insn))
!       {
! 	FOR_EACH_RTX
! 	  (insn, r,
! 	    {
! 	      if (r && GET_CODE (r) == ADDRESSOF
! 		  && GET_CODE (XEXP (r, 0)) == REG)
! 		hash_lookup (ht, XEXP (r, 0), /*create=*/1, /*copy=*/0);
! 	    },
! 	   1);
!       }
!   for (insn = insns; insn != last_insn; insn = NEXT_INSN (insn))
!     if (INSN_P (insn))
!       {
! 	FOR_EACH_RTX
! 	  (insn, r,
! 	    {
! 	      if (r && GET_CODE (r) == REG)
! 		{
! 		  /* Lookup this MEM in the hashtable, creating it if necessary.  */
! 		  struct insns_for_mem_entry *ifme
! 		    = (struct insns_for_mem_entry *) hash_lookup (ht,
! 								  r,
! 								  /*create=*/0,
! 								  /*copy=*/0);
! 
! 		  /* If we have not already recorded this INSN, do so now.  Since
! 		     we process the INSNs in order, we know that if we have
! 		     recorded it it must be at the front of the list.  */
! 		  if (ifme && (!ifme->insns || XEXP (ifme->insns, 0) != insn))
! 		    {
! 		      /* We do the allocation on the same obstack as is used for
! 			 the hash table since this memory will not be used once
! 			 the hash table is deallocated.  */
! 		      push_obstacks (&ht->memory, &ht->memory);
! 		      ifme->insns = gen_rtx_EXPR_LIST (VOIDmode, insn,
! 						       ifme->insns);
! 		      pop_obstacks ();
! 		    }
! 		}
! 	    },
! 	   1);
!       }
  }
  
  /* Helper function for purge_addressof called through for_each_rtx.
*** ../../egcs-20000918.orig/gcc/./jump.c	Wed Sep 20 11:16:47 2000
--- ./jump.c	Wed Sep 20 14:35:05 2000
*************** static void redirect_tablejump		PARAMS (
*** 131,136 ****
--- 131,137 ----
  static void jump_optimize_1		PARAMS ((rtx, int, int, int, int, int));
  static int returnjump_p_1	        PARAMS ((rtx *, void *));
  static void delete_prior_computation    PARAMS ((rtx, rtx));
+ static inline void mark_ref_label	PARAMS ((rtx, rtx, int));
  
  /* Main external entry point into the jump optimizer.  See comments before
     jump_optimize_1 for descriptions of the arguments.  */
*************** tension_vector_labels (x, idx)
*** 2426,2431 ****
--- 2427,2515 ----
    return changed;
  }
  
+ /* Mark single label X present in the INSN.  Used by mark_jump_label.  */
+ static inline void
+ mark_ref_label (x, insn, cross_jump)
+ 	rtx x, insn;
+ 	int cross_jump;
+ {
+   rtx label = XEXP (x, 0);
+   rtx olabel = label;
+   rtx note;
+   rtx next;
+ 
+   /* Ignore remaining references to unreachable labels that
+      have been deleted.  */
+   if (GET_CODE (label) == NOTE
+       && NOTE_LINE_NUMBER (label) == NOTE_INSN_DELETED_LABEL)
+     return;
+ 
+   if (GET_CODE (label) != CODE_LABEL)
+     abort ();
+ 
+   /* Ignore references to labels of containing functions.  */
+   if (LABEL_REF_NONLOCAL_P (x))
+     return;
+ 
+   /* If there are other labels following this one,
+      replace it with the last of the consecutive labels.  */
+   for (next = NEXT_INSN (label); next; next = NEXT_INSN (next))
+     {
+       if (GET_CODE (next) == CODE_LABEL)
+ 	label = next;
+       else if (cross_jump && GET_CODE (next) == INSN
+ 	       && (GET_CODE (PATTERN (next)) == USE
+ 		   || GET_CODE (PATTERN (next)) == CLOBBER))
+ 	continue;
+       else if (GET_CODE (next) != NOTE)
+ 	break;
+       else if (!cross_jump
+ 	       && (NOTE_LINE_NUMBER (next) == NOTE_INSN_LOOP_BEG
+ 		   || NOTE_LINE_NUMBER (next) == NOTE_INSN_FUNCTION_END
+ 		   /* ??? Optional.  Disables some optimizations, but
+ 		      makes gcov output more accurate with -O.  */
+ 		   || (flag_test_coverage && NOTE_LINE_NUMBER (next) > 0)))
+ 	break;
+     }
+ 
+   XEXP (x, 0) = label;
+   if (!insn || !INSN_DELETED_P (insn))
+     ++LABEL_NUSES (label);
+ 
+   if (insn)
+     {
+       if (GET_CODE (insn) == JUMP_INSN)
+ 	JUMP_LABEL (insn) = label;
+ 
+       /* If we've changed OLABEL and we had a REG_LABEL note
+          for it, update it as well.  */
+       else if (label != olabel
+ 	       && (note = find_reg_note (insn, REG_LABEL, olabel)) != 0)
+ 	XEXP (note, 0) = label;
+ 
+       /* Otherwise, add a REG_LABEL note for LABEL unless there already
+          is one.  */
+       else if (!find_reg_note (insn, REG_LABEL, label))
+ 	{
+ 	  /* This code used to ignore labels which refered to dispatch
+ 	     tables to avoid flow.c generating worse code.
+ 
+ 	     However, in the presense of global optimizations like
+ 	     gcse which call find_basic_blocks without calling
+ 	     life_analysis, not recording such labels will lead
+ 	     to compiler aborts because of inconsistencies in the
+ 	     flow graph.  So we go ahead and record the label.
+ 
+ 	     It may also be the case that the optimization argument
+ 	     is no longer valid because of the more accurate cfg
+ 	     we build in find_basic_blocks -- it no longer pessimizes
+ 	     code when it finds a REG_LABEL note.  */
+ 	  REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
+ 						REG_NOTES (insn));
+ 	}
+     }
+ }
+ 
  /* Find all CODE_LABELs referred to in X, and increment their use counts.
     If INSN is a JUMP_INSN and there is at least one CODE_LABEL referenced
     in INSN, then store one of them in JUMP_LABEL (INSN).
*************** tension_vector_labels (x, idx)
*** 2443,2594 ****
     two labels distinct if they are separated by only USE or CLOBBER insns.  */
  
  static void
! mark_jump_label (x, insn, cross_jump, in_mem)
!      register rtx x;
       rtx insn;
       int cross_jump;
       int in_mem;
  {
!   register RTX_CODE code = GET_CODE (x);
    register int i;
!   register const char *fmt;
! 
!   switch (code)
!     {
!     case PC:
!     case CC0:
!     case REG:
!     case SUBREG:
!     case CONST_INT:
!     case CONST_DOUBLE:
!     case CLOBBER:
!     case CALL:
!       return;
! 
!     case MEM:
!       in_mem = 1;
!       break;
  
!     case SYMBOL_REF:
!       if (!in_mem)
! 	return;
! 
!       /* If this is a constant-pool reference, see if it is a label.  */
!       if (CONSTANT_POOL_ADDRESS_P (x))
! 	mark_jump_label (get_pool_constant (x), insn, cross_jump, in_mem);
!       break;
! 
!     case LABEL_REF:
        {
! 	rtx label = XEXP (x, 0);
! 	rtx olabel = label;
! 	rtx note;
! 	rtx next;
! 
! 	/* Ignore remaining references to unreachable labels that
! 	   have been deleted.  */
! 	if (GET_CODE (label) == NOTE
! 	    && NOTE_LINE_NUMBER (label) == NOTE_INSN_DELETED_LABEL)
! 	  break;
! 
! 	if (GET_CODE (label) != CODE_LABEL)
! 	  abort ();
! 
! 	/* Ignore references to labels of containing functions.  */
! 	if (LABEL_REF_NONLOCAL_P (x))
! 	  break;
! 
! 	/* If there are other labels following this one,
! 	   replace it with the last of the consecutive labels.  */
! 	for (next = NEXT_INSN (label); next; next = NEXT_INSN (next))
! 	  {
! 	    if (GET_CODE (next) == CODE_LABEL)
! 	      label = next;
! 	    else if (cross_jump && GET_CODE (next) == INSN
! 		     && (GET_CODE (PATTERN (next)) == USE
! 			 || GET_CODE (PATTERN (next)) == CLOBBER))
! 	      continue;
! 	    else if (GET_CODE (next) != NOTE)
! 	      break;
! 	    else if (! cross_jump
! 		     && (NOTE_LINE_NUMBER (next) == NOTE_INSN_LOOP_BEG
! 			 || NOTE_LINE_NUMBER (next) == NOTE_INSN_FUNCTION_END
! 			 /* ??? Optional.  Disables some optimizations, but
! 			    makes gcov output more accurate with -O.  */
! 			 || (flag_test_coverage
! 			     && NOTE_LINE_NUMBER (next) > 0)))
! 	      break;
! 	  }
! 
! 	XEXP (x, 0) = label;
! 	if (! insn || ! INSN_DELETED_P (insn))
! 	  ++LABEL_NUSES (label);
! 
! 	if (insn)
  	  {
! 	    if (GET_CODE (insn) == JUMP_INSN)
! 	      JUMP_LABEL (insn) = label;
! 
! 	    /* If we've changed OLABEL and we had a REG_LABEL note
! 	       for it, update it as well.  */
! 	    else if (label != olabel
! 		     && (note = find_reg_note (insn, REG_LABEL, olabel)) != 0)
! 	      XEXP (note, 0) = label;
! 
! 	    /* Otherwise, add a REG_LABEL note for LABEL unless there already
! 	       is one.  */
! 	    else if (! find_reg_note (insn, REG_LABEL, label))
  	      {
! 		/* This code used to ignore labels which refered to dispatch
! 		   tables to avoid flow.c generating worse code.
  
! 		   However, in the presense of global optimizations like
! 		   gcse which call find_basic_blocks without calling
! 		   life_analysis, not recording such labels will lead
! 		   to compiler aborts because of inconsistencies in the
! 		   flow graph.  So we go ahead and record the label.
! 
! 		   It may also be the case that the optimization argument
! 		   is no longer valid because of the more accurate cfg
! 		   we build in find_basic_blocks -- it no longer pessimizes
! 		   code when it finds a REG_LABEL note.  */
! 		REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
! 						      REG_NOTES (insn));
  	      }
  	  }
! 	return;
!       }
! 
!   /* Do walk the labels in a vector, but not the first operand of an
!      ADDR_DIFF_VEC.  Don't set the JUMP_LABEL of a vector.  */
!     case ADDR_VEC:
!     case ADDR_DIFF_VEC:
!       if (! INSN_DELETED_P (insn))
! 	{
! 	  int eltnum = code == ADDR_DIFF_VEC ? 1 : 0;
! 
! 	  for (i = 0; i < XVECLEN (x, eltnum); i++)
! 	    mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX,
! 			     cross_jump, in_mem);
! 	}
!       return;
! 
!     default:
!       break;
!     }
! 
!   fmt = GET_RTX_FORMAT (code);
!   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
!     {
!       if (fmt[i] == 'e')
! 	mark_jump_label (XEXP (x, i), insn, cross_jump, in_mem);
!       else if (fmt[i] == 'E')
! 	{
! 	  register int j;
! 	  for (j = 0; j < XVECLEN (x, i); j++)
! 	    mark_jump_label (XVECEXP (x, i, j), insn, cross_jump, in_mem);
! 	}
!     }
  }
  
  /* If all INSN does is set the pc, delete it,
--- 2527,2605 ----
     two labels distinct if they are separated by only USE or CLOBBER insns.  */
  
  static void
! mark_jump_label (exp, insn, cross_jump, in_mem)
!      register rtx exp;
       rtx insn;
       int cross_jump;
       int in_mem;
  {
!   register RTX_CODE code;
    register int i;
!   register int recurse;
  
!   FOR_EACH_RTX
!     (exp, x,
        {
! 	recurse = 1;
! 	if (x)
  	  {
! 	    code = GET_CODE (x);
! 	    switch (code)
  	      {
! 	      case PC:
! 	      case CC0:
! 	      case REG:
! 	      case SUBREG:
! 	      case CONST_INT:
! 	      case CONST_DOUBLE:
! 	      case CLOBBER:
! 	      case CALL:
! 		recurse = 0;
! 		break;
! 
! 	      case MEM:
! 		if (!in_mem)
! 		  {
! 		    mark_jump_label (XEXP (x, 0), insn, cross_jump, 1);
! 		    recurse = 0;
! 		  }
! 		break;
! 
! 	      case SYMBOL_REF:
! 		recurse = 0;
! 		if (!in_mem)
! 		    break;
  
! 		/* If this is a constant-pool reference, see if it is a label.  */
! 		if (CONSTANT_POOL_ADDRESS_P (x))
! 		  FOR_EACH_RTX_PUSH (get_pool_constant (x));
! 		break;
! 
! 	      case LABEL_REF:
! 		mark_ref_label (x, insn, cross_jump);
! 		recurse = 0;
! 		break;
! 
! 	    /* Do walk the labels in a vector, but not the first operand of an
! 	       ADDR_DIFF_VEC.  Don't set the JUMP_LABEL of a vector.  */
! 	      case ADDR_VEC:
! 	      case ADDR_DIFF_VEC:
! 		if (! INSN_DELETED_P (insn))
! 		  {
! 		    int eltnum = code == ADDR_DIFF_VEC ? 1 : 0;
! 
! 		    for (i = 0; i < XVECLEN (x, eltnum); i++)
! 		      mark_ref_label (XVECEXP (x, eltnum, i), NULL_RTX, cross_jump);
! 		  }
! 		recurse = 0;
! 		break;
! 
! 	      default:
! 		break;
  	      }
  	  }
!       },
!    recurse);
  }
  
  /* If all INSN does is set the pc, delete it,
*** ../../egcs-20000918.orig/gcc/./regclass.c	Wed Sep 20 11:18:04 2000
--- ./regclass.c	Wed Sep 20 13:22:15 2000
*************** reg_scan_update (first, last, old_max_re
*** 2250,2257 ****
     greater than or equal to MIN_REGNO.  */
  
  static void
! reg_scan_mark_refs (x, insn, note_flag, min_regno)
!      rtx x;
       rtx insn;
       int note_flag;
       unsigned int min_regno;
--- 2250,2257 ----
     greater than or equal to MIN_REGNO.  */
  
  static void
! reg_scan_mark_refs (exp, insn, note_flag, min_regno)
!      rtx exp;
       rtx insn;
       int note_flag;
       unsigned int min_regno;
*************** reg_scan_mark_refs (x, insn, note_flag, 
*** 2259,2385 ****
    register enum rtx_code code;
    register rtx dest;
    register rtx note;
  
!   code = GET_CODE (x);
!   switch (code)
!     {
!     case CONST:
!     case CONST_INT:
!     case CONST_DOUBLE:
!     case CC0:
!     case PC:
!     case SYMBOL_REF:
!     case LABEL_REF:
!     case ADDR_VEC:
!     case ADDR_DIFF_VEC:
!       return;
! 
!     case REG:
!       {
! 	unsigned int regno = REGNO (x);
! 
! 	if (regno >= min_regno)
! 	  {
! 	    REGNO_LAST_NOTE_UID (regno) = INSN_UID (insn);
! 	    if (!note_flag)
! 	      REGNO_LAST_UID (regno) = INSN_UID (insn);
! 	    if (REGNO_FIRST_UID (regno) == 0)
! 	      REGNO_FIRST_UID (regno) = INSN_UID (insn);
! 	  }
!       }
!       break;
! 
!     case EXPR_LIST:
!       if (XEXP (x, 0))
! 	reg_scan_mark_refs (XEXP (x, 0), insn, note_flag, min_regno);
!       if (XEXP (x, 1))
! 	reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
!       break;
! 
!     case INSN_LIST:
!       if (XEXP (x, 1))
! 	reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
!       break;
! 
!     case SET:
!       /* Count a set of the destination if it is a register.  */
!       for (dest = SET_DEST (x);
! 	   GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
! 	   || GET_CODE (dest) == ZERO_EXTEND;
! 	   dest = XEXP (dest, 0))
! 	;
! 
!       if (GET_CODE (dest) == REG
! 	  && REGNO (dest) >= min_regno)
! 	REG_N_SETS (REGNO (dest))++;
! 
!       /* If this is setting a pseudo from another pseudo or the sum of a
! 	 pseudo and a constant integer and the other pseudo is known to be
! 	 a pointer, set the destination to be a pointer as well.
! 
! 	 Likewise if it is setting the destination from an address or from a
! 	 value equivalent to an address or to the sum of an address and
! 	 something else.
! 		     
! 	 But don't do any of this if the pseudo corresponds to a user
! 	 variable since it should have already been set as a pointer based
! 	 on the type.  */
! 
!       if (GET_CODE (SET_DEST (x)) == REG
! 	  && REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER
! 	  && REGNO (SET_DEST (x)) >= min_regno
! 	  /* If the destination pseudo is set more than once, then other
! 	     sets might not be to a pointer value (consider access to a
! 	     union in two threads of control in the presense of global
! 	     optimizations).  So only set REGNO_POINTER_FLAG on the destination
! 	     pseudo if this is the only set of that pseudo.  */
! 	  && REG_N_SETS (REGNO (SET_DEST (x))) == 1
! 	  && ! REG_USERVAR_P (SET_DEST (x))
! 	  && ! REGNO_POINTER_FLAG (REGNO (SET_DEST (x)))
! 	  && ((GET_CODE (SET_SRC (x)) == REG
! 	       && REGNO_POINTER_FLAG (REGNO (SET_SRC (x))))
! 	      || ((GET_CODE (SET_SRC (x)) == PLUS
! 		   || GET_CODE (SET_SRC (x)) == LO_SUM)
! 		  && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
! 		  && GET_CODE (XEXP (SET_SRC (x), 0)) == REG
! 		  && REGNO_POINTER_FLAG (REGNO (XEXP (SET_SRC (x), 0))))
! 	      || GET_CODE (SET_SRC (x)) == CONST
! 	      || GET_CODE (SET_SRC (x)) == SYMBOL_REF
! 	      || GET_CODE (SET_SRC (x)) == LABEL_REF
! 	      || (GET_CODE (SET_SRC (x)) == HIGH
! 		  && (GET_CODE (XEXP (SET_SRC (x), 0)) == CONST
! 		      || GET_CODE (XEXP (SET_SRC (x), 0)) == SYMBOL_REF
! 		      || GET_CODE (XEXP (SET_SRC (x), 0)) == LABEL_REF))
! 	      || ((GET_CODE (SET_SRC (x)) == PLUS
! 		   || GET_CODE (SET_SRC (x)) == LO_SUM)
! 		  && (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST
! 		      || GET_CODE (XEXP (SET_SRC (x), 1)) == SYMBOL_REF
! 		      || GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF))
! 	      || ((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
! 		  && (GET_CODE (XEXP (note, 0)) == CONST
! 		      || GET_CODE (XEXP (note, 0)) == SYMBOL_REF
! 		      || GET_CODE (XEXP (note, 0)) == LABEL_REF))))
! 	REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1;
! 
!       /* ... fall through ...  */
! 
!     default:
!       {
! 	register const char *fmt = GET_RTX_FORMAT (code);
! 	register int i;
! 	for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
! 	  {
! 	    if (fmt[i] == 'e')
! 	      reg_scan_mark_refs (XEXP (x, i), insn, note_flag, min_regno);
! 	    else if (fmt[i] == 'E' && XVEC (x, i) != 0)
  	      {
! 		register int j;
! 		for (j = XVECLEN (x, i) - 1; j >= 0; j--)
! 		  reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag, min_regno);
  	      }
! 	  }
!       }
!     }
  }
  
  /* Return nonzero if C1 is a subset of C2, i.e., if every register in C1
--- 2259,2374 ----
    register enum rtx_code code;
    register rtx dest;
    register rtx note;
+   register int recurse;
  
!   FOR_EACH_RTX
!     (exp, x,
!        if (x)
! 	 {
! 	    code = GET_CODE (x);
! 	    recurse = 1;
! 	    switch (code)
  	      {
! 	      case CONST:
! 	      case CONST_INT:
! 	      case CONST_DOUBLE:
! 	      case CC0:
! 	      case PC:
! 	      case SYMBOL_REF:
! 	      case LABEL_REF:
! 	      case ADDR_VEC:
! 	      case ADDR_DIFF_VEC:
! 		recurse = 0;
! 		break;
! 
! 	      case REG:
! 		{
! 		  unsigned int regno = REGNO (x);
! 
! 		  if (regno >= min_regno)
! 		    {
! 		      REGNO_LAST_NOTE_UID (regno) = INSN_UID (insn);
! 		      if (!note_flag)
! 			REGNO_LAST_UID (regno) = INSN_UID (insn);
! 		      if (REGNO_FIRST_UID (regno) == 0)
! 			REGNO_FIRST_UID (regno) = INSN_UID (insn);
! 		    }
! 		}
! 		recurse = 0;
! 		break;
! 
! 	      case INSN_LIST:
! 		if (XEXP (x, 1))
! 		  FOR_EACH_RTX_PUSH (XEXP (x, 1));
! 		recurse = 0;
! 		break;
! 
! 	      case SET:
! 		/* Count a set of the destination if it is a register.  */
! 		for (dest = SET_DEST (x);
! 		     GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
! 		     || GET_CODE (dest) == ZERO_EXTEND;
! 		     dest = XEXP (dest, 0))
! 		  ;
! 
! 		if (GET_CODE (dest) == REG
! 		    && REGNO (dest) >= min_regno)
! 		  REG_N_SETS (REGNO (dest))++;
! 
! 		/* If this is setting a pseudo from another pseudo or the sum of a
! 		   pseudo and a constant integer and the other pseudo is known to be
! 		   a pointer, set the destination to be a pointer as well.
! 
! 		   Likewise if it is setting the destination from an address or from a
! 		   value equivalent to an address or to the sum of an address and
! 		   something else.
! 			       
! 		   But don't do any of this if the pseudo corresponds to a user
! 		   variable since it should have already been set as a pointer based
! 		   on the type.  */
! 
! 		if (GET_CODE (SET_DEST (x)) == REG
! 		    && REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER
! 		    && REGNO (SET_DEST (x)) >= min_regno
! 		    /* If the destination pseudo is set more than once, then other
! 		       sets might not be to a pointer value (consider access to a
! 		       union in two threads of control in the presense of global
! 		       optimizations).  So only set REGNO_POINTER_FLAG on the destination
! 		       pseudo if this is the only set of that pseudo.  */
! 		    && REG_N_SETS (REGNO (SET_DEST (x))) == 1
! 		    && ! REG_USERVAR_P (SET_DEST (x))
! 		    && ! REGNO_POINTER_FLAG (REGNO (SET_DEST (x)))
! 		    && ((GET_CODE (SET_SRC (x)) == REG
! 			 && REGNO_POINTER_FLAG (REGNO (SET_SRC (x))))
! 			|| ((GET_CODE (SET_SRC (x)) == PLUS
! 			     || GET_CODE (SET_SRC (x)) == LO_SUM)
! 			    && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
! 			    && GET_CODE (XEXP (SET_SRC (x), 0)) == REG
! 			    && REGNO_POINTER_FLAG (REGNO (XEXP (SET_SRC (x), 0))))
! 			|| GET_CODE (SET_SRC (x)) == CONST
! 			|| GET_CODE (SET_SRC (x)) == SYMBOL_REF
! 			|| GET_CODE (SET_SRC (x)) == LABEL_REF
! 			|| (GET_CODE (SET_SRC (x)) == HIGH
! 			    && (GET_CODE (XEXP (SET_SRC (x), 0)) == CONST
! 				|| GET_CODE (XEXP (SET_SRC (x), 0)) == SYMBOL_REF
! 				|| GET_CODE (XEXP (SET_SRC (x), 0)) == LABEL_REF))
! 			|| ((GET_CODE (SET_SRC (x)) == PLUS
! 			     || GET_CODE (SET_SRC (x)) == LO_SUM)
! 			    && (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST
! 				|| GET_CODE (XEXP (SET_SRC (x), 1)) == SYMBOL_REF
! 				|| GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF))
! 			|| ((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
! 			    && (GET_CODE (XEXP (note, 0)) == CONST
! 				|| GET_CODE (XEXP (note, 0)) == SYMBOL_REF
! 				|| GET_CODE (XEXP (note, 0)) == LABEL_REF))))
! 		  REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1;
! 
! 		break;
! 	      default:
! 		break;
  	      }
! 	 },
!      recurse);
  }
  
  /* Return nonzero if C1 is a subset of C2, i.e., if every register in C1
*** ../../egcs-20000918.orig/gcc/./reload1.c	Wed Sep 20 11:18:04 2000
--- ./reload1.c	Wed Sep 20 21:19:24 2000
*************** eliminate_regs (x, mem_mode, insn)
*** 2558,2756 ****
    return x;
  }
  
! /* Scan rtx X for modifications of elimination target registers.  Update
     the table of eliminables to reflect the changed state.  MEM_MODE is
     the mode of an enclosing MEM rtx, or VOIDmode if not within a MEM.  */
  
  static void
! elimination_effects (x, mem_mode)
!      rtx x;
       enum machine_mode mem_mode;
  
  {
!   enum rtx_code code = GET_CODE (x);
!   struct elim_table *ep;
!   int regno;
!   int i, j;
!   const char *fmt;
! 
!   switch (code)
!     {
!     case CONST_INT:
!     case CONST_DOUBLE:
!     case CONST:
!     case SYMBOL_REF:
!     case CODE_LABEL:
!     case PC:
!     case CC0:
!     case ASM_INPUT:
!     case ADDR_VEC:
!     case ADDR_DIFF_VEC:
!     case RETURN:
!       return;
! 
!     case ADDRESSOF:
!       abort ();
! 
!     case REG:
!       regno = REGNO (x);
! 
!       /* First handle the case where we encounter a bare register that
! 	 is eliminable.  Replace it with a PLUS.  */
!       if (regno < FIRST_PSEUDO_REGISTER)
! 	{
! 	  for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
! 	       ep++)
! 	    if (ep->from_rtx == x && ep->can_eliminate)
! 	      {
! 		if (! mem_mode)
! 		  ep->ref_outside_mem = 1;
! 		return;
! 	      }
  
! 	}
!       else if (reg_renumber[regno] < 0 && reg_equiv_constant
! 	       && reg_equiv_constant[regno]
! 	       && ! CONSTANT_P (reg_equiv_constant[regno]))
! 	elimination_effects (reg_equiv_constant[regno], mem_mode);
!       return;
! 
!     case PRE_INC:
!     case POST_INC:
!     case PRE_DEC:
!     case POST_DEC:
!     case POST_MODIFY:
!     case PRE_MODIFY:
!       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
! 	if (ep->to_rtx == XEXP (x, 0))
  	  {
! 	    int size = GET_MODE_SIZE (mem_mode);
! 
! 	    /* If more bytes than MEM_MODE are pushed, account for them.  */
! #ifdef PUSH_ROUNDING
! 	    if (ep->to_rtx == stack_pointer_rtx)
! 	      size = PUSH_ROUNDING (size);
! #endif
! 	    if (code == PRE_DEC || code == POST_DEC)
! 	      ep->offset += size;
! 	    else if (code == PRE_INC || code == POST_INC)
! 	      ep->offset -= size;
! 	    else if ((code == PRE_MODIFY || code == POST_MODIFY)
! 		     && GET_CODE (XEXP (x, 1)) == PLUS
! 		     && XEXP (x, 0) == XEXP (XEXP (x, 1), 0)
! 		     && CONSTANT_P (XEXP (XEXP (x, 1), 1)))
! 	      ep->offset -= INTVAL (XEXP (XEXP (x, 1), 1));
! 	  }
  
!       /* These two aren't unary operators.  */
!       if (code == POST_MODIFY || code == PRE_MODIFY)
! 	break;
! 
!       /* Fall through to generic unary operation case.  */
!     case STRICT_LOW_PART:
!     case NEG:          case NOT:
!     case SIGN_EXTEND:  case ZERO_EXTEND:
!     case TRUNCATE:     case FLOAT_EXTEND: case FLOAT_TRUNCATE:
!     case FLOAT:        case FIX:
!     case UNSIGNED_FIX: case UNSIGNED_FLOAT:
!     case ABS:
!     case SQRT:
!     case FFS:
!       elimination_effects (XEXP (x, 0), mem_mode);
!       return;
! 
!     case SUBREG:
!       if (GET_CODE (SUBREG_REG (x)) == REG
! 	  && (GET_MODE_SIZE (GET_MODE (x))
! 	      <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
! 	  && reg_equiv_memory_loc != 0
! 	  && reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0)
! 	return;
! 
!       elimination_effects (SUBREG_REG (x), mem_mode);
!       return;
! 
!     case USE:
!       /* If using a register that is the source of an eliminate we still
! 	 think can be performed, note it cannot be performed since we don't
! 	 know how this register is used.  */
!       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
! 	if (ep->from_rtx == XEXP (x, 0))
! 	  ep->can_eliminate = 0;
! 
!       elimination_effects (XEXP (x, 0), mem_mode);
!       return;
! 
!     case CLOBBER:
!       /* If clobbering a register that is the replacement register for an
! 	 elimination we still think can be performed, note that it cannot
! 	 be performed.  Otherwise, we need not be concerned about it.  */
!       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
! 	if (ep->to_rtx == XEXP (x, 0))
! 	  ep->can_eliminate = 0;
! 
!       elimination_effects (XEXP (x, 0), mem_mode);
!       return;
! 
!     case SET:
!       /* Check for setting a register that we know about.  */
!       if (GET_CODE (SET_DEST (x)) == REG)
! 	{
! 	  /* See if this is setting the replacement register for an
! 	     elimination.
! 
! 	     If DEST is the hard frame pointer, we do nothing because we
! 	     assume that all assignments to the frame pointer are for
! 	     non-local gotos and are being done at a time when they are valid
! 	     and do not disturb anything else.  Some machines want to
! 	     eliminate a fake argument pointer (or even a fake frame pointer)
! 	     with either the real frame or the stack pointer.  Assignments to
! 	     the hard frame pointer must not prevent this elimination.  */
! 
! 	  for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
! 	       ep++)
! 	    if (ep->to_rtx == SET_DEST (x)
! 		&& SET_DEST (x) != hard_frame_pointer_rtx)
  	      {
! 		/* If it is being incremented, adjust the offset.  Otherwise,
! 		   this elimination can't be done.  */
! 		rtx src = SET_SRC (x);
! 
! 		if (GET_CODE (src) == PLUS
! 		    && XEXP (src, 0) == SET_DEST (x)
! 		    && GET_CODE (XEXP (src, 1)) == CONST_INT)
! 		  ep->offset -= INTVAL (XEXP (src, 1));
! 		else
! 		  ep->can_eliminate = 0;
  	      }
! 	}
  
!       elimination_effects (SET_DEST (x), 0);
!       elimination_effects (SET_SRC (x), 0);
!       return;
! 
!     case MEM:
!       if (GET_CODE (XEXP (x, 0)) == ADDRESSOF)
! 	abort ();
! 
!       /* Our only special processing is to pass the mode of the MEM to our
! 	 recursive call.  */
!       elimination_effects (XEXP (x, 0), GET_MODE (x));
!       return;
! 
!     default:
!       break;
!     }
! 
!   fmt = GET_RTX_FORMAT (code);
!   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
!     {
!       if (*fmt == 'e')
! 	elimination_effects (XEXP (x, i), mem_mode);
!       else if (*fmt == 'E')
! 	for (j = 0; j < XVECLEN (x, i); j++)
! 	  elimination_effects (XVECEXP (x, i, j), mem_mode);
!     }
  }
  
  /* Descend through rtx X and verify that no references to eliminable registers
--- 2558,2736 ----
    return x;
  }
  
! /* Scan rtx EXP for modifications of elimination target registers.  Update
     the table of eliminables to reflect the changed state.  MEM_MODE is
     the mode of an enclosing MEM rtx, or VOIDmode if not within a MEM.  */
  
+ /* We can't use directives nested inside macro operand.  */
+ #ifndef PUSH_ROUNDING
+ #define MAYBE_PUSH_ROUNDING(x) x
+ #else
+ #define MAYBE_PUSH_ROUNDING(x) PUSH_ROUNDING(x)
+ #endif
+ 
  static void
! elimination_effects (exp, mem_mode)
!      rtx exp;
       enum machine_mode mem_mode;
  
  {
!   int recurse;
!   FOR_EACH_RTX
!     (exp, x,
!       {
! 	enum rtx_code code = GET_CODE (x);
! 	struct elim_table *ep;
! 	int regno;
! 	recurse = 1;
  
! 	switch (code)
  	  {
! 	  case CONST_INT:
! 	  case CONST_DOUBLE:
! 	  case CONST:
! 	  case SYMBOL_REF:
! 	  case CODE_LABEL:
! 	  case PC:
! 	  case CC0:
! 	  case ASM_INPUT:
! 	  case ADDR_VEC:
! 	  case ADDR_DIFF_VEC:
! 	  case RETURN:
! 	    recurse = 0;
! 	    break;
! 
! 	  case ADDRESSOF:
! 	    abort ();
! 
! 	  case REG:
! 	    regno = REGNO (x);
! 
! 	    /* First handle the case where we encounter a bare register that
! 	       is eliminable.  Replace it with a PLUS.  */
! 	    if (regno < FIRST_PSEUDO_REGISTER)
! 	      {
! 		for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
! 		     ep++)
! 		  if (ep->from_rtx == x && ep->can_eliminate)
! 		    {
! 		      if (! mem_mode)
! 			ep->ref_outside_mem = 1;
! 		      break;
! 		      return;
! 		    }
  
! 	      }
! 	    else if (reg_renumber[regno] < 0 && reg_equiv_constant
! 		     && reg_equiv_constant[regno]
! 		     && ! CONSTANT_P (reg_equiv_constant[regno]))
! 	      elimination_effects (reg_equiv_constant[regno], mem_mode);
! 	    recurse = 0;
! 	    break;
! 
! 	  case PRE_INC:
! 	  case POST_INC:
! 	  case PRE_DEC:
! 	  case POST_DEC:
! 	  case POST_MODIFY:
! 	  case PRE_MODIFY:
! 	    for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
! 	      if (ep->to_rtx == XEXP (x, 0))
! 		{
! 		  int size = GET_MODE_SIZE (mem_mode);
! 
! 		  /* If more bytes than MEM_MODE are pushed, account for them.  */
! 		  if (ep->to_rtx == stack_pointer_rtx)
! 		    size = MAYBE_PUSH_ROUNDING (size);
! 		  if (code == PRE_DEC || code == POST_DEC)
! 		    ep->offset += size;
! 		  else if (code == PRE_INC || code == POST_INC)
! 		    ep->offset -= size;
! 		  else if ((code == PRE_MODIFY || code == POST_MODIFY)
! 			   && GET_CODE (XEXP (x, 1)) == PLUS
! 			   && XEXP (x, 0) == XEXP (XEXP (x, 1), 0)
! 			   && CONSTANT_P (XEXP (XEXP (x, 1), 1)))
! 		    ep->offset -= INTVAL (XEXP (XEXP (x, 1), 1));
! 		}
! 	    break;
! 
! 	  case SUBREG:
! 	    if (GET_CODE (SUBREG_REG (x)) == REG
! 		&& (GET_MODE_SIZE (GET_MODE (x))
! 		    <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
! 		&& reg_equiv_memory_loc != 0
! 		&& reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0)
! 	      recurse = 0;
! 	    break;
! 
! 	  case USE:
! 	    /* If using a register that is the source of an eliminate we still
! 	       think can be performed, note it cannot be performed since we don't
! 	       know how this register is used.  */
! 	    for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
! 	      if (ep->from_rtx == XEXP (x, 0))
! 		ep->can_eliminate = 0;
! 	    break;
! 
! 	  case CLOBBER:
! 	    /* If clobbering a register that is the replacement register for an
! 	       elimination we still think can be performed, note that it cannot
! 	       be performed.  Otherwise, we need not be concerned about it.  */
! 	    for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
! 	      if (ep->to_rtx == XEXP (x, 0))
! 		ep->can_eliminate = 0;
! 
! 	    break;
! 
! 	  case SET:
! 	    /* Check for setting a register that we know about.  */
! 	    if (GET_CODE (SET_DEST (x)) == REG)
  	      {
! 		/* See if this is setting the replacement register for an
! 		   elimination.
! 
! 		   If DEST is the hard frame pointer, we do nothing because we
! 		   assume that all assignments to the frame pointer are for
! 		   non-local gotos and are being done at a time when they are valid
! 		   and do not disturb anything else.  Some machines want to
! 		   eliminate a fake argument pointer (or even a fake frame pointer)
! 		   with either the real frame or the stack pointer.  Assignments to
! 		   the hard frame pointer must not prevent this elimination.  */
! 
! 		for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
! 		     ep++)
! 		  if (ep->to_rtx == SET_DEST (x)
! 		      && SET_DEST (x) != hard_frame_pointer_rtx)
! 		    {
! 		      /* If it is being incremented, adjust the offset.  Otherwise,
! 			 this elimination can't be done.  */
! 		      rtx src = SET_SRC (x);
! 
! 		      if (GET_CODE (src) == PLUS
! 			  && XEXP (src, 0) == SET_DEST (x)
! 			  && GET_CODE (XEXP (src, 1)) == CONST_INT)
! 			ep->offset -= INTVAL (XEXP (src, 1));
! 		      else
! 			ep->can_eliminate = 0;
! 		    }
  	      }
! 	    break;
! 
! 	  case MEM:
! 	    if (GET_CODE (XEXP (x, 0)) == ADDRESSOF)
! 	      abort ();
! 
! 	    /* Our only special processing is to pass the mode of the MEM to our
! 	       recursive call.  */
! 	    elimination_effects (XEXP (x, 0), GET_MODE (x));
! 	    recurse = 0;
! 	    return;
  
! 	  default:
! 	    break;
! 	  }
!       },
!     recurse);
  }
  
  /* Descend through rtx X and verify that no references to eliminable registers
*** ../../egcs-20000918.orig/gcc/./rtlanal.c	Wed Sep 20 11:18:04 2000
--- ./rtlanal.c	Wed Sep 20 21:19:24 2000
*************** for_each_rtx (x, f, data)
*** 2278,2335 ****
       rtx_function f;
       void *data;
  {
!   int result;
!   int length;
!   const char* format;
!   int i;
! 
!   /* Call F on X.  */
!   result = (*f)(x, data);
!   if (result == -1)
!     /* Do not traverse sub-expressions.  */
!     return 0;
!   else if (result != 0)
!     /* Stop the traversal.  */
!     return result;
! 
!   if (*x == NULL_RTX)
!     /* There are no sub-expressions.  */
!     return 0;
! 
!   length = GET_RTX_LENGTH (GET_CODE (*x));
!   format = GET_RTX_FORMAT (GET_CODE (*x));
! 
!   for (i = 0; i < length; ++i) 
!     {
!       switch (format[i]) 
! 	{
! 	case 'e':
! 	  result = for_each_rtx (&XEXP (*x, i), f, data);
! 	  if (result != 0)
! 	    return result;
! 	  break;
! 
! 	case 'V':
! 	case 'E':
! 	  if (XVEC (*x, i) != 0) 
! 	    {
! 	      int j;
! 	      for (j = 0; j < XVECLEN (*x, i); ++j)
! 		{
! 		  result = for_each_rtx (&XVECEXP (*x, i, j), f, data);
! 		  if (result != 0)
! 		    return result;
! 		}
! 	    }
! 	  break; 
! 
! 	default:
! 	  /* Nothing to do.  */
! 	  break;
! 	}
! 
!     }
! 
    return 0;
  }
  
--- 2366,2380 ----
       rtx_function f;
       void *data;
  {
!   int current;
!   FOR_EACH_RTXP
!     (x, rtxp,
!       {
! 	current = (*f) (rtxp, data);
! 	if (current && current != -1)
! 	  return current;
!       },
!      !current);
    return 0;
  }
  

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