/* Allocate registers within a basic block, for GNU compiler.
- Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1991, 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "recog.h"
#include "output.h"
\f
+/* Pseudos allocated here cannot be reallocated by global.c if the hard
+ register is used as a spill register. So we don't allocate such pseudos
+ here if their preferred class is likely to be used by spills.
+
+ On most machines, the appropriate test is if the class has one
+ register, so we default to that. */
+
+#ifndef CLASS_LIKELY_SPILLED_P
+#define CLASS_LIKELY_SPILLED_P(CLASS) (reg_class_size[(int) (CLASS)] == 1)
+#endif
+
/* Next quantity number available for allocation. */
static int next_qty;
/* Element Q is the number of refs to quantity Q. */
-static short *qty_n_refs;
+static int *qty_n_refs;
/* Element Q is a reg class contained in (smaller than) the
preferred classes of all the pseudo regs that are tied in quantity Q.
static int *qty_n_calls_crossed;
-/* Nonzero means don't allocate qty Q if we can't get its preferred class. */
+/* Register class within which we allocate qty Q if we can't get
+ its preferred class. */
-static char *qty_preferred_or_nothing;
+static enum reg_class *qty_alternate_class;
/* Element Q is the SCRATCH expression for which this quantity is being
allocated or 0 if this quantity is allocating registers. */
reg_qty value is Q, or -1 is this quantity is for a SCRATCH. This
register should be the head of the chain maintained in reg_next_in_qty. */
-static short *qty_first_reg;
+static int *qty_first_reg;
/* If (REG N) has been assigned a quantity number, is a register number
of another register assigned the same quantity number, or -1 for the
end of the chain. qty_first_reg point to the head of this chain. */
-static short *reg_next_in_qty;
+static int *reg_next_in_qty;
/* reg_qty[N] (where N is a pseudo reg number) is the qty number of that reg
if it is >= 0,
static HARD_REG_SET *regs_live_at;
+int *scratch_block;
+rtx *scratch_list;
+int scratch_list_length;
+static int scratch_index;
+
/* Communicate local vars `insn_number' and `insn'
from `block_alloc' to `reg_is_set', `wipe_dead_reg', and `alloc_qty'. */
static int this_insn_number;
qty_birth[qty] = birth;
qty_n_calls_crossed[qty] = reg_n_calls_crossed[regno];
qty_min_class[qty] = reg_preferred_class (regno);
- qty_preferred_or_nothing[qty] = reg_preferred_or_nothing (regno);
+ qty_alternate_class[qty] = reg_alternate_class (regno);
qty_n_refs[qty] = reg_n_refs[regno];
}
\f
char *p, c;
int i;
+#ifdef REGISTER_CONSTRAINTS
/* If we haven't yet computed which alternative will be used, do so now.
Then set P to the constraints for that alternative. */
if (which_alternative == -1)
break;
}
- /* If CLASS has only one register, don't allocate the SCRATCH here since
- it will prevent that register from being used as a spill register.
- reload will do the allocation. */
-
- if (class == NO_REGS || reg_class_size[(int) class] == 1)
+ if (class == NO_REGS)
return;
+#else /* REGISTER_CONSTRAINTS */
+
+ class = GENERAL_REGS;
+#endif
+
+
qty = next_qty++;
qty_first_reg[qty] = -1;
qty_death[qty] = 2 * insn_number + 1;
qty_n_calls_crossed[qty] = 0;
qty_min_class[qty] = class;
- qty_preferred_or_nothing[qty] = 1;
+ qty_alternate_class[qty] = NO_REGS;
qty_n_refs[qty] = 1;
}
\f
update_equiv_regs ();
/* This sets the maximum number of quantities we can have. Quantity
- numbers start at zero and we can have one for each psuedo plus the
- number of SCRATCHs in the largest block, in the worst case. */
+ numbers start at zero and we can have one for each pseudo plus the
+ number of SCRATCHes in the largest block, in the worst case. */
max_qty = (max_regno - FIRST_PSEUDO_REGISTER) + max_scratch;
/* Allocate vectors of temporary data.
See the declarations of these variables, above,
for what they mean. */
+ /* There can be up to MAX_SCRATCH * N_BASIC_BLOCKS SCRATCHes to allocate.
+ Instead of allocating this much memory from now until the end of
+ reload, only allocate space for MAX_QTY SCRATCHes. If there are more
+ reload will allocate them. */
+
+ scratch_list_length = max_qty;
+ scratch_list = (rtx *) xmalloc (scratch_list_length * sizeof (rtx));
+ bzero (scratch_list, scratch_list_length * sizeof (rtx));
+ scratch_block = (int *) xmalloc (scratch_list_length * sizeof (int));
+ bzero (scratch_block, scratch_list_length * sizeof (int));
+ scratch_index = 0;
+
qty_phys_reg = (short *) alloca (max_qty * sizeof (short));
qty_phys_copy_sugg = (HARD_REG_SET *) alloca (max_qty * sizeof (HARD_REG_SET));
qty_phys_has_copy_sugg = (char *) alloca (max_qty * sizeof (char));
qty_birth = (int *) alloca (max_qty * sizeof (int));
qty_death = (int *) alloca (max_qty * sizeof (int));
qty_scratch_rtx = (rtx *) alloca (max_qty * sizeof (rtx));
- qty_first_reg = (short *) alloca (max_qty * sizeof (short));
+ qty_first_reg = (int *) alloca (max_qty * sizeof (int));
qty_size = (int *) alloca (max_qty * sizeof (int));
qty_mode = (enum machine_mode *) alloca (max_qty * sizeof (enum machine_mode));
qty_n_calls_crossed = (int *) alloca (max_qty * sizeof (int));
qty_min_class = (enum reg_class *) alloca (max_qty * sizeof (enum reg_class));
- qty_preferred_or_nothing = (char *) alloca (max_qty);
- qty_n_refs = (short *) alloca (max_qty * sizeof (short));
+ qty_alternate_class = (enum reg_class *) alloca (max_qty * sizeof (enum reg_class));
+ qty_n_refs = (int *) alloca (max_qty * sizeof (int));
reg_qty = (int *) alloca (max_regno * sizeof (int));
reg_offset = (char *) alloca (max_regno * sizeof (char));
- reg_next_in_qty = (short *) alloca (max_regno * sizeof (short));
+ reg_next_in_qty = (int *) alloca (max_regno * sizeof (int));
reg_renumber = (short *) oballoc (max_regno * sizeof (short));
for (i = 0; i < max_regno; i++)
/* Determine which pseudo-registers can be allocated by local-alloc.
In general, these are the registers used only in a single block and
which only die once. However, if a register's preferred class has only
- one entry, don't allocate this register here unless it is preferred
+ a few entries, don't allocate this register here unless it is preferred
or nothing since retry_global_alloc won't be able to move it to
GENERAL_REGS if a reload register of this class is needed.
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
{
if (reg_basic_block[i] >= 0 && reg_n_deaths[i] == 1
- && (reg_preferred_or_nothing (i)
- || reg_class_size[(int) reg_preferred_class (i)] > 1))
+ && (reg_alternate_class (i) == NO_REGS
+ || ! CLASS_LIKELY_SPILLED_P (reg_preferred_class (i))))
reg_qty[i] = -2;
else
reg_qty[i] = -1;
register-register copy. */
static void
-optimize_reg_copy (insn, dest, src)
+optimize_reg_copy_1 (insn, dest, src)
rtx insn;
rtx dest;
rtx src;
&& reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
break;
- if ((note = find_regno_note (p, REG_DEAD, sregno)) != 0)
+ /* See if all of SRC dies in P. This test is slightly more
+ conservative than it needs to be. */
+ if ((note = find_regno_note (p, REG_DEAD, sregno)) != 0
+ && GET_MODE (XEXP (note, 0)) == GET_MODE (src))
{
int failed = 0;
int length = 0;
+ int d_length = 0;
int n_calls = 0;
+ int d_n_calls = 0;
/* We can do the optimization. Scan forward from INSN again,
replacing regs as we go. Set FAILED if a replacement can't
q != next_real_insn (p);
q = next_real_insn (q))
{
- if (reg_mentioned_p (src, PATTERN (q)))
+ if (reg_overlap_mentioned_p (src, PATTERN (q)))
{
- if (validate_replace_rtx (src, dest, q))
+ /* If SRC is a hard register, we might miss some
+ overlapping registers with validate_replace_rtx,
+ so we would have to undo it. We can't if DEST is
+ present in the insn, so fail in that combination
+ of cases. */
+ if (sregno < FIRST_PSEUDO_REGISTER
+ && reg_mentioned_p (dest, PATTERN (q)))
+ failed = 1;
+
+ /* Replace all uses and make sure that the register
+ isn't still present. */
+ else if (validate_replace_rtx (src, dest, q)
+ && (sregno >= FIRST_PSEUDO_REGISTER
+ || ! reg_overlap_mentioned_p (src,
+ PATTERN (q))))
{
/* We assume that a register is used exactly once per
insn in the updates below. If this is not correct,
reg_n_refs[dregno] += loop_depth;
}
else
- failed = 1;
+ {
+ validate_replace_rtx (dest, src, q);
+ failed = 1;
+ }
}
/* Count the insns and CALL_INSNs passed. If we passed the
death note of DEST, show increased live length. */
length++;
if (dest_death)
- reg_live_length[dregno]++;
+ d_length++;
if (GET_CODE (q) == CALL_INSN)
{
n_calls++;
if (dest_death)
- reg_n_calls_crossed[dregno]++;
+ d_n_calls++;
}
/* If DEST dies here, remove the death note and save it for
- later. */
+ later. Make sure ALL of DEST dies here; again, this is
+ overly conservative. */
if (dest_death == 0
- && (dest_death = find_regno_note (q, REG_DEAD, dregno)) != 0)
+ && (dest_death = find_regno_note (q, REG_DEAD, dregno)) != 0
+ && GET_MODE (XEXP (dest_death, 0)) == GET_MODE (dest))
remove_note (q, dest_death);
}
reg_n_calls_crossed[sregno] -= n_calls;
}
+ if (dregno >= FIRST_PSEUDO_REGISTER)
+ {
+ reg_live_length[dregno] += d_length;
+ reg_n_calls_crossed[dregno] += d_n_calls;
+ }
+
/* Move death note of SRC from P to INSN. */
remove_note (p, note);
XEXP (note, 1) = REG_NOTES (insn);
return;
}
+
+ /* If SRC is a hard register which is set or killed in some other
+ way, we can't do this optimization. */
+ else if (sregno < FIRST_PSEUDO_REGISTER
+ && dead_or_set_p (p, src))
+ break;
+ }
+}
+\f
+/* INSN is a copy of SRC to DEST, in which SRC dies. See if we now have
+ a sequence of insns that modify DEST followed by an insn that sets
+ SRC to DEST in which DEST dies, with no prior modification of DEST.
+ (There is no need to check if the insns in between actually modify
+ DEST. We should not have cases where DEST is not modified, but
+ the optimization is safe if no such modification is detected.)
+ In that case, we can replace all uses of DEST, starting with INSN and
+ ending with the set of SRC to DEST, with SRC. We do not do this
+ optimization if a CALL_INSN is crossed unless SRC already crosses a
+ call.
+
+ It is assumed that DEST and SRC are pseudos; it is too complicated to do
+ this for hard registers since the substitutions we may make might fail. */
+
+static void
+optimize_reg_copy_2 (insn, dest, src)
+ rtx insn;
+ rtx dest;
+ rtx src;
+{
+ rtx p, q;
+ rtx set;
+ int sregno = REGNO (src);
+ int dregno = REGNO (dest);
+
+ for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
+ {
+ if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
+ || (GET_CODE (p) == NOTE
+ && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
+ break;
+
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+
+ set = single_set (p);
+ if (set && SET_SRC (set) == dest && SET_DEST (set) == src
+ && find_reg_note (p, REG_DEAD, dest))
+ {
+ /* We can do the optimization. Scan forward from INSN again,
+ replacing regs as we go. */
+
+ /* Set to stop at next insn. */
+ for (q = insn; q != NEXT_INSN (p); q = NEXT_INSN (q))
+ if (GET_RTX_CLASS (GET_CODE (q)) == 'i')
+ {
+ if (reg_mentioned_p (dest, PATTERN (q)))
+ {
+ PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
+
+ /* We assume that a register is used exactly once per
+ insn in the updates below. If this is not correct,
+ no great harm is done. */
+ reg_n_refs[dregno] -= loop_depth;
+ reg_n_refs[sregno] += loop_depth;
+ }
+
+
+ if (GET_CODE (q) == CALL_INSN)
+ {
+ reg_n_calls_crossed[dregno]--;
+ reg_n_calls_crossed[sregno]++;
+ }
+ }
+
+ remove_note (p, find_reg_note (p, REG_DEAD, dest));
+ reg_n_deaths[dregno]--;
+ remove_note (insn, find_reg_note (insn, REG_DEAD, src));
+ reg_n_deaths[sregno]--;
+ return;
+ }
+
+ if (reg_set_p (src, p)
+ || (GET_CODE (p) == CALL_INSN && reg_n_calls_crossed[sregno] == 0))
+ break;
}
}
\f
if (flag_expensive_optimizations && GET_CODE (dest) == REG
&& GET_CODE (SET_SRC (set)) == REG
&& ! find_reg_note (insn, REG_DEAD, SET_SRC (set)))
- optimize_reg_copy (insn, dest, SET_SRC (set));
+ optimize_reg_copy_1 (insn, dest, SET_SRC (set));
+
+ /* Similarly for a pseudo-pseudo copy when SRC is dead. */
+ else if (flag_expensive_optimizations && GET_CODE (dest) == REG
+ && REGNO (dest) >= FIRST_PSEUDO_REGISTER
+ && GET_CODE (SET_SRC (set)) == REG
+ && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER
+ && find_reg_note (insn, REG_DEAD, SET_SRC (set)))
+ optimize_reg_copy_2 (insn, dest, SET_SRC (set));
/* Otherwise, we only handle the case of a pseudo register being set
once. */
|| reg_n_sets[regno] != 1)
continue;
- note = find_reg_note (insn, REG_EQUAL, 0);
+ note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
/* Record this insn as initializing this register. */
reg_equiv_init_insn[regno] = insn;
MEM remains unchanged for the life of the register, add a REG_EQUIV
note. */
- note = find_reg_note (insn, REG_EQUIV, 0);
+ note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
if (note == 0 && reg_basic_block[regno] >= 0
&& GET_CODE (SET_SRC (set)) == MEM
int insn_number = 0;
int insn_count = 0;
int max_uid = get_max_uid ();
- short *qty_order;
+ int *qty_order;
int no_conflict_combined_regno = -1;
+ /* Counter to prevent allocating more SCRATCHes than can be stored
+ in SCRATCH_LIST. */
+ int scratches_allocated = scratch_index;
/* Count the instructions in the basic block. */
Suitable insns are those with at least two operands and where
operand 0 is an output that is a register that is not
earlyclobber.
- For a commutative operation, try (set reg0 (arithop ... reg1)).
+
+ We can tie operand 0 with some operand that dies in this insn.
+ First look for operands that are required to be in the same
+ register as operand 0. If we find such, only try tying that
+ operand or one that can be put into that operand if the
+ operation is commutative. If we don't find an operand
+ that is required to be in the same register as operand 0,
+ we can tie with any operand.
+
Subregs in place of regs are also ok.
If tying is done, WIN is set nonzero. */
if (insn_code_number >= 0
+#ifdef REGISTER_CONSTRAINTS
&& insn_n_operands[insn_code_number] > 1
&& insn_operand_constraint[insn_code_number][0][0] == '='
- && insn_operand_constraint[insn_code_number][0][1] != '&')
+ && insn_operand_constraint[insn_code_number][0][1] != '&'
+#else
+ && GET_CODE (PATTERN (insn)) == SET
+ && rtx_equal_p (SET_DEST (PATTERN (insn)), recog_operand[0])
+#endif
+ )
{
- r0 = recog_operand[0];
- r1 = recog_operand[1];
+#ifdef REGISTER_CONSTRAINTS
+ int must_match_0 = -1;
+
- /* If the first operand is an address, find a register in it.
- There may be more than one register, but we only try one of
- them. */
- if (insn_operand_constraint[insn_code_number][1][0] == 'p')
- while (GET_CODE (r1) == PLUS || GET_CODE (r1) == MULT)
- r1 = XEXP (r1, 0);
+ for (i = 1; i < insn_n_operands[insn_code_number]; i++)
+ if (requires_inout_p
+ (insn_operand_constraint[insn_code_number][i]))
+ must_match_0 = i;
+#endif
- if (GET_CODE (r0) == REG || GET_CODE (r0) == SUBREG)
+ r0 = recog_operand[0];
+ for (i = 1; i < insn_n_operands[insn_code_number]; i++)
{
- /* We have two priorities for hard register preferrences.
- If we have a move insn or an insn whose first input can
- only be in the same register as the output, give
- priority to an equivalence found from that insn. */
- int may_save_copy
- = ((SET_DEST (body) == r0 && SET_SRC (body) == r1)
- || (r1 == recog_operand[1]
- && (requires_inout_p (insn_operand_constraint[insn_code_number][1]))));
-
- if (GET_CODE (r1) == REG || GET_CODE (r1) == SUBREG)
- win = combine_regs (r1, r0, may_save_copy,
- insn_number, insn, 0);
-
- if (win == 0
- && insn_n_operands[insn_code_number] > 2
- && insn_operand_constraint[insn_code_number][1][0] == '%'
- && (r1 = recog_operand[2],
- GET_CODE (r1) == REG || GET_CODE (r1) == SUBREG))
- win = combine_regs (r1, r0, may_save_copy,
- insn_number, insn, 0);
+#ifdef REGISTER_CONSTRAINTS
+ /* Skip this operand if we found an operand that
+ must match operand 0 and this operand isn't it
+ and can't be made to be it by commutativity. */
+
+ if (must_match_0 >= 0 && i != must_match_0
+ && ! (i == must_match_0 + 1
+ && insn_operand_constraint[insn_code_number][i-1][0] == '%')
+ && ! (i == must_match_0 - 1
+ && insn_operand_constraint[insn_code_number][i][0] == '%'))
+ continue;
+#endif
+
+ r1 = recog_operand[i];
+
+ /* If the operand is an address, find a register in it.
+ There may be more than one register, but we only try one
+ of them. */
+ if (
+#ifdef REGISTER_CONSTRAINTS
+ insn_operand_constraint[insn_code_number][i][0] == 'p'
+#else
+ insn_operand_address_p[insn_code_number][i]
+#endif
+ )
+ while (GET_CODE (r1) == PLUS || GET_CODE (r1) == MULT)
+ r1 = XEXP (r1, 0);
+
+ if (GET_CODE (r0) == REG || GET_CODE (r0) == SUBREG)
+ {
+ /* We have two priorities for hard register preferences.
+ If we have a move insn or an insn whose first input
+ can only be in the same register as the output, give
+ priority to an equivalence found from that insn. */
+ int may_save_copy
+ = ((SET_DEST (body) == r0 && SET_SRC (body) == r1)
+#ifdef REGISTER_CONSTRAINTS
+ || (r1 == recog_operand[i] && must_match_0 >= 0)
+#endif
+ );
+
+ if (GET_CODE (r1) == REG || GET_CODE (r1) == SUBREG)
+ win = combine_regs (r1, r0, may_save_copy,
+ insn_number, insn, 0);
+ }
}
}
if (GET_CODE (PATTERN (insn)) == CLOBBER
&& (r0 = XEXP (PATTERN (insn), 0),
GET_CODE (r0) == REG)
- && (link = find_reg_note (insn, REG_LIBCALL, 0)) != 0
+ && (link = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0
+ && XEXP (link, 0) != 0
&& GET_CODE (XEXP (link, 0)) == INSN
&& (set = single_set (XEXP (link, 0))) != 0
&& SET_DEST (set) == r0 && SET_SRC (set) == r0
- && (note = find_reg_note (XEXP (link, 0), REG_EQUAL, 0)) != 0)
+ && (note = find_reg_note (XEXP (link, 0), REG_EQUAL,
+ NULL_RTX)) != 0)
{
if (r1 = XEXP (note, 0), GET_CODE (r1) == REG
/* Check that we have such a sequence. */
&& GET_CODE (XEXP (link, 0)) == REG)
wipe_dead_reg (XEXP (link, 0), 1);
-#ifndef SMALL_REGISTER_CLASSES
- /* Allocate quantities for any SCRATCH operands of this insn. We
- don't do this for machines with small register classes because
- those machines can use registers explicitly mentioned in the
- RTL as spill registers and our usage of hard registers
- explicitly for SCRATCH operands will conflict. On those machines,
- reload will allocate the SCRATCH. */
+ /* Allocate quantities for any SCRATCH operands of this insn. */
if (insn_code_number >= 0)
for (i = 0; i < insn_n_operands[insn_code_number]; i++)
- if (GET_CODE (recog_operand[i]) == SCRATCH)
+ if (GET_CODE (recog_operand[i]) == SCRATCH
+ && scratches_allocated++ < scratch_list_length)
alloc_qty_for_scratch (recog_operand[i], i, insn,
insn_code_number, insn_number);
-#endif
/* If this is an insn that has a REG_RETVAL note pointing at a
CLOBBER insn, we have reached the end of a REG_NO_CONFLICT
block, so clear any register number that combined within it. */
- if ((note = find_reg_note (insn, REG_RETVAL, 0)) != 0
+ if ((note = find_reg_note (insn, REG_RETVAL, NULL_RTX)) != 0
&& GET_CODE (XEXP (note, 0)) == INSN
&& GET_CODE (PATTERN (XEXP (note, 0))) == CLOBBER)
no_conflict_combined_regno = -1;
decreasing length of life. Normally call qsort, but if we
have only a very small number of quantities, sort them ourselves. */
- qty_order = (short *) alloca (next_qty * sizeof (short));
+ qty_order = (int *) alloca (next_qty * sizeof (int));
for (i = 0; i < next_qty; i++)
qty_order[i] = i;
break;
default:
- qsort (qty_order, next_qty, sizeof (short), qty_compare_1);
+ qsort (qty_order, next_qty, sizeof (int), qty_compare_1);
}
/* Try to put each quantity in a suggested physical register, if it has one.
continue;
}
- if (!qty_preferred_or_nothing[q])
- qty_phys_reg[q] = find_free_reg (ALL_REGS,
+ if (qty_alternate_class[q] != NO_REGS)
+ qty_phys_reg[q] = find_free_reg (qty_alternate_class[q],
qty_mode[q], q, 0, 0,
qty_birth[q], qty_death[q]);
}
reg_renumber[i] = qty_phys_reg[q] + reg_offset[i];
if (qty_scratch_rtx[q])
{
+ if (GET_CODE (qty_scratch_rtx[q]) == REG)
+ abort ();
PUT_CODE (qty_scratch_rtx[q], REG);
REGNO (qty_scratch_rtx[q]) = qty_phys_reg[q];
- for (i = HARD_REGNO_NREGS (qty_phys_reg[q],
- GET_MODE (qty_scratch_rtx[q])) - 1;
- i >= 0; i--)
- regs_ever_live[qty_phys_reg[q] + i] = 1;
+ scratch_block[scratch_index] = b;
+ scratch_list[scratch_index++] = qty_scratch_rtx[q];
/* Must clear the USED field, because it will have been set by
copy_rtx_if_shared, but the leaf_register code expects that
\f
/* Compare two quantities' priority for getting real registers.
We give shorter-lived quantities higher priority.
- Quantities with more references are also preferred, as are quanties that
- require multiple registers. This is the identical prioritorization as
+ Quantities with more references are also preferred, as are quantities that
+ require multiple registers. This is the identical prioritization as
done by global-alloc.
We used to give preference to registers with *longer* lives, but using
static int
qty_compare_1 (q1, q2)
- short *q1, *q2;
+ int *q1, *q2;
{
register int tem;
register int sqty;
/* Determine the numbers and sizes of registers being used. If a subreg
- is present that does not change the entire register, don't conside
+ is present that does not change the entire register, don't consider
this a copy insn. */
while (GET_CODE (usedreg) == SUBREG)
/* Update info about quantity SQTY. */
qty_n_calls_crossed[sqty] += reg_n_calls_crossed[sreg];
qty_n_refs[sqty] += reg_n_refs[sreg];
- if (! reg_preferred_or_nothing (sreg))
- qty_preferred_or_nothing[sqty] = 0;
if (usize < ssize)
{
register int i;
enum reg_class rclass = reg_preferred_class (reg);
if (reg_class_subset_p (rclass, qty_min_class[qty]))
qty_min_class[qty] = rclass;
+
+ rclass = reg_alternate_class (reg);
+ if (reg_class_subset_p (rclass, qty_alternate_class[qty]))
+ qty_alternate_class[qty] = rclass;
}
\f
/* Handle something which alters the value of an rtx REG.
/* Record the death of REG in the current insn. If OUTPUT_P is non-zero,
REG is an output that is dying (i.e., it is never used), otherwise it
- is an input (the normal case). */
+ is an input (the normal case).
+ If OUTPUT_P is 1, then we extend the life past the end of this insn. */
static void
wipe_dead_reg (reg, output_p)
{
register int regno = REGNO (reg);
+ /* If this insn has multiple results,
+ and the dead reg is used in one of the results,
+ extend its life to after this insn,
+ so it won't get allocated together with any other result of this insn. */
+ if (GET_CODE (PATTERN (this_insn)) == PARALLEL
+ && !single_set (this_insn))
+ {
+ int i;
+ for (i = XVECLEN (PATTERN (this_insn), 0) - 1; i >= 0; i--)
+ {
+ rtx set = XVECEXP (PATTERN (this_insn), 0, i);
+ if (GET_CODE (set) == SET
+ && GET_CODE (SET_DEST (set)) != REG
+ && !rtx_equal_p (reg, SET_DEST (set))
+ && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+ output_p = 1;
+ }
+ }
+
if (regno < FIRST_PSEUDO_REGISTER)
{
mark_life (regno, GET_MODE (reg), 0);
born_index, dead_index);
}
+ /* We need not check to see if the current function has nonlocal
+ labels because we don't put any pseudos that are live over calls in
+ registers in that case. */
+
if (! accept_call_clobbered
&& flag_caller_saves
&& ! just_try_suggested
rtx insn, r0, r1;
{
int ok = 0;
- rtx note = find_reg_note (insn, REG_LIBCALL, 0);
+ rtx note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
rtx p, last;
/* If R1 is a hard register, return 0 since we handle this case
return ok;
}
\f
+#ifdef REGISTER_CONSTRAINTS
+
/* Return 1 if the constraint string P indicates that the a the operand
must be equal to operand 0 and that no register is acceptable. */
return found_zero;
}
+#endif /* REGISTER_CONSTRAINTS */
\f
void
dump_local_alloc (file)