Commit bbf9b913 by Richard Henderson Committed by Richard Henderson

function.c (instantiate_decls): Remove valid_only argument.

        * function.c (instantiate_decls): Remove valid_only argument.
        (instantiate_decls_1, instantiate_decl): Likewise.
        (instantiate_virtual_regs_1): Delete.
        (instantiate_virtual_regs_lossage): Delete.
        (instantiate_virtual_regs_in_rtx): New.
        (safe_insn_predicate): New.
        (instantiate_virtual_regs_in_insn): New.
        (instantiate_virtual_regs): Update to match all that.  Only run
        instantiate_decls once.

From-SVN: r99032
parent afd4e048
2005-04-29 Richard Henderson <rth@redhat.com> 2005-04-29 Richard Henderson <rth@redhat.com>
* function.c (instantiate_decls): Remove valid_only argument.
(instantiate_decls_1, instantiate_decl): Likewise.
(instantiate_virtual_regs_1): Delete.
(instantiate_virtual_regs_lossage): Delete.
(instantiate_virtual_regs_in_rtx): New.
(safe_insn_predicate): New.
(instantiate_virtual_regs_in_insn): New.
(instantiate_virtual_regs): Update to match all that. Only run
instantiate_decls once.
2005-04-29 Richard Henderson <rth@redhat.com>
Daniel Jacobowitz <dan@codesourcery.com> Daniel Jacobowitz <dan@codesourcery.com>
* gengtype.c (write_func_for_structure): Split out ... * gengtype.c (write_func_for_structure): Split out ...
......
...@@ -189,11 +189,6 @@ struct temp_slot GTY(()) ...@@ -189,11 +189,6 @@ struct temp_slot GTY(())
static rtx assign_stack_local_1 (enum machine_mode, HOST_WIDE_INT, int, static rtx assign_stack_local_1 (enum machine_mode, HOST_WIDE_INT, int,
struct function *); struct function *);
static struct temp_slot *find_temp_slot_from_address (rtx); static struct temp_slot *find_temp_slot_from_address (rtx);
static void instantiate_decls (tree, int);
static void instantiate_decls_1 (tree, int);
static void instantiate_decl (rtx, HOST_WIDE_INT, int);
static rtx instantiate_new_reg (rtx, HOST_WIDE_INT *);
static int instantiate_virtual_regs_1 (rtx *, rtx, int);
static void pad_to_arg_alignment (struct args_size *, int, struct args_size *); static void pad_to_arg_alignment (struct args_size *, int, struct args_size *);
static void pad_below (struct args_size *, enum machine_mode, tree); static void pad_below (struct args_size *, enum machine_mode, tree);
static void reorder_blocks_1 (rtx, tree, varray_type *); static void reorder_blocks_1 (rtx, tree, varray_type *);
...@@ -214,7 +209,6 @@ static rtx keep_stack_depressed (rtx); ...@@ -214,7 +209,6 @@ static rtx keep_stack_depressed (rtx);
static void prepare_function_start (tree); static void prepare_function_start (tree);
static void do_clobber_return_reg (rtx, void *); static void do_clobber_return_reg (rtx, void *);
static void do_use_return_reg (rtx, void *); static void do_use_return_reg (rtx, void *);
static void instantiate_virtual_regs_lossage (rtx);
static void set_insn_locators (rtx, int) ATTRIBUTE_UNUSED; static void set_insn_locators (rtx, int) ATTRIBUTE_UNUSED;
/* Pointer to chain of `struct function' for containing functions. */ /* Pointer to chain of `struct function' for containing functions. */
...@@ -1217,608 +1211,446 @@ static int cfa_offset; ...@@ -1217,608 +1211,446 @@ static int cfa_offset;
#endif #endif
/* Pass through the INSNS of function FNDECL and convert virtual register /* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX
references to hard register references. */ is a virtual register, return the equivalent hard register and set the
offset indirectly through the pointer. Otherwise, return 0. */
void static rtx
instantiate_virtual_regs (void) instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
{ {
rtx insn; rtx new;
HOST_WIDE_INT offset;
/* Compute the offsets to use for this function. */
in_arg_offset = FIRST_PARM_OFFSET (current_function_decl);
var_offset = STARTING_FRAME_OFFSET;
dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl);
out_arg_offset = STACK_POINTER_OFFSET;
cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
/* Scan all variables and parameters of this function. For each that is
in memory, instantiate all virtual registers if the result is a valid
address. If not, we do it later. That will handle most uses of virtual
regs on many machines. */
instantiate_decls (current_function_decl, 1);
/* Initialize recognition, indicating that volatile is OK. */
init_recog ();
/* Scan through all the insns, instantiating every virtual register still
present. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
instantiate_virtual_regs_1 (&PATTERN (insn), insn, 1);
if (INSN_DELETED_P (insn))
continue;
instantiate_virtual_regs_1 (&REG_NOTES (insn), NULL_RTX, 0);
/* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE. */
if (CALL_P (insn))
instantiate_virtual_regs_1 (&CALL_INSN_FUNCTION_USAGE (insn),
NULL_RTX, 0);
/* Past this point all ASM statements should match. Verify that
to avoid failures later in the compilation process. */
if (asm_noperands (PATTERN (insn)) >= 0
&& ! check_asm_operands (PATTERN (insn)))
instantiate_virtual_regs_lossage (insn);
}
/* Now instantiate the remaining register equivalences for debugging info. if (x == virtual_incoming_args_rtx)
These will not be valid addresses. */ new = arg_pointer_rtx, offset = in_arg_offset;
instantiate_decls (current_function_decl, 0); else if (x == virtual_stack_vars_rtx)
new = frame_pointer_rtx, offset = var_offset;
else if (x == virtual_stack_dynamic_rtx)
new = stack_pointer_rtx, offset = dynamic_offset;
else if (x == virtual_outgoing_args_rtx)
new = stack_pointer_rtx, offset = out_arg_offset;
else if (x == virtual_cfa_rtx)
new = arg_pointer_rtx, offset = cfa_offset;
else
return NULL_RTX;
/* Indicate that, from now on, assign_stack_local should use *poffset = offset;
frame_pointer_rtx. */ return new;
virtuals_instantiated = 1;
} }
/* Scan all decls in FNDECL (both variables and parameters) and instantiate /* A subroutine of instantiate_virtual_regs, called via for_each_rtx.
all virtual registers in their DECL_RTL's. Instantiate any virtual registers present inside of *LOC. The expression
is simplified, as much as possible, but is not to be considered "valid"
in any sense implied by the target. If any change is made, set CHANGED
to true. */
If VALID_ONLY, do this only if the resulting address is still valid. static int
Otherwise, always do it. */ instantiate_virtual_regs_in_rtx (rtx *loc, void *data)
static void
instantiate_decls (tree fndecl, int valid_only)
{ {
tree decl; HOST_WIDE_INT offset;
bool *changed = (bool *) data;
rtx x, new;
/* Process all parameters of the function. */ x = *loc;
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl)) if (x == 0)
return 0;
switch (GET_CODE (x))
{ {
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl)); case REG:
HOST_WIDE_INT size_rtl; new = instantiate_new_reg (x, &offset);
if (new)
{
*loc = plus_constant (new, offset);
if (changed)
*changed = true;
}
return -1;
case PLUS:
new = instantiate_new_reg (XEXP (x, 0), &offset);
if (new)
{
new = plus_constant (new, offset);
*loc = simplify_gen_binary (PLUS, GET_MODE (x), new, XEXP (x, 1));
if (changed)
*changed = true;
return -1;
}
instantiate_decl (DECL_RTL (decl), size, valid_only); /* FIXME -- from old code */
/* If we have (plus (subreg (virtual-reg)) (const_int)), we know
we can commute the PLUS and SUBREG because pointers into the
frame are well-behaved. */
break;
/* If the parameter was promoted, then the incoming RTL mode may be default:
larger than the declared type size. We must use the larger of break;
the two sizes. */
size_rtl = GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl)));
size = MAX (size_rtl, size);
instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only);
} }
/* Now process all variables defined in the function or its subblocks. */ return 0;
instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only);
} }
/* Subroutine of instantiate_decls: Process all decls in the given /* A subroutine of instantiate_virtual_regs_in_insn. Return true if X
BLOCK node and all its subblocks. */ matches the predicate for insn CODE operand OPERAND. */
static void static int
instantiate_decls_1 (tree let, int valid_only) safe_insn_predicate (int code, int operand, rtx x)
{ {
tree t; const struct insn_operand_data *op_data;
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) if (code < 0)
if (DECL_RTL_SET_P (t)) return true;
instantiate_decl (DECL_RTL (t),
int_size_in_bytes (TREE_TYPE (t)),
valid_only);
/* Process all subblocks. */ op_data = &insn_data[code].operand[operand];
for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t)) if (op_data->predicate == NULL)
instantiate_decls_1 (t, valid_only); return true;
}
/* Subroutine of the preceding procedures: Given RTL representing a return op_data->predicate (x, op_data->mode);
decl and the size of the object, do any instantiation required. }
If VALID_ONLY is nonzero, it means that the RTL should only be /* A subroutine of instantiate_virtual_regs. Instantiate any virtual
changed if the new address is valid. */ registers present inside of insn. The result will be a valid insn. */
static void static void
instantiate_decl (rtx x, HOST_WIDE_INT size, int valid_only) instantiate_virtual_regs_in_insn (rtx insn)
{ {
enum machine_mode mode; HOST_WIDE_INT offset;
rtx addr; int insn_code, i;
bool any_change;
if (x == 0) rtx set, new, x, seq;
return;
/* If this is a CONCAT, recurse for the pieces. */ /* There are some special cases to be handled first. */
if (GET_CODE (x) == CONCAT) set = single_set (insn);
if (set)
{ {
instantiate_decl (XEXP (x, 0), size / 2, valid_only); /* We're allowed to assign to a virtual register. This is interpreted
instantiate_decl (XEXP (x, 1), size / 2, valid_only); to mean that the underlying register gets assigned the inverse
return; transformation. This is used, for example, in the handling of
} non-local gotos. */
new = instantiate_new_reg (SET_DEST (set), &offset);
/* If this is not a MEM, no need to do anything. Similarly if the if (new)
address is a constant or a register that is not a virtual register. */ {
if (!MEM_P (x)) start_sequence ();
return;
addr = XEXP (x, 0); for_each_rtx (&SET_SRC (set), instantiate_virtual_regs_in_rtx, NULL);
if (CONSTANT_P (addr) x = simplify_gen_binary (PLUS, GET_MODE (new), SET_SRC (set),
|| (REG_P (addr) GEN_INT (-offset));
&& (REGNO (addr) < FIRST_VIRTUAL_REGISTER x = force_operand (x, new);
|| REGNO (addr) > LAST_VIRTUAL_REGISTER))) if (x != new)
return; emit_move_insn (new, x);
/* If we should only do this if the address is valid, copy the address. seq = get_insns ();
We need to do this so we can undo any changes that might make the end_sequence ();
address invalid. This copy is unfortunate, but probably can't be
avoided. */
if (valid_only) emit_insn_before (seq, insn);
addr = copy_rtx (addr); delete_insn (insn);
return;
}
instantiate_virtual_regs_1 (&addr, NULL_RTX, 0); /* Handle a straight copy from a virtual register by generating a
new add insn. The difference between this and falling through
to the generic case is avoiding a new pseudo and eliminating a
move insn in the initial rtl stream. */
new = instantiate_new_reg (SET_SRC (set), &offset);
if (new && offset != 0
&& REG_P (SET_DEST (set))
&& REGNO (SET_DEST (set)) > LAST_VIRTUAL_REGISTER)
{
start_sequence ();
if (valid_only && size >= 0) x = expand_simple_binop (GET_MODE (SET_DEST (set)), PLUS,
{ new, GEN_INT (offset), SET_DEST (set),
unsigned HOST_WIDE_INT decl_size = size; 1, OPTAB_LIB_WIDEN);
if (x != SET_DEST (set))
emit_move_insn (SET_DEST (set), x);
/* Now verify that the resulting address is valid for every integer or seq = get_insns ();
floating-point mode up to and including SIZE bytes long. We do this end_sequence ();
since the object might be accessed in any mode and frame addresses
are shared. */
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); emit_insn_before (seq, insn);
mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size; delete_insn (insn);
mode = GET_MODE_WIDER_MODE (mode))
if (! memory_address_p (mode, addr))
return; return;
}
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); extract_insn (insn);
mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size;
mode = GET_MODE_WIDER_MODE (mode))
if (! memory_address_p (mode, addr))
return;
}
/* Put back the address now that we have updated it and we either know /* Handle a plus involving a virtual register by determining if the
it is valid or we don't care whether it is valid. */ operands remain valid if they're modified in place. */
if (GET_CODE (SET_SRC (set)) == PLUS
&& recog_data.n_operands >= 3
&& recog_data.operand_loc[1] == &XEXP (SET_SRC (set), 0)
&& recog_data.operand_loc[2] == &XEXP (SET_SRC (set), 1)
&& GET_CODE (recog_data.operand[2]) == CONST_INT
&& (new = instantiate_new_reg (recog_data.operand[1], &offset)))
{
offset += INTVAL (recog_data.operand[2]);
XEXP (x, 0) = addr; /* If the sum is zero, then replace with a plain move. */
} if (offset == 0)
{
/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX start_sequence ();
is a virtual register, return the equivalent hard register and set the emit_move_insn (SET_DEST (set), new);
offset indirectly through the pointer. Otherwise, return 0. */ seq = get_insns ();
end_sequence ();
static rtx emit_insn_before (seq, insn);
instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset) delete_insn (insn);
{ return;
rtx new; }
HOST_WIDE_INT offset;
if (x == virtual_incoming_args_rtx) x = gen_int_mode (offset, recog_data.operand_mode[2]);
new = arg_pointer_rtx, offset = in_arg_offset; insn_code = INSN_CODE (insn);
else if (x == virtual_stack_vars_rtx)
new = frame_pointer_rtx, offset = var_offset; /* Using validate_change and apply_change_group here leaves
else if (x == virtual_stack_dynamic_rtx) recog_data in an invalid state. Since we know exactly what
new = stack_pointer_rtx, offset = dynamic_offset; we want to check, do those two by hand. */
else if (x == virtual_outgoing_args_rtx) if (safe_insn_predicate (insn_code, 1, new)
new = stack_pointer_rtx, offset = out_arg_offset; && safe_insn_predicate (insn_code, 2, x))
else if (x == virtual_cfa_rtx) {
new = arg_pointer_rtx, offset = cfa_offset; *recog_data.operand_loc[1] = recog_data.operand[1] = new;
*recog_data.operand_loc[2] = recog_data.operand[2] = x;
any_change = true;
goto verify;
}
}
}
else else
return 0; extract_insn (insn);
*poffset = offset; insn_code = INSN_CODE (insn);
return new; any_change = false;
}
/* Called when instantiate_virtual_regs has failed to update the instruction. /* In the general case, we expect virtual registers to appear only in
Usually this means that non-matching instruction has been emit, however for operands, and then only as either bare registers or inside memories. */
asm statements it may be the problem in the constraints. */ for (i = 0; i < recog_data.n_operands; ++i)
static void {
instantiate_virtual_regs_lossage (rtx insn) x = recog_data.operand[i];
{ switch (GET_CODE (x))
gcc_assert (asm_noperands (PATTERN (insn)) >= 0); {
error_for_asm (insn, "impossible constraint in %<asm%>"); case MEM:
delete_insn (insn); {
} rtx addr = XEXP (x, 0);
/* Given a pointer to a piece of rtx and an optional pointer to the bool changed = false;
containing object, instantiate any virtual registers present in it.
If EXTRA_INSNS, we always do the replacement and generate for_each_rtx (&addr, instantiate_virtual_regs_in_rtx, &changed);
any extra insns before OBJECT. If it zero, we do nothing if replacement if (!changed)
is not valid. continue;
Return 1 if we either had nothing to do or if we were able to do the start_sequence ();
needed replacement. Return 0 otherwise; we only return zero if x = replace_equiv_address (x, addr);
EXTRA_INSNS is zero. seq = get_insns ();
end_sequence ();
if (seq)
emit_insn_before (seq, insn);
}
break;
We first try some simple transformations to avoid the creation of extra case REG:
pseudos. */ new = instantiate_new_reg (x, &offset);
if (new == NULL)
continue;
if (offset == 0)
x = new;
else
{
start_sequence ();
static int /* Careful, special mode predicates may have stuff in
instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns) insn_data[insn_code].operand[i].mode that isn't useful
{ to us for computing a new value. */
rtx x; /* ??? Recognize address_operand and/or "p" constraints
RTX_CODE code; to see if (plus new offset) is a valid before we put
rtx new = 0; this through expand_simple_binop. */
HOST_WIDE_INT offset = 0; x = expand_simple_binop (GET_MODE (x), PLUS, new,
rtx temp; GEN_INT (offset), NULL_RTX,
rtx seq; 1, OPTAB_LIB_WIDEN);
int i, j; seq = get_insns ();
const char *fmt; end_sequence ();
emit_insn_before (seq, insn);
}
break;
/* Re-start here to avoid recursion in common cases. */ case SUBREG:
restart: new = instantiate_new_reg (SUBREG_REG (x), &offset);
if (new == NULL)
continue;
if (offset != 0)
{
start_sequence ();
new = expand_simple_binop (GET_MODE (new), PLUS, new,
GEN_INT (offset), NULL_RTX,
1, OPTAB_LIB_WIDEN);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, insn);
}
x = simplify_gen_subreg (insn_data[insn_code].operand[i].mode,
new, GET_MODE (new), SUBREG_BYTE (x));
break;
x = *loc; default:
if (x == 0) continue;
return 1; }
/* We may have detected and deleted invalid asm statements. */ /* At this point, X contains the new value for the operand.
if (object && INSN_P (object) && INSN_DELETED_P (object)) Validate the new value vs the insn predicate. Note that
return 1; asm insns will have insn_code -1 here. */
if (!safe_insn_predicate (insn_code, i, x))
x = force_reg (insn_data[insn_code].operand[i].mode, x);
code = GET_CODE (x); *recog_data.operand_loc[i] = recog_data.operand[i] = x;
any_change = true;
}
/* Check for some special cases. */ verify:
switch (code) if (any_change)
{ {
case CONST_INT: /* Propagate operand changes into the duplicates. */
case CONST_DOUBLE: for (i = 0; i < recog_data.n_dups; ++i)
case CONST_VECTOR: *recog_data.dup_loc[i]
case CONST: = recog_data.operand[(unsigned)recog_data.dup_num[i]];
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case ASM_INPUT:
case ADDR_VEC:
case ADDR_DIFF_VEC:
case RETURN:
return 1;
case SET: /* Force re-recognition of the instruction for validation. */
/* We are allowed to set the virtual registers. This means that INSN_CODE (insn) = -1;
the actual register should receive the source minus the }
appropriate offset. This is used, for example, in the handling
of non-local gotos. */ if (asm_noperands (PATTERN (insn)) >= 0)
if ((new = instantiate_new_reg (SET_DEST (x), &offset)) != 0) {
if (!check_asm_operands (PATTERN (insn)))
{ {
rtx src = SET_SRC (x); error_for_asm (insn, "impossible constraint in %<asm%>");
delete_insn (insn);
}
}
else
{
if (recog_memoized (insn) < 0)
fatal_insn_not_found (insn);
}
}
/* We are setting the register, not using it, so the relevant /* Subroutine of instantiate_decls. Given RTL representing a decl,
offset is the negative of the offset to use were we using do any instantiation required. */
the register. */
offset = - offset;
instantiate_virtual_regs_1 (&src, NULL_RTX, 0);
/* The only valid sources here are PLUS or REG. Just do static void
the simplest possible thing to handle them. */ instantiate_decl (rtx x)
if (!REG_P (src) && GET_CODE (src) != PLUS) {
{ rtx addr;
instantiate_virtual_regs_lossage (object);
return 1;
}
start_sequence (); if (x == 0)
if (!REG_P (src)) return;
temp = force_operand (src, NULL_RTX);
else
temp = src;
temp = force_operand (plus_constant (temp, offset), NULL_RTX);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, object); /* If this is a CONCAT, recurse for the pieces. */
SET_DEST (x) = new; if (GET_CODE (x) == CONCAT)
{
instantiate_decl (XEXP (x, 0));
instantiate_decl (XEXP (x, 1));
return;
}
if (! validate_change (object, &SET_SRC (x), temp, 0) /* If this is not a MEM, no need to do anything. Similarly if the
|| ! extra_insns) address is a constant or a register that is not a virtual register. */
instantiate_virtual_regs_lossage (object); if (!MEM_P (x))
return;
return 1; addr = XEXP (x, 0);
} if (CONSTANT_P (addr)
|| (REG_P (addr)
&& (REGNO (addr) < FIRST_VIRTUAL_REGISTER
|| REGNO (addr) > LAST_VIRTUAL_REGISTER)))
return;
instantiate_virtual_regs_1 (&SET_DEST (x), object, extra_insns); for_each_rtx (&XEXP (x, 0), instantiate_virtual_regs_in_rtx, NULL);
loc = &SET_SRC (x); }
goto restart;
case PLUS: /* Subroutine of instantiate_decls: Process all decls in the given
/* Handle special case of virtual register plus constant. */ BLOCK node and all its subblocks. */
if (CONSTANT_P (XEXP (x, 1)))
{
rtx old, new_offset;
/* Check for (plus (plus VIRT foo) (const_int)) first. */ static void
if (GET_CODE (XEXP (x, 0)) == PLUS) instantiate_decls_1 (tree let)
{ {
if ((new = instantiate_new_reg (XEXP (XEXP (x, 0), 0), &offset))) tree t;
{
instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
extra_insns);
new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
}
else
{
loc = &XEXP (x, 0);
goto restart;
}
}
#ifdef POINTERS_EXTEND_UNSIGNED for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
/* If we have (plus (subreg (virtual-reg)) (const_int)), we know if (DECL_RTL_SET_P (t))
we can commute the PLUS and SUBREG because pointers into the instantiate_decl (DECL_RTL (t));
frame are well-behaved. */
else if (GET_CODE (XEXP (x, 0)) == SUBREG && GET_MODE (x) == ptr_mode
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& 0 != (new
= instantiate_new_reg (SUBREG_REG (XEXP (x, 0)),
&offset))
&& validate_change (object, loc,
plus_constant (gen_lowpart (ptr_mode,
new),
offset
+ INTVAL (XEXP (x, 1))),
0))
return 1;
#endif
else if ((new = instantiate_new_reg (XEXP (x, 0), &offset)) == 0)
{
/* We know the second operand is a constant. Unless the
first operand is a REG (which has been already checked),
it needs to be checked. */
if (!REG_P (XEXP (x, 0)))
{
loc = &XEXP (x, 0);
goto restart;
}
return 1;
}
new_offset = plus_constant (XEXP (x, 1), offset); /* Process all subblocks. */
for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
/* If the new constant is zero, try to replace the sum with just instantiate_decls_1 (t);
the register. */ }
if (new_offset == const0_rtx
&& validate_change (object, loc, new, 0))
return 1;
/* Next try to replace the register and new offset.
There are two changes to validate here and we can't assume that
in the case of old offset equals new just changing the register
will yield a valid insn. In the interests of a little efficiency,
however, we only call validate change once (we don't queue up the
changes and then call apply_change_group). */
old = XEXP (x, 0);
if (offset == 0
? ! validate_change (object, &XEXP (x, 0), new, 0)
: (XEXP (x, 0) = new,
! validate_change (object, &XEXP (x, 1), new_offset, 0)))
{
if (! extra_insns)
{
XEXP (x, 0) = old;
return 0;
}
/* Otherwise copy the new constant into a register and replace /* Scan all decls in FNDECL (both variables and parameters) and instantiate
constant with that register. */ all virtual registers in their DECL_RTL's. */
temp = gen_reg_rtx (Pmode);
XEXP (x, 0) = new;
if (validate_change (object, &XEXP (x, 1), temp, 0))
emit_insn_before (gen_move_insn (temp, new_offset), object);
else
{
/* If that didn't work, replace this expression with a
register containing the sum. */
XEXP (x, 0) = old; static void
new = gen_rtx_PLUS (Pmode, new, new_offset); instantiate_decls (tree fndecl)
{
tree decl;
start_sequence (); /* Process all parameters of the function. */
temp = force_operand (new, NULL_RTX); for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
seq = get_insns (); {
end_sequence (); instantiate_decl (DECL_RTL (decl));
instantiate_decl (DECL_INCOMING_RTL (decl));
}
emit_insn_before (seq, object); /* Now process all variables defined in the function or its subblocks. */
if (! validate_change (object, loc, temp, 0) instantiate_decls_1 (DECL_INITIAL (fndecl));
&& ! validate_replace_rtx (x, temp, object)) }
{
instantiate_virtual_regs_lossage (object);
return 1;
}
}
}
return 1; /* Pass through the INSNS of function FNDECL and convert virtual register
} references to hard register references. */
/* Fall through to generic two-operand expression case. */ void
case EXPR_LIST: instantiate_virtual_regs (void)
case CALL: {
case COMPARE: rtx insn;
case MINUS:
case MULT:
case DIV: case UDIV:
case MOD: case UMOD:
case AND: case IOR: case XOR:
case ROTATERT: case ROTATE:
case ASHIFTRT: case LSHIFTRT: case ASHIFT:
case NE: case EQ:
case GE: case GT: case GEU: case GTU:
case LE: case LT: case LEU: case LTU:
if (XEXP (x, 1) && ! CONSTANT_P (XEXP (x, 1)))
instantiate_virtual_regs_1 (&XEXP (x, 1), object, extra_insns);
loc = &XEXP (x, 0);
goto restart;
case MEM:
/* Most cases of MEM that convert to valid addresses have already been
handled by our scan of decls. The only special handling we
need here is to make a copy of the rtx to ensure it isn't being
shared if we have to change it to a pseudo.
If the rtx is a simple reference to an address via a virtual register,
it can potentially be shared. In such cases, first try to make it
a valid address, which can also be shared. Otherwise, copy it and
proceed normally.
First check for common cases that need no processing. These are
usually due to instantiation already being done on a previous instance
of a shared rtx. */
temp = XEXP (x, 0);
if (CONSTANT_ADDRESS_P (temp)
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| temp == arg_pointer_rtx
#endif
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
|| temp == hard_frame_pointer_rtx
#endif
|| temp == frame_pointer_rtx)
return 1;
if (GET_CODE (temp) == PLUS
&& CONSTANT_ADDRESS_P (XEXP (temp, 1))
&& (XEXP (temp, 0) == frame_pointer_rtx
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
|| XEXP (temp, 0) == hard_frame_pointer_rtx
#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| XEXP (temp, 0) == arg_pointer_rtx
#endif
))
return 1;
if (temp == virtual_stack_vars_rtx
|| temp == virtual_incoming_args_rtx
|| (GET_CODE (temp) == PLUS
&& CONSTANT_ADDRESS_P (XEXP (temp, 1))
&& (XEXP (temp, 0) == virtual_stack_vars_rtx
|| XEXP (temp, 0) == virtual_incoming_args_rtx)))
{
/* This MEM may be shared. If the substitution can be done without
the need to generate new pseudos, we want to do it in place
so all copies of the shared rtx benefit. The call below will
only make substitutions if the resulting address is still
valid.
Note that we cannot pass X as the object in the recursive call
since the insn being processed may not allow all valid
addresses. However, if we were not passed on object, we can
only modify X without copying it if X will have a valid
address.
??? Also note that this can still lose if OBJECT is an insn that
has less restrictions on an address that some other insn.
In that case, we will modify the shared address. This case
doesn't seem very likely, though. One case where this could
happen is in the case of a USE or CLOBBER reference, but we
take care of that below. */
if (instantiate_virtual_regs_1 (&XEXP (x, 0),
object ? object : x, 0))
return 1;
/* Otherwise make a copy and process that copy. We copy the entire
RTL expression since it might be a PLUS which could also be
shared. */
*loc = x = copy_rtx (x);
}
/* Fall through to generic unary operation case. */ /* Compute the offsets to use for this function. */
case PREFETCH: in_arg_offset = FIRST_PARM_OFFSET (current_function_decl);
case SUBREG: var_offset = STARTING_FRAME_OFFSET;
case STRICT_LOW_PART: dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl);
case NEG: case NOT: out_arg_offset = STACK_POINTER_OFFSET;
case PRE_DEC: case PRE_INC: case POST_DEC: case POST_INC: cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
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:
case CLZ: case CTZ:
case POPCOUNT: case PARITY:
/* These case either have just one operand or we know that we need not
check the rest of the operands. */
loc = &XEXP (x, 0);
goto restart;
case USE:
case CLOBBER:
/* If the operand is a MEM, see if the change is a valid MEM. If not,
go ahead and make the invalid one, but do it to a copy. For a REG,
just make the recursive call, since there's no chance of a problem. */
if ((MEM_P (XEXP (x, 0))
&& instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0),
0))
|| (REG_P (XEXP (x, 0))
&& instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0)))
return 1;
XEXP (x, 0) = copy_rtx (XEXP (x, 0));
loc = &XEXP (x, 0);
goto restart;
case REG: /* Initialize recognition, indicating that volatile is OK. */
/* Try to replace with a PLUS. If that doesn't work, compute the sum init_recog ();
in front of this insn and substitute the temporary. */
if ((new = instantiate_new_reg (x, &offset)) != 0)
{
temp = plus_constant (new, offset);
if (!validate_change (object, loc, temp, 0))
{
if (! extra_insns)
return 0;
start_sequence (); /* Scan through all the insns, instantiating every virtual register still
temp = force_operand (temp, NULL_RTX); present. */
seq = get_insns (); for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
end_sequence (); if (INSN_P (insn))
{
/* These patterns in the instruction stream can never be recognized.
Fortunately, they shouldn't contain virtual registers either. */
if (GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == CLOBBER
|| GET_CODE (PATTERN (insn)) == ADDR_VEC
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
|| GET_CODE (PATTERN (insn)) == ASM_INPUT)
continue;
emit_insn_before (seq, object); instantiate_virtual_regs_in_insn (insn);
if (! validate_change (object, loc, temp, 0)
&& ! validate_replace_rtx (x, temp, object))
instantiate_virtual_regs_lossage (object);
}
}
return 1; if (INSN_DELETED_P (insn))
continue;
default: for_each_rtx (&REG_NOTES (insn), instantiate_virtual_regs_in_rtx, NULL);
break;
}
/* Scan all subexpressions. */ /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE. */
fmt = GET_RTX_FORMAT (code); if (GET_CODE (insn) == CALL_INSN)
for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) for_each_rtx (&CALL_INSN_FUNCTION_USAGE (insn),
if (*fmt == 'e') instantiate_virtual_regs_in_rtx, NULL);
{
if (!instantiate_virtual_regs_1 (&XEXP (x, i), object, extra_insns))
return 0;
} }
else if (*fmt == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
if (! instantiate_virtual_regs_1 (&XVECEXP (x, i, j), object,
extra_insns))
return 0;
return 1; /* Instantiate the virtual registers in the DECLs for debugging purposes. */
instantiate_decls (current_function_decl);
/* Indicate that, from now on, assign_stack_local should use
frame_pointer_rtx. */
virtuals_instantiated = 1;
} }
/* Return 1 if EXP is an aggregate type (or a value with aggregate type). /* Return 1 if EXP is an aggregate type (or a value with aggregate type).
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment