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. */
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);
}
override it. */
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;
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;
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. */
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 (INSN_P (first) && 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;
}