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>
* 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>
* gengtype.c (write_func_for_structure): Split out ...
......
......@@ -189,11 +189,6 @@ struct temp_slot GTY(())
static rtx assign_stack_local_1 (enum machine_mode, HOST_WIDE_INT, int,
struct function *);
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_below (struct args_size *, enum machine_mode, tree);
static void reorder_blocks_1 (rtx, tree, varray_type *);
......@@ -214,7 +209,6 @@ static rtx keep_stack_depressed (rtx);
static void prepare_function_start (tree);
static void do_clobber_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;
/* Pointer to chain of `struct function' for containing functions. */
......@@ -1217,608 +1211,446 @@ static int cfa_offset;
#endif
/* Pass through the INSNS of function FNDECL and convert virtual register
references to hard register references. */
/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX
is a virtual register, return the equivalent hard register and set the
offset indirectly through the pointer. Otherwise, return 0. */
void
instantiate_virtual_regs (void)
static rtx
instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
{
rtx insn;
/* 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);
}
rtx new;
HOST_WIDE_INT offset;
/* Now instantiate the remaining register equivalences for debugging info.
These will not be valid addresses. */
instantiate_decls (current_function_decl, 0);
if (x == virtual_incoming_args_rtx)
new = arg_pointer_rtx, offset = in_arg_offset;
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
frame_pointer_rtx. */
virtuals_instantiated = 1;
*poffset = offset;
return new;
}
/* Scan all decls in FNDECL (both variables and parameters) and instantiate
all virtual registers in their DECL_RTL's.
/* A subroutine of instantiate_virtual_regs, called via for_each_rtx.
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.
Otherwise, always do it. */
static void
instantiate_decls (tree fndecl, int valid_only)
static int
instantiate_virtual_regs_in_rtx (rtx *loc, void *data)
{
tree decl;
HOST_WIDE_INT offset;
bool *changed = (bool *) data;
rtx x, new;
/* Process all parameters of the function. */
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
x = *loc;
if (x == 0)
return 0;
switch (GET_CODE (x))
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
HOST_WIDE_INT size_rtl;
case REG:
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
larger than the declared type size. We must use the larger of
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);
default:
break;
}
/* Now process all variables defined in the function or its subblocks. */
instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only);
return 0;
}
/* Subroutine of instantiate_decls: Process all decls in the given
BLOCK node and all its subblocks. */
/* A subroutine of instantiate_virtual_regs_in_insn. Return true if X
matches the predicate for insn CODE operand OPERAND. */
static void
instantiate_decls_1 (tree let, int valid_only)
static int
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 (DECL_RTL_SET_P (t))
instantiate_decl (DECL_RTL (t),
int_size_in_bytes (TREE_TYPE (t)),
valid_only);
if (code < 0)
return true;
/* Process all subblocks. */
for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
instantiate_decls_1 (t, valid_only);
}
op_data = &insn_data[code].operand[operand];
if (op_data->predicate == NULL)
return true;
/* Subroutine of the preceding procedures: Given RTL representing a
decl and the size of the object, do any instantiation required.
return op_data->predicate (x, op_data->mode);
}
If VALID_ONLY is nonzero, it means that the RTL should only be
changed if the new address is valid. */
/* A subroutine of instantiate_virtual_regs. Instantiate any virtual
registers present inside of insn. The result will be a valid insn. */
static void
instantiate_decl (rtx x, HOST_WIDE_INT size, int valid_only)
instantiate_virtual_regs_in_insn (rtx insn)
{
enum machine_mode mode;
rtx addr;
if (x == 0)
return;
HOST_WIDE_INT offset;
int insn_code, i;
bool any_change;
rtx set, new, x, seq;
/* If this is a CONCAT, recurse for the pieces. */
if (GET_CODE (x) == CONCAT)
/* There are some special cases to be handled first. */
set = single_set (insn);
if (set)
{
instantiate_decl (XEXP (x, 0), size / 2, valid_only);
instantiate_decl (XEXP (x, 1), size / 2, valid_only);
return;
}
/* If this is not a MEM, no need to do anything. Similarly if the
address is a constant or a register that is not a virtual register. */
if (!MEM_P (x))
return;
/* We're allowed to assign to a virtual register. This is interpreted
to mean that the underlying register gets assigned the inverse
transformation. This is used, for example, in the handling of
non-local gotos. */
new = instantiate_new_reg (SET_DEST (set), &offset);
if (new)
{
start_sequence ();
addr = XEXP (x, 0);
if (CONSTANT_P (addr)
|| (REG_P (addr)
&& (REGNO (addr) < FIRST_VIRTUAL_REGISTER
|| REGNO (addr) > LAST_VIRTUAL_REGISTER)))
return;
for_each_rtx (&SET_SRC (set), instantiate_virtual_regs_in_rtx, NULL);
x = simplify_gen_binary (PLUS, GET_MODE (new), SET_SRC (set),
GEN_INT (-offset));
x = force_operand (x, new);
if (x != new)
emit_move_insn (new, x);
/* If we should only do this if the address is valid, copy the address.
We need to do this so we can undo any changes that might make the
address invalid. This copy is unfortunate, but probably can't be
avoided. */
seq = get_insns ();
end_sequence ();
if (valid_only)
addr = copy_rtx (addr);
emit_insn_before (seq, insn);
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)
{
unsigned HOST_WIDE_INT decl_size = size;
x = expand_simple_binop (GET_MODE (SET_DEST (set)), PLUS,
new, GEN_INT (offset), SET_DEST (set),
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
floating-point mode up to and including SIZE bytes long. We do this
since the object might be accessed in any mode and frame addresses
are shared. */
seq = get_insns ();
end_sequence ();
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size;
mode = GET_MODE_WIDER_MODE (mode))
if (! memory_address_p (mode, addr))
emit_insn_before (seq, insn);
delete_insn (insn);
return;
}
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size;
mode = GET_MODE_WIDER_MODE (mode))
if (! memory_address_p (mode, addr))
return;
}
extract_insn (insn);
/* Put back the address now that we have updated it and we either know
it is valid or we don't care whether it is valid. */
/* Handle a plus involving a virtual register by determining if the
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;
}
/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX
is a virtual register, return the equivalent hard register and set the
offset indirectly through the pointer. Otherwise, return 0. */
/* If the sum is zero, then replace with a plain move. */
if (offset == 0)
{
start_sequence ();
emit_move_insn (SET_DEST (set), new);
seq = get_insns ();
end_sequence ();
static rtx
instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
{
rtx new;
HOST_WIDE_INT offset;
emit_insn_before (seq, insn);
delete_insn (insn);
return;
}
if (x == virtual_incoming_args_rtx)
new = arg_pointer_rtx, offset = in_arg_offset;
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;
x = gen_int_mode (offset, recog_data.operand_mode[2]);
insn_code = INSN_CODE (insn);
/* Using validate_change and apply_change_group here leaves
recog_data in an invalid state. Since we know exactly what
we want to check, do those two by hand. */
if (safe_insn_predicate (insn_code, 1, new)
&& safe_insn_predicate (insn_code, 2, x))
{
*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
return 0;
extract_insn (insn);
*poffset = offset;
return new;
}
insn_code = INSN_CODE (insn);
any_change = false;
/* Called when instantiate_virtual_regs has failed to update the instruction.
Usually this means that non-matching instruction has been emit, however for
asm statements it may be the problem in the constraints. */
static void
instantiate_virtual_regs_lossage (rtx insn)
{
gcc_assert (asm_noperands (PATTERN (insn)) >= 0);
error_for_asm (insn, "impossible constraint in %<asm%>");
delete_insn (insn);
}
/* Given a pointer to a piece of rtx and an optional pointer to the
containing object, instantiate any virtual registers present in it.
/* In the general case, we expect virtual registers to appear only in
operands, and then only as either bare registers or inside memories. */
for (i = 0; i < recog_data.n_operands; ++i)
{
x = recog_data.operand[i];
switch (GET_CODE (x))
{
case MEM:
{
rtx addr = XEXP (x, 0);
bool changed = false;
If EXTRA_INSNS, we always do the replacement and generate
any extra insns before OBJECT. If it zero, we do nothing if replacement
is not valid.
for_each_rtx (&addr, instantiate_virtual_regs_in_rtx, &changed);
if (!changed)
continue;
Return 1 if we either had nothing to do or if we were able to do the
needed replacement. Return 0 otherwise; we only return zero if
EXTRA_INSNS is zero.
start_sequence ();
x = replace_equiv_address (x, addr);
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
pseudos. */
case REG:
new = instantiate_new_reg (x, &offset);
if (new == NULL)
continue;
if (offset == 0)
x = new;
else
{
start_sequence ();
static int
instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns)
{
rtx x;
RTX_CODE code;
rtx new = 0;
HOST_WIDE_INT offset = 0;
rtx temp;
rtx seq;
int i, j;
const char *fmt;
/* Careful, special mode predicates may have stuff in
insn_data[insn_code].operand[i].mode that isn't useful
to us for computing a new value. */
/* ??? Recognize address_operand and/or "p" constraints
to see if (plus new offset) is a valid before we put
this through expand_simple_binop. */
x = expand_simple_binop (GET_MODE (x), PLUS, new,
GEN_INT (offset), NULL_RTX,
1, OPTAB_LIB_WIDEN);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, insn);
}
break;
/* Re-start here to avoid recursion in common cases. */
restart:
case SUBREG:
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;
if (x == 0)
return 1;
default:
continue;
}
/* We may have detected and deleted invalid asm statements. */
if (object && INSN_P (object) && INSN_DELETED_P (object))
return 1;
/* At this point, X contains the new value for the operand.
Validate the new value vs the insn predicate. Note that
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. */
switch (code)
verify:
if (any_change)
{
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
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 1;
/* Propagate operand changes into the duplicates. */
for (i = 0; i < recog_data.n_dups; ++i)
*recog_data.dup_loc[i]
= recog_data.operand[(unsigned)recog_data.dup_num[i]];
case SET:
/* We are allowed to set the virtual registers. This means that
the actual register should receive the source minus the
appropriate offset. This is used, for example, in the handling
of non-local gotos. */
if ((new = instantiate_new_reg (SET_DEST (x), &offset)) != 0)
/* Force re-recognition of the instruction for validation. */
INSN_CODE (insn) = -1;
}
if (asm_noperands (PATTERN (insn)) >= 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
offset is the negative of the offset to use were we using
the register. */
offset = - offset;
instantiate_virtual_regs_1 (&src, NULL_RTX, 0);
/* Subroutine of instantiate_decls. Given RTL representing a decl,
do any instantiation required. */
/* The only valid sources here are PLUS or REG. Just do
the simplest possible thing to handle them. */
if (!REG_P (src) && GET_CODE (src) != PLUS)
{
instantiate_virtual_regs_lossage (object);
return 1;
}
static void
instantiate_decl (rtx x)
{
rtx addr;
start_sequence ();
if (!REG_P (src))
temp = force_operand (src, NULL_RTX);
else
temp = src;
temp = force_operand (plus_constant (temp, offset), NULL_RTX);
seq = get_insns ();
end_sequence ();
if (x == 0)
return;
emit_insn_before (seq, object);
SET_DEST (x) = new;
/* If this is a CONCAT, recurse for the pieces. */
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)
|| ! extra_insns)
instantiate_virtual_regs_lossage (object);
/* If this is not a MEM, no need to do anything. Similarly if the
address is a constant or a register that is not a virtual register. */
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);
loc = &SET_SRC (x);
goto restart;
for_each_rtx (&XEXP (x, 0), instantiate_virtual_regs_in_rtx, NULL);
}
case PLUS:
/* Handle special case of virtual register plus constant. */
if (CONSTANT_P (XEXP (x, 1)))
{
rtx old, new_offset;
/* Subroutine of instantiate_decls: Process all decls in the given
BLOCK node and all its subblocks. */
/* Check for (plus (plus VIRT foo) (const_int)) first. */
if (GET_CODE (XEXP (x, 0)) == PLUS)
{
if ((new = instantiate_new_reg (XEXP (XEXP (x, 0), 0), &offset)))
{
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;
}
}
static void
instantiate_decls_1 (tree let)
{
tree t;
#ifdef POINTERS_EXTEND_UNSIGNED
/* 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. */
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;
}
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
if (DECL_RTL_SET_P (t))
instantiate_decl (DECL_RTL (t));
new_offset = plus_constant (XEXP (x, 1), offset);
/* If the new constant is zero, try to replace the sum with just
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;
}
/* Process all subblocks. */
for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
instantiate_decls_1 (t);
}
/* Otherwise copy the new constant into a register and replace
constant with that register. */
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. */
/* Scan all decls in FNDECL (both variables and parameters) and instantiate
all virtual registers in their DECL_RTL's. */
XEXP (x, 0) = old;
new = gen_rtx_PLUS (Pmode, new, new_offset);
static void
instantiate_decls (tree fndecl)
{
tree decl;
start_sequence ();
temp = force_operand (new, NULL_RTX);
seq = get_insns ();
end_sequence ();
/* Process all parameters of the function. */
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
{
instantiate_decl (DECL_RTL (decl));
instantiate_decl (DECL_INCOMING_RTL (decl));
}
emit_insn_before (seq, object);
if (! validate_change (object, loc, temp, 0)
&& ! validate_replace_rtx (x, temp, object))
{
instantiate_virtual_regs_lossage (object);
return 1;
}
}
}
/* Now process all variables defined in the function or its subblocks. */
instantiate_decls_1 (DECL_INITIAL (fndecl));
}
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. */
case EXPR_LIST:
case CALL:
case COMPARE:
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);
}
void
instantiate_virtual_regs (void)
{
rtx insn;
/* Fall through to generic unary operation case. */
case PREFETCH:
case SUBREG:
case STRICT_LOW_PART:
case NEG: case NOT:
case PRE_DEC: case PRE_INC: case POST_DEC: case POST_INC:
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;
/* 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);
case REG:
/* Try to replace with a PLUS. If that doesn't work, compute the sum
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;
/* Initialize recognition, indicating that volatile is OK. */
init_recog ();
start_sequence ();
temp = force_operand (temp, NULL_RTX);
seq = get_insns ();
end_sequence ();
/* Scan through all the insns, instantiating every virtual register still
present. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
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);
if (! validate_change (object, loc, temp, 0)
&& ! validate_replace_rtx (x, temp, object))
instantiate_virtual_regs_lossage (object);
}
}
instantiate_virtual_regs_in_insn (insn);
return 1;
if (INSN_DELETED_P (insn))
continue;
default:
break;
}
for_each_rtx (&REG_NOTES (insn), instantiate_virtual_regs_in_rtx, NULL);
/* Scan all subexpressions. */
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
if (*fmt == 'e')
{
if (!instantiate_virtual_regs_1 (&XEXP (x, i), object, extra_insns))
return 0;
/* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE. */
if (GET_CODE (insn) == CALL_INSN)
for_each_rtx (&CALL_INSN_FUNCTION_USAGE (insn),
instantiate_virtual_regs_in_rtx, NULL);
}
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).
......
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