Copyright (C) 1987, 1988, 1991, 1994, 1996, 1997, 1998,
1999, 2000 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
#include "config.h"
5. Allocate the variables in that order; each if possible into
a preferred register, else into another register. */
\f
-/* Number of pseudo-registers which are candidates for allocation. */
+/* Number of pseudo-registers which are candidates for allocation. */
static int max_allocno;
/* Number of calls crossed by each allocno. */
int calls_crossed;
- /* Number of refs (weighted) to each allocno. */
+ /* Number of refs to each allocno. */
int n_refs;
+ /* Frequency of uses of each allocno. */
+ int freq;
+
/* Guess at live length of each allocno.
This is actually the max of the live lengths of the regs. */
int live_length;
static HARD_REG_SET regs_used_so_far;
-/* Number of refs (weighted) to each hard reg, as used by local alloc.
+/* Number of refs to each hard reg, as used by local alloc.
It is zero for a reg that contains global pseudos or is explicitly used. */
static int local_reg_n_refs[FIRST_PSEUDO_REGISTER];
+/* Frequency of uses of given hard reg. */
+static int local_reg_freq[FIRST_PSEUDO_REGISTER];
+
/* Guess at live length of each hard reg, as used by local alloc.
This is actually the sum of the live lengths of the specific regs. */
/* Build the regset of all eliminable registers and show we can't use those
that we already know won't be eliminated. */
#ifdef ELIMINABLE_REGS
- for (i = 0; i < sizeof eliminables / sizeof eliminables[0]; i++)
+ for (i = 0; i < ARRAY_SIZE (eliminables); i++)
{
SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
allocno[num].size = PSEUDO_REGNO_SIZE (i);
allocno[num].calls_crossed += REG_N_CALLS_CROSSED (i);
allocno[num].n_refs += REG_N_REFS (i);
+ allocno[num].freq += REG_FREQ (i);
if (allocno[num].live_length < REG_LIVE_LENGTH (i))
allocno[num].live_length = REG_LIVE_LENGTH (i);
}
/* Calculate amount of usage of each hard reg by pseudos
allocated by local-alloc. This is to see if we want to
override it. */
- bzero ((char *) local_reg_live_length, sizeof local_reg_live_length);
- bzero ((char *) local_reg_n_refs, sizeof local_reg_n_refs);
+ memset ((char *) local_reg_live_length, 0, sizeof local_reg_live_length);
+ memset ((char *) local_reg_n_refs, 0, sizeof local_reg_n_refs);
+ memset ((char *) local_reg_freq, 0, sizeof local_reg_freq);
for (i = FIRST_PSEUDO_REGISTER; i < (size_t) max_regno; i++)
if (reg_renumber[i] >= 0)
{
for (j = regno; j < endregno; j++)
{
local_reg_n_refs[j] += REG_N_REFS (i);
+ local_reg_freq[j] += REG_FREQ (i);
local_reg_live_length[j] += REG_LIVE_LENGTH (i);
}
}
/* We can't override local-alloc for a reg used not just by local-alloc. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (regs_ever_live[i])
- local_reg_n_refs[i] = 0;
+ local_reg_n_refs[i] = 0, local_reg_freq[i] = 0;
allocno_row_words = (max_allocno + INT_BITS - 1) / INT_BITS;
#endif
{
build_insn_chain (get_insns ());
- retval = reload (get_insns (), 1, file);
+ retval = reload (get_insns (), 1);
}
/* Clean up. */
int v1 = *(const int *)v1p, v2 = *(const int *)v2p;
/* Note that the quotient will never be bigger than
the value of floor_log2 times the maximum number of
- times a register can occur in one insn (surely less than 100).
- Multiplying this by 10000 can't overflow. */
+ times a register can occur in one insn (surely less than 100)
+ weighted by the frequency (maximally REG_FREQ_MAX).
+ Multiplying this by 10000/REG_FREQ_MAX can't overflow. */
register int pri1
- = (((double) (floor_log2 (allocno[v1].n_refs) * allocno[v1].n_refs)
+ = (((double) (floor_log2 (allocno[v1].n_refs) * allocno[v1].freq)
/ allocno[v1].live_length)
- * 10000 * allocno[v1].size);
+ * (10000 / REG_FREQ_MAX) * allocno[v1].size);
register int pri2
- = (((double) (floor_log2 (allocno[v2].n_refs) * allocno[v2].n_refs)
+ = (((double) (floor_log2 (allocno[v2].n_refs) * allocno[v2].freq)
/ allocno[v2].live_length)
- * 10000 * allocno[v2].size);
+ * (10000 / REG_FREQ_MAX) * allocno[v2].size);
if (pri2 - pri1)
return pri2 - pri1;
for (b = 0; b < n_basic_blocks; b++)
{
- bzero ((char *) allocnos_live, allocno_row_words * sizeof (INT_TYPE));
+ memset ((char *) allocnos_live, 0, allocno_row_words * sizeof (INT_TYPE));
/* Initialize table of registers currently live
to the state at the beginning of this basic block.
/* Mark any registers set in INSN and then never used. */
- while (n_regs_set > 0)
- if (find_regno_note (insn, REG_UNUSED,
- REGNO (regs_set[--n_regs_set])))
- mark_reg_death (regs_set[n_regs_set]);
+ while (n_regs_set-- > 0)
+ {
+ rtx note = find_regno_note (insn, REG_UNUSED,
+ REGNO (regs_set[n_regs_set]));
+ if (note)
+ mark_reg_death (XEXP (note, 0));
+ }
}
if (insn == BLOCK_END (b))
where this wins are reg-reg copies. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ if (INSN_P (insn)
&& (set = single_set (insn)) != 0
&& GET_CODE (SET_DEST (set)) == REG
&& reg_allocno[REGNO (SET_DEST (set))] >= 0)
variables so as to avoid excess precision problems that occur
on a i386-unknown-sysv4.2 (unixware) host. */
- double tmp1 = ((double) local_reg_n_refs[regno]
+ double tmp1 = ((double) local_reg_freq[regno]
/ local_reg_live_length[regno]);
- double tmp2 = ((double) allocno[num].n_refs
+ double tmp2 = ((double) allocno[num].freq
/ allocno[num].live_length);
if (tmp1 < tmp2)
SET_HARD_REG_BIT (regs_used_so_far, j);
/* This is no longer a reg used just by local regs. */
local_reg_n_refs[j] = 0;
+ local_reg_freq[j] = 0;
}
/* For each other pseudo-reg conflicting with this one,
mark it as conflicting with the hard regs this one occupies. */
int regno;
HARD_REG_SET forbidden_regs;
{
- int allocno = reg_allocno[regno];
- if (allocno >= 0)
+ int alloc_no = reg_allocno[regno];
+ if (alloc_no >= 0)
{
/* If we have more than one register class,
first try allocating in the class that is cheapest
for this pseudo-reg. If that fails, try any reg. */
if (N_REG_CLASSES > 1)
- find_reg (allocno, forbidden_regs, 0, 0, 1);
+ find_reg (alloc_no, forbidden_regs, 0, 0, 1);
if (reg_renumber[regno] < 0
&& reg_alternate_class (regno) != NO_REGS)
- find_reg (allocno, forbidden_regs, 1, 0, 1);
+ find_reg (alloc_no, forbidden_regs, 1, 0, 1);
/* If we found a register, modify the RTL for the register to
show the hard register, and mark that register live. */
{
register int regno;
- /* WORD is which word of a multi-register group is being stored.
- For the case where the store is actually into a SUBREG of REG.
- Except we don't use it; I believe the entire REG needs to be
- made live. */
- int word = 0;
-
if (GET_CODE (reg) == SUBREG)
- {
- word = SUBREG_WORD (reg);
- reg = SUBREG_REG (reg);
- }
+ reg = SUBREG_REG (reg);
if (GET_CODE (reg) != REG)
return;
}
if (reg_renumber[regno] >= 0)
- regno = reg_renumber[regno] /* + word */;
+ regno = reg_renumber[regno];
/* Handle hardware regs (and pseudos allocated to hard regs). */
if (regno < FIRST_PSEUDO_REGISTER && ! fixed_regs[regno])
else if (GET_CODE (src) == SUBREG && GET_CODE (SUBREG_REG (src)) == REG)
{
src_regno = REGNO (SUBREG_REG (src));
- offset += SUBREG_WORD (src);
+
+ if (REGNO (SUBREG_REG (src)) < FIRST_PSEUDO_REGISTER)
+ offset += subreg_regno_offset (REGNO (SUBREG_REG (src)),
+ GET_MODE (SUBREG_REG (src)),
+ SUBREG_BYTE (src),
+ GET_MODE (src));
+ else
+ offset += (SUBREG_BYTE (src)
+ / REGMODE_NATURAL_SIZE (GET_MODE (src)));
}
else
return;
else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG)
{
dest_regno = REGNO (SUBREG_REG (dest));
- offset -= SUBREG_WORD (dest);
+
+ if (REGNO (SUBREG_REG (dest)) < FIRST_PSEUDO_REGISTER)
+ offset -= subreg_regno_offset (REGNO (SUBREG_REG (dest)),
+ GET_MODE (SUBREG_REG (dest)),
+ SUBREG_BYTE (dest),
+ GET_MODE (dest));
+ else
+ offset -= (SUBREG_BYTE (dest)
+ / REGMODE_NATURAL_SIZE (GET_MODE (dest)));
}
else
return;
c->insn = first;
c->block = b;
- if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
+ if (INSN_P (first))
{
rtx link;
else
COPY_REG_SET (&c->live_throughout, live_relevant_regs);
- if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
+ if (INSN_P (first))
{
rtx link;
no real insns are after the end of the last basic block.
We may want to reorganize the loop somewhat since this test should
- always be the right exit test. */
+ always be the right exit test. Allow an ADDR_VEC or ADDR_DIF_VEC if
+ the previous real insn is a JUMP_INSN. */
if (b == n_basic_blocks)
{
for (first = NEXT_INSN (first) ; first; first = NEXT_INSN (first))
- if (GET_RTX_CLASS (GET_CODE (first)) == 'i'
- && GET_CODE (PATTERN (first)) != USE)
+ if (INSN_P (first)
+ && GET_CODE (PATTERN (first)) != USE
+ && ! ((GET_CODE (PATTERN (first)) == ADDR_VEC
+ || GET_CODE (PATTERN (first)) == ADDR_DIFF_VEC)
+ && prev_real_insn (first) != 0
+ && GET_CODE (prev_real_insn (first)) == JUMP_INSN))
abort ();
break;
}