This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
FOR_EACH_RTX usage
- To: gcc-patches at gcc dot gnu dot org, rth at cygnus dot com
- Subject: FOR_EACH_RTX usage
- From: Jan Hubicka <jh at suse dot cz>
- Date: Wed, 20 Sep 2000 21:45:32 +0200
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 < ®_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 < ®_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 < ®_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 < ®_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 < ®_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 < ®_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 < ®_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 < ®_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 < ®_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 < ®_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;
}