This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
More on addressof: how to fix the backends that use them?
- From: Steven Bosscher <stevenb at suse dot de>
- To: gcc at gcc dot gnu dot org
- Cc: jh at suse dot cz
- Date: Tue, 1 Jun 2004 23:34:13 +0200
- Subject: More on addressof: how to fix the backends that use them?
- Organization: SUSE Labs
Hi,
Before we can even consider removing addresof, there still
are two backends that build ADDRESSOF rtxes: alpha and ia64.
For example, alpha.c uses it as follows:
/* Return or create a pseudo containing the gp value for the current
function. Needed only if TARGET_LD_BUGGY_LDGP. */
rtx
alpha_gp_save_rtx (void)
{
rtx r = get_hard_reg_initial_val (DImode, 29);
if (GET_CODE (r) != MEM)
r = gen_mem_addressof (r, NULL_TREE, /*rescan=*/true);
return r;
}
What can this code be replaced with such that it does not
create an ADDRESSOF?
I've attached an updated version of Honza's patch from some time
ago (http://gcc.gnu.org/ml/gcc-patches/2004-02/msg01417.html) for
those who are interested.
Gr.
Steven
Index: function.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.c,v
retrieving revision 1.518
diff -c -3 -p -r1.518 function.c
*** function.c 20 May 2004 17:37:02 -0000 1.518
--- function.c 1 Jun 2004 21:28:11 -0000
*************** static int contains (rtx, varray_type);
*** 264,280 ****
#ifdef HAVE_return
static void emit_return_into_block (basic_block, rtx);
#endif
- static void put_addressof_into_stack (rtx, htab_t);
- static bool purge_addressof_1 (rtx *, rtx, int, int, int, htab_t);
- static void purge_single_hard_subreg_set (rtx);
#if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
static rtx keep_stack_depressed (rtx);
#endif
- static int is_addressof (rtx *, void *);
- static hashval_t insns_for_mem_hash (const void *);
- static int insns_for_mem_comp (const void *, const void *);
- static int insns_for_mem_walk (rtx *, void *);
- static void compute_insns_for_mem (rtx, rtx, htab_t);
static void prepare_function_start (tree);
static void do_clobber_return_reg (rtx, void *);
static void do_use_return_reg (rtx, void *);
--- 264,272 ----
*************** static void set_insn_locators (rtx, int)
*** 285,293 ****
/* Pointer to chain of `struct function' for containing functions. */
struct function *outer_function_chain;
- /* List of insns that were postponed by purge_addressof_1. */
- static rtx postponed_insns;
-
/* Given a function decl for a containing function,
return the `struct function' for it. */
--- 277,282 ----
*************** put_var_into_stack (tree decl, int resca
*** 1368,1374 ****
enum machine_mode promoted_mode, decl_mode;
struct function *function = 0;
tree context;
- bool can_use_addressof_p;
bool volatile_p = TREE_CODE (decl) != SAVE_EXPR && TREE_THIS_VOLATILE (decl);
bool used_p = (TREE_USED (decl)
|| (TREE_CODE (decl) != SAVE_EXPR && DECL_INITIAL (decl) != 0));
--- 1357,1362 ----
*************** put_var_into_stack (tree decl, int resca
*** 1414,1455 ****
decl_mode = promoted_mode = GET_MODE (reg);
}
- /* If this variable lives in the current function and we don't need to put it
- in the stack for the sake of setjmp or the non-locality, try to keep it in
- a register until we know we actually need the address. */
- can_use_addressof_p
- = (function == 0
- && ! (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl))
- && optimize > 0
- /* FIXME make it work for promoted modes too */
- && decl_mode == promoted_mode
- #ifdef NON_SAVING_SETJMP
- && ! (NON_SAVING_SETJMP && current_function_calls_setjmp)
- #endif
- );
-
- /* If we can't use ADDRESSOF, make sure we see through one we already
- generated. */
- if (! can_use_addressof_p
- && GET_CODE (reg) == MEM
- && GET_CODE (XEXP (reg, 0)) == ADDRESSOF)
- reg = XEXP (XEXP (reg, 0), 0);
-
/* Now we should have a value that resides in one or more pseudo regs. */
if (GET_CODE (reg) == REG)
{
! if (can_use_addressof_p)
! gen_mem_addressof (reg, decl, rescan);
! else
! put_reg_into_stack (function, reg, TREE_TYPE (decl), decl_mode,
! 0, volatile_p, used_p, false, 0);
!
! /* If this was previously a MEM but we've removed the ADDRESSOF,
! set this address into that MEM so we always use the same
! rtx for this variable. */
! if (orig_reg != reg && GET_CODE (orig_reg) == MEM)
! XEXP (orig_reg, 0) = XEXP (reg, 0);
}
else if (GET_CODE (reg) == CONCAT)
{
--- 1402,1413 ----
decl_mode = promoted_mode = GET_MODE (reg);
}
/* Now we should have a value that resides in one or more pseudo regs. */
if (GET_CODE (reg) == REG)
{
! put_reg_into_stack (function, reg, TREE_TYPE (decl), decl_mode,
! 0, volatile_p, used_p, false, 0);
}
else if (GET_CODE (reg) == CONCAT)
{
*************** static int cfa_offset;
*** 2916,3557 ****
#define ARG_POINTER_CFA_OFFSET(FNDECL) FIRST_PARM_OFFSET (FNDECL)
#endif
- /* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just
- had its address taken. DECL is the decl or SAVE_EXPR for the
- object stored in the register, for later use if we do need to force
- REG into the stack. REG is overwritten by the MEM like in
- put_reg_into_stack. RESCAN is true if previously emitted
- instructions must be rescanned and modified now that the REG has
- been transformed. */
-
- rtx
- gen_mem_addressof (rtx reg, tree decl, int rescan)
- {
- rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)),
- REGNO (reg), decl);
-
- /* Calculate this before we start messing with decl's RTL. */
- HOST_WIDE_INT set = decl ? get_alias_set (decl) : 0;
-
- /* If the original REG was a user-variable, then so is the REG whose
- address is being taken. Likewise for unchanging. */
- REG_USERVAR_P (XEXP (r, 0)) = REG_USERVAR_P (reg);
- RTX_UNCHANGING_P (XEXP (r, 0)) = RTX_UNCHANGING_P (reg);
-
- PUT_CODE (reg, MEM);
- MEM_VOLATILE_P (reg) = 0;
- MEM_ATTRS (reg) = 0;
- XEXP (reg, 0) = r;
-
- if (decl)
- {
- tree type = TREE_TYPE (decl);
- enum machine_mode decl_mode
- = (DECL_P (decl) ? DECL_MODE (decl) : TYPE_MODE (TREE_TYPE (decl)));
- rtx decl_rtl = (TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl)
- : DECL_RTL_IF_SET (decl));
-
- PUT_MODE (reg, decl_mode);
-
- /* Clear DECL_RTL momentarily so functions below will work
- properly, then set it again. */
- if (DECL_P (decl) && decl_rtl == reg)
- SET_DECL_RTL (decl, 0);
-
- set_mem_attributes (reg, decl, 1);
- set_mem_alias_set (reg, set);
-
- if (DECL_P (decl) && decl_rtl == reg)
- SET_DECL_RTL (decl, reg);
-
- if (rescan
- && (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0)))
- fixup_var_refs (reg, GET_MODE (reg), TYPE_UNSIGNED (type), reg, 0);
- }
- else if (rescan)
- {
- /* This can only happen during reload. Clear the same flag bits as
- reload. */
- RTX_UNCHANGING_P (reg) = 0;
- MEM_IN_STRUCT_P (reg) = 0;
- MEM_SCALAR_P (reg) = 0;
-
- fixup_var_refs (reg, GET_MODE (reg), 0, reg, 0);
- }
-
- return reg;
- }
-
- /* If DECL has an RTL that is an ADDRESSOF rtx, put it into the stack. */
-
- void
- flush_addressof (tree decl)
- {
- if ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL)
- && DECL_RTL (decl) != 0
- && GET_CODE (DECL_RTL (decl)) == MEM
- && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF
- && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == REG)
- put_addressof_into_stack (XEXP (DECL_RTL (decl), 0), 0);
- }
-
- /* Force the register pointed to by R, an ADDRESSOF rtx, into the stack. */
-
- static void
- put_addressof_into_stack (rtx r, htab_t ht)
- {
- tree decl, type;
- bool volatile_p, used_p;
-
- rtx reg = XEXP (r, 0);
-
- if (GET_CODE (reg) != REG)
- abort ();
-
- decl = ADDRESSOF_DECL (r);
- if (decl)
- {
- type = TREE_TYPE (decl);
- volatile_p = (TREE_CODE (decl) != SAVE_EXPR
- && TREE_THIS_VOLATILE (decl));
- used_p = (TREE_USED (decl)
- || (DECL_P (decl) && DECL_INITIAL (decl) != 0));
- }
- else
- {
- type = NULL_TREE;
- volatile_p = false;
- used_p = true;
- }
-
- put_reg_into_stack (0, reg, type, GET_MODE (reg), ADDRESSOF_REGNO (r),
- volatile_p, used_p, false, ht);
- }
-
- /* List of replacements made below in purge_addressof_1 when creating
- bitfield insertions. */
- static rtx purge_bitfield_addressof_replacements;
-
- /* List of replacements made below in purge_addressof_1 for patterns
- (MEM (ADDRESSOF (REG ...))). The key of the list entry is the
- corresponding (ADDRESSOF (REG ...)) and value is a substitution for
- the all pattern. List PURGE_BITFIELD_ADDRESSOF_REPLACEMENTS is not
- enough in complex cases, e.g. when some field values can be
- extracted by usage MEM with narrower mode. */
- static rtx purge_addressof_replacements;
-
- /* Helper function for purge_addressof. See if the rtx expression at *LOC
- in INSN needs to be changed. If FORCE, always put any ADDRESSOFs into
- the stack. If the function returns FALSE then the replacement could not
- be made. If MAY_POSTPONE is true and we would not put the addressof
- to stack, postpone processing of the insn. */
-
- static bool
- purge_addressof_1 (rtx *loc, rtx insn, int force, int store, int may_postpone,
- htab_t ht)
- {
- rtx x;
- RTX_CODE code;
- int i, j;
- const char *fmt;
- bool result = true;
- bool libcall = false;
-
- /* Re-start here to avoid recursion in common cases. */
- restart:
-
- x = *loc;
- if (x == 0)
- return true;
-
- /* Is this a libcall? */
- if (!insn)
- libcall = REG_NOTE_KIND (*loc) == REG_RETVAL;
-
- code = GET_CODE (x);
-
- /* If we don't return in any of the cases below, we will recurse inside
- the RTX, which will normally result in any ADDRESSOF being forced into
- memory. */
- if (code == SET)
- {
- result = purge_addressof_1 (&SET_DEST (x), insn, force, 1,
- may_postpone, ht);
- result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0,
- may_postpone, ht);
- return result;
- }
- else if (code == ADDRESSOF)
- {
- rtx sub, insns;
-
- if (GET_CODE (XEXP (x, 0)) != MEM)
- put_addressof_into_stack (x, ht);
-
- /* We must create a copy of the rtx because it was created by
- overwriting a REG rtx which is always shared. */
- sub = copy_rtx (XEXP (XEXP (x, 0), 0));
- if (validate_change (insn, loc, sub, 0)
- || validate_replace_rtx (x, sub, insn))
- return true;
-
- start_sequence ();
-
- /* If SUB is a hard or virtual register, try it as a pseudo-register.
- Otherwise, perhaps SUB is an expression, so generate code to compute
- it. */
- if (GET_CODE (sub) == REG && REGNO (sub) <= LAST_VIRTUAL_REGISTER)
- sub = copy_to_reg (sub);
- else
- sub = force_operand (sub, NULL_RTX);
-
- if (! validate_change (insn, loc, sub, 0)
- && ! validate_replace_rtx (x, sub, insn))
- abort ();
-
- insns = get_insns ();
- end_sequence ();
- emit_insn_before (insns, insn);
- return true;
- }
-
- else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force)
- {
- rtx sub = XEXP (XEXP (x, 0), 0);
-
- if (GET_CODE (sub) == MEM)
- sub = adjust_address_nv (sub, GET_MODE (x), 0);
- else if (GET_CODE (sub) == REG
- && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
- ;
- else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
- {
- int size_x, size_sub;
-
- if (may_postpone)
- {
- /* Postpone for now, so that we do not emit bitfield arithmetics
- unless there is some benefit from it. */
- if (!postponed_insns || XEXP (postponed_insns, 0) != insn)
- postponed_insns = alloc_INSN_LIST (insn, postponed_insns);
- return true;
- }
-
- if (!insn)
- {
- /* When processing REG_NOTES look at the list of
- replacements done on the insn to find the register that X
- was replaced by. */
- rtx tem;
-
- for (tem = purge_bitfield_addressof_replacements;
- tem != NULL_RTX;
- tem = XEXP (XEXP (tem, 1), 1))
- if (rtx_equal_p (x, XEXP (tem, 0)))
- {
- *loc = XEXP (XEXP (tem, 1), 0);
- return true;
- }
-
- /* See comment for purge_addressof_replacements. */
- for (tem = purge_addressof_replacements;
- tem != NULL_RTX;
- tem = XEXP (XEXP (tem, 1), 1))
- if (rtx_equal_p (XEXP (x, 0), XEXP (tem, 0)))
- {
- rtx z = XEXP (XEXP (tem, 1), 0);
-
- if (GET_MODE (x) == GET_MODE (z)
- || (GET_CODE (XEXP (XEXP (tem, 1), 0)) != REG
- && GET_CODE (XEXP (XEXP (tem, 1), 0)) != SUBREG))
- abort ();
-
- /* It can happen that the note may speak of things
- in a wider (or just different) mode than the
- code did. This is especially true of
- REG_RETVAL. */
-
- if (GET_CODE (z) == SUBREG && SUBREG_BYTE (z) == 0)
- z = SUBREG_REG (z);
-
- if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (x))
- > GET_MODE_SIZE (GET_MODE (z))))
- {
- /* This can occur as a result in invalid
- pointer casts, e.g. float f; ...
- *(long long int *)&f.
- ??? We could emit a warning here, but
- without a line number that wouldn't be
- very helpful. */
- z = gen_rtx_SUBREG (GET_MODE (x), z, 0);
- }
- else
- z = gen_lowpart (GET_MODE (x), z);
-
- *loc = z;
- return true;
- }
-
- /* When we are processing the REG_NOTES of the last instruction
- of a libcall, there will be typically no replacements
- for that insn; the replacements happened before, piecemeal
- fashion. OTOH we are not interested in the details of
- this for the REG_EQUAL note, we want to know the big picture,
- which can be succinctly described with a simple SUBREG.
- Note that removing the REG_EQUAL note is not an option
- on the last insn of a libcall, so we must do a replacement. */
-
- /* In compile/990107-1.c:7 compiled at -O1 -m1 for sh-elf,
- we got
- (mem:DI (addressof:SI (reg/v:DF 160) 159 0x401c8510)
- [0 S8 A32]), which can be expressed with a simple
- same-size subreg */
- if ((GET_MODE_SIZE (GET_MODE (x))
- <= GET_MODE_SIZE (GET_MODE (sub)))
- /* Again, invalid pointer casts (as in
- compile/990203-1.c) can require paradoxical
- subregs. */
- || (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (x))
- > GET_MODE_SIZE (GET_MODE (sub)))
- && libcall))
- {
- *loc = gen_rtx_SUBREG (GET_MODE (x), sub, 0);
- return true;
- }
- /* ??? Are there other cases we should handle? */
-
- /* Sometimes we may not be able to find the replacement. For
- example when the original insn was a MEM in a wider mode,
- and the note is part of a sign extension of a narrowed
- version of that MEM. Gcc testcase compile/990829-1.c can
- generate an example of this situation. Rather than complain
- we return false, which will prompt our caller to remove the
- offending note. */
- return false;
- }
-
- size_x = GET_MODE_BITSIZE (GET_MODE (x));
- size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
-
- /* Do not frob unchanging MEMs. If a later reference forces the
- pseudo to the stack, we can wind up with multiple writes to
- an unchanging memory, which is invalid. */
- if (RTX_UNCHANGING_P (x) && size_x != size_sub)
- ;
-
- /* Don't even consider working with paradoxical subregs,
- or the moral equivalent seen here. */
- else if (size_x <= size_sub
- && int_mode_for_mode (GET_MODE (sub)) != BLKmode)
- {
- /* Do a bitfield insertion to mirror what would happen
- in memory. */
-
- rtx val, seq;
-
- if (store)
- {
- rtx p = PREV_INSN (insn);
-
- start_sequence ();
- val = gen_reg_rtx (GET_MODE (x));
- if (! validate_change (insn, loc, val, 0))
- {
- /* Discard the current sequence and put the
- ADDRESSOF on stack. */
- end_sequence ();
- goto give_up;
- }
- seq = get_insns ();
- end_sequence ();
- emit_insn_before (seq, insn);
- compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (),
- insn, ht);
-
- start_sequence ();
- store_bit_field (sub, size_x, 0, GET_MODE (x),
- val, GET_MODE_SIZE (GET_MODE (sub)));
-
- /* Make sure to unshare any shared rtl that store_bit_field
- might have created. */
- unshare_all_rtl_again (get_insns ());
-
- seq = get_insns ();
- end_sequence ();
- p = emit_insn_after (seq, insn);
- if (NEXT_INSN (insn))
- compute_insns_for_mem (NEXT_INSN (insn),
- p ? NEXT_INSN (p) : NULL_RTX,
- ht);
- }
- else
- {
- rtx p = PREV_INSN (insn);
-
- start_sequence ();
- val = extract_bit_field (sub, size_x, 0, 1, NULL_RTX,
- GET_MODE (x), GET_MODE (x),
- GET_MODE_SIZE (GET_MODE (sub)));
-
- if (! validate_change (insn, loc, val, 0))
- {
- /* Discard the current sequence and put the
- ADDRESSOF on stack. */
- end_sequence ();
- goto give_up;
- }
-
- seq = get_insns ();
- end_sequence ();
- emit_insn_before (seq, insn);
- compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (),
- insn, ht);
- }
-
- /* Remember the replacement so that the same one can be done
- on the REG_NOTES. */
- purge_bitfield_addressof_replacements
- = gen_rtx_EXPR_LIST (VOIDmode, x,
- gen_rtx_EXPR_LIST
- (VOIDmode, val,
- purge_bitfield_addressof_replacements));
-
- /* We replaced with a reg -- all done. */
- return true;
- }
- }
-
- else if (validate_change (insn, loc, sub, 0))
- {
- /* Remember the replacement so that the same one can be done
- on the REG_NOTES. */
- if (GET_CODE (sub) == REG || GET_CODE (sub) == SUBREG)
- {
- rtx tem;
-
- for (tem = purge_addressof_replacements;
- tem != NULL_RTX;
- tem = XEXP (XEXP (tem, 1), 1))
- if (rtx_equal_p (XEXP (x, 0), XEXP (tem, 0)))
- {
- XEXP (XEXP (tem, 1), 0) = sub;
- return true;
- }
- purge_addressof_replacements
- = gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0),
- gen_rtx_EXPR_LIST (VOIDmode, sub,
- purge_addressof_replacements));
- return true;
- }
- goto restart;
- }
- }
-
- give_up:
- /* Scan all subexpressions. */
- fmt = GET_RTX_FORMAT (code);
- for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
- {
- if (*fmt == 'e')
- result &= purge_addressof_1 (&XEXP (x, i), insn, force, 0,
- may_postpone, ht);
- else if (*fmt == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- result &= purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0,
- may_postpone, ht);
- }
-
- return result;
- }
-
- /* Return a hash value for K, a REG. */
-
- static hashval_t
- insns_for_mem_hash (const void *k)
- {
- /* Use the address of the key for the hash value. */
- struct insns_for_mem_entry *m = (struct insns_for_mem_entry *) k;
- return htab_hash_pointer (m->key);
- }
-
- /* Return nonzero if K1 and K2 (two REGs) are the same. */
-
- static int
- insns_for_mem_comp (const void *k1, const void *k2)
- {
- struct insns_for_mem_entry *m1 = (struct insns_for_mem_entry *) k1;
- struct insns_for_mem_entry *m2 = (struct insns_for_mem_entry *) k2;
- return m1->key == m2->key;
- }
-
- struct insns_for_mem_walk_info
- {
- /* The hash table that we are using to record which INSNs use which
- MEMs. */
- htab_t ht;
-
- /* The INSN we are currently processing. */
- 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 (rtx *r, void *data)
- {
- struct insns_for_mem_walk_info *ifmwi
- = (struct insns_for_mem_walk_info *) data;
- struct insns_for_mem_entry tmp;
- tmp.insns = NULL_RTX;
-
- if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF
- && GET_CODE (XEXP (*r, 0)) == REG)
- {
- void **e;
- tmp.key = XEXP (*r, 0);
- e = htab_find_slot (ifmwi->ht, &tmp, INSERT);
- if (*e == NULL)
- {
- *e = ggc_alloc (sizeof (tmp));
- memcpy (*e, &tmp, sizeof (tmp));
- }
- }
- else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG)
- {
- struct insns_for_mem_entry *ifme;
- tmp.key = *r;
- ifme = htab_find (ifmwi->ht, &tmp);
-
- /* 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))
- ifme->insns = gen_rtx_EXPR_LIST (VOIDmode, ifmwi->insn,
- ifme->insns);
- }
-
- return 0;
- }
-
- /* Walk the INSNS, until we reach LAST_INSN, recording which INSNs use
- which REGs in HT. */
-
- static void
- compute_insns_for_mem (rtx insns, rtx last_insn, htab_t 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.
- Returns true iff the rtl is an ADDRESSOF. */
-
- static int
- is_addressof (rtx *rtl, void *data ATTRIBUTE_UNUSED)
- {
- return GET_CODE (*rtl) == ADDRESSOF;
- }
-
- /* Eliminate all occurrences of ADDRESSOF from INSNS. Elide any remaining
- (MEM (ADDRESSOF)) patterns, and force any needed registers into the
- stack. */
-
- void
- purge_addressof (rtx insns)
- {
- rtx insn, tmp;
- htab_t ht;
-
- /* When we actually purge ADDRESSOFs, we turn REGs into MEMs. That
- requires a fixup pass over the instruction stream to correct
- INSNs that depended on the REG being a REG, and not a MEM. But,
- these fixup passes are slow. Furthermore, most MEMs are not
- mentioned in very many instructions. So, we speed up the process
- by pre-calculating which REGs occur in which INSNs; that allows
- us to perform the fixup passes much more quickly. */
- ht = htab_create_ggc (1000, insns_for_mem_hash, insns_for_mem_comp, NULL);
- compute_insns_for_mem (insns, NULL_RTX, ht);
-
- postponed_insns = NULL;
-
- for (insn = insns; insn; insn = NEXT_INSN (insn))
- if (INSN_P (insn))
- {
- if (! purge_addressof_1 (&PATTERN (insn), insn,
- asm_noperands (PATTERN (insn)) > 0, 0, 1, ht))
- /* If we could not replace the ADDRESSOFs in the insn,
- something is wrong. */
- abort ();
-
- if (! purge_addressof_1 (®_NOTES (insn), NULL_RTX, 0, 0, 0, ht))
- {
- /* If we could not replace the ADDRESSOFs in the insn's notes,
- we can just remove the offending notes instead. */
- rtx note;
-
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- {
- /* If we find a REG_RETVAL note then the insn is a libcall.
- Such insns must have REG_EQUAL notes as well, in order
- for later passes of the compiler to work. So it is not
- safe to delete the notes here, and instead we abort. */
- if (REG_NOTE_KIND (note) == REG_RETVAL)
- abort ();
- if (for_each_rtx (¬e, is_addressof, NULL))
- remove_note (insn, note);
- }
- }
- }
-
- /* Process the postponed insns. */
- while (postponed_insns)
- {
- insn = XEXP (postponed_insns, 0);
- tmp = postponed_insns;
- postponed_insns = XEXP (postponed_insns, 1);
- free_INSN_LIST_node (tmp);
-
- if (! purge_addressof_1 (&PATTERN (insn), insn,
- asm_noperands (PATTERN (insn)) > 0, 0, 0, ht))
- abort ();
- }
-
- /* Clean up. */
- purge_bitfield_addressof_replacements = 0;
- purge_addressof_replacements = 0;
-
- /* REGs are shared. purge_addressof will destructively replace a REG
- with a MEM, which creates shared MEMs.
-
- Unfortunately, the children of put_reg_into_stack assume that MEMs
- referring to the same stack slot are shared (fixup_var_refs and
- the associated hash table code).
-
- So, we have to do another unsharing pass after we have flushed any
- REGs that had their address taken into the stack.
-
- It may be worth tracking whether or not we converted any REGs into
- MEMs to avoid this overhead when it is not needed. */
- unshare_all_rtl_again (get_insns ());
- }
/* Convert a SET of a hard subreg to a set of the appropriate hard
register. A subroutine of purge_hard_subreg_sets. */
--- 2874,2879 ----
Index: passes.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/passes.c,v
retrieving revision 2.17
diff -c -3 -p -r2.17 passes.c
*** passes.c 30 May 2004 18:32:27 -0000 2.17
--- passes.c 1 Jun 2004 21:28:11 -0000
*************** enum dump_file_index
*** 138,144 ****
DFI_jump,
DFI_null,
DFI_cse,
- DFI_addressof,
DFI_gcse,
DFI_loop,
DFI_bypass,
--- 138,143 ----
*************** static struct dump_file_info dump_file_t
*** 192,198 ****
{ "jump", 'j', 0, 0, 0 },
{ "null", 'u', 0, 0, 0 },
{ "cse", 's', 0, 0, 0 },
- { "addressof", 'F', 0, 0, 0 },
{ "gcse", 'G', 1, 0, 0 },
{ "loop", 'L', 1, 0, 0 },
{ "bypass", 'G', 1, 0, 0 }, /* Yes, duplicate enable switch. */
--- 191,196 ----
*************** rest_of_handle_cfg (tree decl, rtx insns
*** 989,1008 ****
close_dump_file (DFI_cfg, print_rtl_with_bb, insns);
}
- /* Purge addressofs. */
- static void
- rest_of_handle_addressof (tree decl, rtx insns)
- {
- open_dump_file (DFI_addressof, decl);
-
- purge_addressof (insns);
- if (optimize && purge_all_dead_edges (0))
- delete_unreachable_blocks ();
- reg_scan (insns, max_reg_num (), 1);
-
- close_dump_file (DFI_addressof, print_rtl, insns);
- }
-
/* Perform jump bypassing and control flow optimizations. */
static void
rest_of_handle_jump_bypass (tree decl, rtx insns)
--- 987,992 ----
*************** rest_of_compilation (tree decl)
*** 1561,1568 ****
if (optimize > 0)
rest_of_handle_cse (decl, insns);
- rest_of_handle_addressof (decl, insns);
-
ggc_collect ();
if (optimize > 0)
--- 1545,1550 ----
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.477
diff -c -3 -p -r1.477 rtl.h
*** rtl.h 28 May 2004 06:27:31 -0000 1.477
--- rtl.h 1 Jun 2004 21:28:12 -0000
*************** extern rtx simplify_replace_rtx (rtx, rt
*** 1774,1782 ****
extern rtx simplify_rtx (rtx);
extern rtx avoid_constant_pool_reference (rtx);
- /* In function.c */
- extern rtx gen_mem_addressof (rtx, tree, int);
-
/* In regclass.c */
extern enum machine_mode choose_hard_reg_mode (unsigned int, unsigned int,
bool);
--- 1774,1779 ----
*************** extern int sibcall_epilogue_contains (rt
*** 2249,2255 ****
extern void preserve_rtl_expr_result (rtx);
extern void mark_temp_addr_taken (rtx);
extern void update_temp_slot_address (rtx, rtx);
- extern void purge_addressof (rtx);
extern void purge_hard_subreg_sets (rtx);
/* In stmt.c */
--- 2246,2251 ----
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.503
diff -c -3 -p -r1.503 tree.h
*** tree.h 30 May 2004 18:32:31 -0000 1.503
--- tree.h 1 Jun 2004 21:28:12 -0000
*************** extern void allocate_struct_function (tr
*** 3538,3544 ****
extern void init_function_start (tree);
extern void assign_parms (tree);
extern void put_var_into_stack (tree, int);
- extern void flush_addressof (tree);
extern void setjmp_vars_warning (tree);
extern void setjmp_args_warning (void);
extern void init_temp_slots (void);
--- 3538,3543 ----