/* Compute register class preferences for pseudo-registers.
- Copyright (C) 1987, 1988, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* This file contains two passes of the compiler: reg_scan and reg_class.
and a function init_reg_sets to initialize the tables. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "recog.h"
#include "reload.h"
#include "real.h"
-#include "bytecode.h"
+#include "toplev.h"
+#include "output.h"
#ifndef REGISTER_MOVE_COST
#define REGISTER_MOVE_COST(x, y) 2
#endif
-#ifndef MEMORY_MOVE_COST
-#define MEMORY_MOVE_COST(x) 4
-#endif
+static void init_reg_sets_1 PROTO((void));
+static void init_reg_modes PROTO((void));
/* If we have auto-increment or auto-decrement and we can have secondary
reloads, we are not allowed to use classes requiring secondary
- reloads for psuedos auto-incremented since reload can't handle it. */
+ reloads for pseudos auto-incremented since reload can't handle it. */
#ifdef AUTO_INC_DEC
#if defined(SECONDARY_INPUT_RELOAD_CLASS) || defined(SECONDARY_OUTPUT_RELOAD_CLASS)
/* Indexed by hard register number, contains 1 for registers
that are fixed use (stack pointer, pc, frame pointer, etc.).
These are the registers that cannot be used to allocate
- a pseudo reg whose life does not cross calls. */
+ a pseudo reg for general use. */
char fixed_regs[FIRST_PSEUDO_REGISTER];
/* Indexed by hard register number, contains 1 for registers
that are fixed use or are clobbered by function calls.
These are the registers that cannot be used to allocate
- a pseudo reg whose life crosses calls. */
+ a pseudo reg whose life crosses calls unless we are able
+ to save/restore them across the calls. */
char call_used_regs[FIRST_PSEUDO_REGISTER];
HARD_REG_SET call_used_reg_set;
+/* HARD_REG_SET of registers we want to avoid caller saving. */
+HARD_REG_SET losing_caller_save_reg_set;
+
/* Data for initializing the above. */
static char initial_call_used_regs[] = CALL_USED_REGISTERS;
/* Indexed by hard register number, contains 1 for registers that are
- fixed use -- i.e. in fixed_regs -- or a function value return register
- or STRUCT_VALUE_REGNUM or STATIC_CHAIN_REGNUM. These are the
- registers that cannot hold quantities across calls even if we are
- willing to save and restore them. */
+ fixed use or call used registers that cannot hold quantities across
+ calls even if we are willing to save and restore them. call fixed
+ registers are a subset of call used registers. */
char call_fixed_regs[FIRST_PSEUDO_REGISTER];
char *reg_names[] = REGISTER_NAMES;
-/* Indexed by n, gives number of times (REG n) is set or clobbered.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation.
+/* For each hard register, the widest mode object that it can contain.
+ This will be a MODE_INT mode if the register can hold integers. Otherwise
+ it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
+ register. */
- This information applies to both hard registers and pseudo registers,
- unlike much of the information above. */
-
-short *reg_n_sets;
+enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
/* Maximum cost of moving from a register in one class to a register in
another class. Based on REGISTER_MOVE_COST. */
#endif /* FORBIDDEN_INC_DEC_CLASSES */
+#ifdef HAVE_SECONDARY_RELOADS
+
+/* Sample MEM values for use by memory_move_secondary_cost. */
+
+static rtx top_of_stack[MAX_MACHINE_MODE];
+
+#endif /* HAVE_SECONDARY_RELOADS */
+
+/* Linked list of reg_info structures allocated for reg_n_info array.
+ Grouping all of the allocated structures together in one lump
+ means only one call to bzero to clear them, rather than n smaller
+ calls. */
+struct reg_info_data {
+ struct reg_info_data *next; /* next set of reg_info structures */
+ size_t min_index; /* minimum index # */
+ size_t max_index; /* maximum index # */
+ char used_p; /* non-zero if this has been used previously */
+ reg_info data[1]; /* beginning of the reg_info data */
+};
+
+static struct reg_info_data *reg_info_head;
+
+
/* Function called only once to initialize the above data on reg usage.
Once this is done, various switches may override. */
bcopy (initial_call_used_regs, call_used_regs, sizeof call_used_regs);
bzero (global_regs, sizeof global_regs);
+ /* Do any additional initialization regsets may need */
+ INIT_ONCE_REG_SET ();
+}
+
+/* After switches have been processed, which perhaps alter
+ `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs. */
+
+static void
+init_reg_sets_1 ()
+{
+ register unsigned int i, j;
+
+ /* This macro allows the fixed or call-used registers
+ and the register classes to depend on target flags. */
+
+#ifdef CONDITIONAL_REGISTER_USAGE
+ CONDITIONAL_REGISTER_USAGE;
+#endif
+
/* Compute number of hard regs in each class. */
- bzero (reg_class_size, sizeof reg_class_size);
+ bzero ((char *) reg_class_size, sizeof reg_class_size);
for (i = 0; i < N_REG_CLASSES; i++)
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
}
}
+ /* Initialize "constant" tables. */
+
+ CLEAR_HARD_REG_SET (fixed_reg_set);
+ CLEAR_HARD_REG_SET (call_used_reg_set);
+ CLEAR_HARD_REG_SET (call_fixed_reg_set);
+
+ bcopy (fixed_regs, call_fixed_regs, sizeof call_fixed_regs);
+
+ n_non_fixed_regs = 0;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (fixed_regs[i])
+ SET_HARD_REG_BIT (fixed_reg_set, i);
+ else
+ n_non_fixed_regs++;
+
+ if (call_used_regs[i])
+ SET_HARD_REG_BIT (call_used_reg_set, i);
+ if (call_fixed_regs[i])
+ SET_HARD_REG_BIT (call_fixed_reg_set, i);
+ if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (i)))
+ SET_HARD_REG_BIT (losing_caller_save_reg_set, i);
+ }
+
/* Initialize the move cost table. Find every subset of each class
and take the maximum cost of moving any subset to any other. */
}
}
-/* After switches have been processed, which perhaps alter
- `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs. */
+/* Compute the table of register modes.
+ These values are used to record death information for individual registers
+ (as opposed to a multi-register mode). */
-void
-init_reg_sets_1 ()
+static void
+init_reg_modes ()
{
register int i;
- /* This macro allows the fixed or call-used registers
- to depend on target flags. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ reg_raw_mode[i] = choose_hard_reg_mode (i, 1);
+
+ /* If we couldn't find a valid mode, just use the previous mode.
+ ??? One situation in which we need to do this is on the mips where
+ HARD_REGNO_NREGS (fpreg, [SD]Fmode) returns 2. Ideally we'd like
+ to use DF mode for the even registers and VOIDmode for the odd
+ (for the cpu models where the odd ones are inaccessible). */
+ if (reg_raw_mode[i] == VOIDmode)
+ reg_raw_mode[i] = i == 0 ? word_mode : reg_raw_mode[i-1];
+ }
+}
-#ifdef CONDITIONAL_REGISTER_USAGE
- CONDITIONAL_REGISTER_USAGE;
+/* Finish initializing the register sets and
+ initialize the register modes. */
+
+void
+init_regs ()
+{
+ /* This finishes what was started by init_reg_sets, but couldn't be done
+ until after register usage was specified. */
+ init_reg_sets_1 ();
+
+ init_reg_modes ();
+
+#ifdef HAVE_SECONDARY_RELOADS
+ {
+ /* Make some fake stack-frame MEM references for use in
+ memory_move_secondary_cost. */
+ int i;
+ for (i = 0; i < MAX_MACHINE_MODE; i++)
+ top_of_stack[i] = gen_rtx_MEM (i, stack_pointer_rtx);
+ }
#endif
+}
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (global_regs[i])
- {
- if (call_used_regs[i] && ! fixed_regs[i])
- warning ("call-clobbered register used for global register variable");
- fixed_regs[i] = 1;
- /* Prevent saving/restoring of this reg. */
- call_used_regs[i] = 1;
- }
+#ifdef HAVE_SECONDARY_RELOADS
- /* Initialize "constant" tables. */
+/* Compute extra cost of moving registers to/from memory due to reloads.
+ Only needed if secondary reloads are required for memory moves. */
- CLEAR_HARD_REG_SET (fixed_reg_set);
- CLEAR_HARD_REG_SET (call_used_reg_set);
- CLEAR_HARD_REG_SET (call_fixed_reg_set);
+int
+memory_move_secondary_cost (mode, class, in)
+ enum machine_mode mode;
+ enum reg_class class;
+ int in;
+{
+ enum reg_class altclass;
+ int partial_cost = 0;
+ /* We need a memory reference to feed to SECONDARY... macros. */
+ rtx mem = top_of_stack[(int) mode];
- bcopy (fixed_regs, call_fixed_regs, sizeof call_fixed_regs);
-#ifdef STRUCT_VALUE_REGNUM
- call_fixed_regs[STRUCT_VALUE_REGNUM] = 1;
+ if (in)
+ {
+#ifdef SECONDARY_INPUT_RELOAD_CLASS
+ altclass = SECONDARY_INPUT_RELOAD_CLASS (class, mode, mem);
+#else
+ altclass = NO_REGS;
#endif
-#ifdef STATIC_CHAIN_REGNUM
- call_fixed_regs[STATIC_CHAIN_REGNUM] = 1;
+ }
+ else
+ {
+#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
+ altclass = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, mem);
+#else
+ altclass = NO_REGS;
#endif
+ }
- n_non_fixed_regs = 0;
+ if (altclass == NO_REGS)
+ return 0;
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- if (FUNCTION_VALUE_REGNO_P (i))
- call_fixed_regs[i] = 1;
- if (fixed_regs[i])
- SET_HARD_REG_BIT (fixed_reg_set, i);
- else
- n_non_fixed_regs++;
+ if (in)
+ partial_cost = REGISTER_MOVE_COST (altclass, class);
+ else
+ partial_cost = REGISTER_MOVE_COST (class, altclass);
- if (call_used_regs[i])
- SET_HARD_REG_BIT (call_used_reg_set, i);
- if (call_fixed_regs[i])
- SET_HARD_REG_BIT (call_fixed_reg_set, i);
- }
+ if (class == altclass)
+ /* This isn't simply a copy-to-temporary situation. Can't guess
+ what it is, so MEMORY_MOVE_COST really ought not to be calling
+ here in that case.
+
+ I'm tempted to put in an abort here, but returning this will
+ probably only give poor estimates, which is what we would've
+ had before this code anyways. */
+ return partial_cost;
+
+ /* Check if the secondary reload register will also need a
+ secondary reload. */
+ return memory_move_secondary_cost (mode, altclass, in) + partial_cost;
+}
+#endif
+
+/* Return a machine mode that is legitimate for hard reg REGNO and large
+ enough to save nregs. If we can't find one, return VOIDmode. */
+
+enum machine_mode
+choose_hard_reg_mode (regno, nregs)
+ int regno;
+ int nregs;
+{
+ enum machine_mode found_mode = VOIDmode, mode;
+
+ /* We first look for the largest integer mode that can be validly
+ held in REGNO. If none, we look for the largest floating-point mode.
+ If we still didn't find a valid mode, try CCmode. */
+
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ if (HARD_REGNO_NREGS (regno, mode) == nregs
+ && HARD_REGNO_MODE_OK (regno, mode))
+ found_mode = mode;
+
+ if (found_mode != VOIDmode)
+ return found_mode;
+
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ if (HARD_REGNO_NREGS (regno, mode) == nregs
+ && HARD_REGNO_MODE_OK (regno, mode))
+ found_mode = mode;
+
+ if (found_mode != VOIDmode)
+ return found_mode;
+
+ if (HARD_REGNO_NREGS (regno, CCmode) == nregs
+ && HARD_REGNO_MODE_OK (regno, CCmode))
+ return CCmode;
+
+ /* We can't find a mode valid for this register. */
+ return VOIDmode;
}
/* Specify the usage characteristics of the register named NAME.
{
int i;
- if (output_bytecode)
- {
- warning ("request to mark `%s' as %s ignored by bytecode compiler",
- name, call_used ? "call-used" : "fixed");
- return;
- }
-
/* Decode the name and update the primary form of
the register info. */
if ((i = decode_reg_name (name)) >= 0)
{
- fixed_regs[i] = fixed;
- call_used_regs[i] = call_used;
+ if ((i == STACK_POINTER_REGNUM
+#ifdef HARD_FRAME_POINTER_REGNUM
+ || i == HARD_FRAME_POINTER_REGNUM
+#else
+ || i == FRAME_POINTER_REGNUM
+#endif
+ )
+ && (fixed == 0 || call_used == 0))
+ {
+ static char* what_option[2][2] = {
+ { "call-saved", "call-used" },
+ { "no-such-option", "fixed" }};
+
+ error ("can't use '%s' as a %s register", name,
+ what_option[fixed][call_used]);
+ }
+ else
+ {
+ fixed_regs[i] = fixed;
+ call_used_regs[i] = call_used;
+ }
}
else
{
warning ("unknown register name: %s", name);
}
}
+
+/* Mark register number I as global. */
+
+void
+globalize_reg (i)
+ int i;
+{
+ if (global_regs[i])
+ {
+ warning ("register used for two global register variables");
+ return;
+ }
+
+ if (call_used_regs[i] && ! fixed_regs[i])
+ warning ("call-clobbered register used for global register variable");
+
+ global_regs[i] = 1;
+
+ /* If already fixed, nothing else to do. */
+ if (fixed_regs[i])
+ return;
+
+ fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1;
+ n_non_fixed_regs--;
+
+ SET_HARD_REG_BIT (fixed_reg_set, i);
+ SET_HARD_REG_BIT (call_used_reg_set, i);
+ SET_HARD_REG_BIT (call_fixed_reg_set, i);
+}
\f
/* Now the data and code for the `regclass' pass, which happens
just before local-alloc. */
static struct costs *costs;
+/* Initialized once, and used to initialize cost values for each insn. */
+
+static struct costs init_cost;
+
/* Record the same data by operand number, accumulated for each alternative
in an insn. The contribution to a pseudo is that of the minimum-cost
alternative. */
static char *altclass;
+/* Allocated buffers for prefclass and altclass. */
+static char *prefclass_buffer;
+static char *altclass_buffer;
+
/* Record the depth of loops that we are in. */
static int loop_depth;
static int loop_cost;
-static int copy_cost ();
-static void record_reg_classes ();
-static void record_address_regs ();
-
+static rtx scan_one_insn PROTO((rtx, int));
+static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *,
+ const char **, rtx));
+static int copy_cost PROTO((rtx, enum machine_mode,
+ enum reg_class, int));
+static void record_address_regs PROTO((rtx, enum reg_class, int));
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+static int auto_inc_dec_reg_p PROTO((rtx, enum machine_mode));
+#endif
+static void reg_scan_mark_refs PROTO((rtx, rtx, int, int));
/* Return the reg_class in which pseudo reg number REGNO is best allocated.
This function is sometimes called before the info has been computed.
enum reg_class
reg_alternate_class (regno)
+ int regno;
{
if (prefclass == 0)
return ALL_REGS;
return (enum reg_class) altclass[regno];
}
-/* This prevents dump_flow_info from losing if called
- before regclass is run. */
+/* Initialize some global data for this pass. */
void
regclass_init ()
{
+ int i;
+
+ init_cost.mem_cost = 10000;
+ for (i = 0; i < N_REG_CLASSES; i++)
+ init_cost.cost[i] = 10000;
+
+ /* This prevents dump_flow_info from losing if called
+ before regclass is run. */
prefclass = 0;
}
\f
+/* Subroutine of regclass, processes one insn INSN. Scan it and record each
+ time it would save code to put a certain register in a certain class.
+ PASS, when nonzero, inhibits some optimizations which need only be done
+ once.
+ Return the last insn processed, so that the scan can be continued from
+ there. */
+
+static rtx
+scan_one_insn (insn, pass)
+ rtx insn;
+ int pass;
+{
+ enum rtx_code code = GET_CODE (insn);
+ enum rtx_code pat_code;
+ const char *constraints[MAX_RECOG_OPERANDS];
+ enum machine_mode modes[MAX_RECOG_OPERANDS];
+ rtx set, note;
+ int i, j;
+
+ /* Show that an insn inside a loop is likely to be executed three
+ times more than insns outside a loop. This is much more aggressive
+ than the assumptions made elsewhere and is being tried as an
+ experiment. */
+
+ if (code == NOTE)
+ {
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+ loop_depth++, loop_cost = 1 << (2 * MIN (loop_depth, 5));
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+ loop_depth--, loop_cost = 1 << (2 * MIN (loop_depth, 5));
+
+ return insn;
+ }
+
+ if (GET_RTX_CLASS (code) != 'i')
+ return insn;
+
+ pat_code = GET_CODE (PATTERN (insn));
+ if (pat_code == USE
+ || pat_code == CLOBBER
+ || pat_code == ASM_INPUT
+ || pat_code == ADDR_VEC
+ || pat_code == ADDR_DIFF_VEC)
+ return insn;
+
+ set = single_set (insn);
+ extract_insn (insn);
+
+ for (i = 0; i < recog_n_operands; i++)
+ {
+ constraints[i] = recog_constraints[i];
+ modes[i] = recog_operand_mode[i];
+ }
+
+ /* If this insn loads a parameter from its stack slot, then
+ it represents a savings, rather than a cost, if the
+ parameter is stored in memory. Record this fact. */
+
+ if (set != 0 && GET_CODE (SET_DEST (set)) == REG
+ && GET_CODE (SET_SRC (set)) == MEM
+ && (note = find_reg_note (insn, REG_EQUIV,
+ NULL_RTX)) != 0
+ && GET_CODE (XEXP (note, 0)) == MEM)
+ {
+ costs[REGNO (SET_DEST (set))].mem_cost
+ -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)),
+ GENERAL_REGS, 1)
+ * loop_cost);
+ record_address_regs (XEXP (SET_SRC (set), 0),
+ BASE_REG_CLASS, loop_cost * 2);
+ return insn;
+ }
+
+ /* Improve handling of two-address insns such as
+ (set X (ashift CONST Y)) where CONST must be made to
+ match X. Change it into two insns: (set X CONST)
+ (set X (ashift X Y)). If we left this for reloading, it
+ would probably get three insns because X and Y might go
+ in the same place. This prevents X and Y from receiving
+ the same hard reg.
+
+ We can only do this if the modes of operands 0 and 1
+ (which might not be the same) are tieable and we only need
+ do this during our first pass. */
+
+ if (pass == 0 && optimize
+ && recog_n_operands >= 3
+ && recog_constraints[1][0] == '0'
+ && recog_constraints[1][1] == 0
+ && CONSTANT_P (recog_operand[1])
+ && ! rtx_equal_p (recog_operand[0], recog_operand[1])
+ && ! rtx_equal_p (recog_operand[0], recog_operand[2])
+ && GET_CODE (recog_operand[0]) == REG
+ && MODES_TIEABLE_P (GET_MODE (recog_operand[0]),
+ recog_operand_mode[1]))
+ {
+ rtx previnsn = prev_real_insn (insn);
+ rtx dest
+ = gen_lowpart (recog_operand_mode[1],
+ recog_operand[0]);
+ rtx newinsn
+ = emit_insn_before (gen_move_insn (dest,
+ recog_operand[1]),
+ insn);
+
+ /* If this insn was the start of a basic block,
+ include the new insn in that block.
+ We need not check for code_label here;
+ while a basic block can start with a code_label,
+ INSN could not be at the beginning of that block. */
+ if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN)
+ {
+ int b;
+ for (b = 0; b < n_basic_blocks; b++)
+ if (insn == BLOCK_HEAD (b))
+ BLOCK_HEAD (b) = newinsn;
+ }
+
+ /* This makes one more setting of new insns's dest. */
+ REG_N_SETS (REGNO (recog_operand[0]))++;
+
+ *recog_operand_loc[1] = recog_operand[0];
+ for (i = recog_n_dups - 1; i >= 0; i--)
+ if (recog_dup_num[i] == 1)
+ *recog_dup_loc[i] = recog_operand[0];
+
+ return PREV_INSN (newinsn);
+ }
+
+ /* If we get here, we are set up to record the costs of all the
+ operands for this insn. Start by initializing the costs.
+ Then handle any address registers. Finally record the desired
+ classes for any pseudos, doing it twice if some pair of
+ operands are commutative. */
+
+ for (i = 0; i < recog_n_operands; i++)
+ {
+ op_costs[i] = init_cost;
+
+ if (GET_CODE (recog_operand[i]) == SUBREG)
+ recog_operand[i] = SUBREG_REG (recog_operand[i]);
+
+ if (GET_CODE (recog_operand[i]) == MEM)
+ record_address_regs (XEXP (recog_operand[i], 0),
+ BASE_REG_CLASS, loop_cost * 2);
+ else if (constraints[i][0] == 'p')
+ record_address_regs (recog_operand[i],
+ BASE_REG_CLASS, loop_cost * 2);
+ }
+
+ /* Check for commutative in a separate loop so everything will
+ have been initialized. We must do this even if one operand
+ is a constant--see addsi3 in m68k.md. */
+
+ for (i = 0; i < recog_n_operands - 1; i++)
+ if (constraints[i][0] == '%')
+ {
+ const char *xconstraints[MAX_RECOG_OPERANDS];
+ int j;
+
+ /* Handle commutative operands by swapping the constraints.
+ We assume the modes are the same. */
+
+ for (j = 0; j < recog_n_operands; j++)
+ xconstraints[j] = constraints[j];
+
+ xconstraints[i] = constraints[i+1];
+ xconstraints[i+1] = constraints[i];
+ record_reg_classes (recog_n_alternatives, recog_n_operands,
+ recog_operand, modes, xconstraints,
+ insn);
+ }
+
+ record_reg_classes (recog_n_alternatives, recog_n_operands, recog_operand,
+ modes, constraints, insn);
+
+ /* Now add the cost for each operand to the total costs for
+ its register. */
+
+ for (i = 0; i < recog_n_operands; i++)
+ if (GET_CODE (recog_operand[i]) == REG
+ && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER)
+ {
+ int regno = REGNO (recog_operand[i]);
+ struct costs *p = &costs[regno], *q = &op_costs[i];
+
+ p->mem_cost += q->mem_cost * loop_cost;
+ for (j = 0; j < N_REG_CLASSES; j++)
+ p->cost[j] += q->cost[j] * loop_cost;
+ }
+
+ return insn;
+}
+
/* This is a pass of the compiler that scans all instructions
and calculates the preferred class for each pseudo-register.
This information can be accessed later by calling `reg_preferred_class'.
{
#ifdef REGISTER_CONSTRAINTS
register rtx insn;
- register int i, j;
- struct costs init_cost;
- rtx set;
+ register int i;
int pass;
init_recog ();
- costs = (struct costs *) alloca (nregs * sizeof (struct costs));
+ costs = (struct costs *) xmalloc (nregs * sizeof (struct costs));
#ifdef FORBIDDEN_INC_DEC_CLASSES
for (i = 0; i < N_REG_CLASSES; i++)
{
- rtx r = gen_rtx (REG, VOIDmode, 0);
+ rtx r = gen_rtx_REG (VOIDmode, 0);
enum machine_mode m;
+ register int j;
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
if (HARD_REGNO_MODE_OK (j, m))
{
PUT_MODE (r, m);
- if (0
+
+ /* If a register is not directly suitable for an
+ auto-increment or decrement addressing mode and
+ requires secondary reloads, disallow its class from
+ being used in such addresses. */
+
+ if ((0
+#ifdef SECONDARY_RELOAD_CLASS
+ || (SECONDARY_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+ != NO_REGS)
+#else
#ifdef SECONDARY_INPUT_RELOAD_CLASS
- || (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
- != NO_REGS)
+ || (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+ != NO_REGS)
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
- || (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
- != NO_REGS)
+ || (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+ != NO_REGS)
+#endif
#endif
- )
+ )
+ && ! auto_inc_dec_reg_p (r, m))
forbidden_inc_dec_class[i] = 1;
}
}
}
#endif /* FORBIDDEN_INC_DEC_CLASSES */
- init_cost.mem_cost = 10000;
- for (i = 0; i < N_REG_CLASSES; i++)
- init_cost.cost[i] = 10000;
-
/* Normally we scan the insns once and determine the best class to use for
each register. However, if -fexpensive_optimizations are on, we do so
twice, the second time using the tentative best classes to guide the
{
/* Zero out our accumulation of the cost of each class for each reg. */
- bzero (costs, nregs * sizeof (struct costs));
+ bzero ((char *) costs, nregs * sizeof (struct costs));
#ifdef FORBIDDEN_INC_DEC_CLASSES
bzero (in_inc_dec, nregs);
for (insn = f; insn; insn = NEXT_INSN (insn))
{
- char *constraints[MAX_RECOG_OPERANDS];
- enum machine_mode modes[MAX_RECOG_OPERANDS];
- int nalternatives;
- int noperands;
-
- /* Show that an insn inside a loop is likely to be executed three
- times more than insns outside a loop. This is much more aggressive
- than the assumptions made elsewhere and is being tried as an
- experiment. */
-
- if (GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
- loop_depth++, loop_cost = 1 << (2 * MIN (loop_depth, 5));
- else if (GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
- loop_depth--, loop_cost = 1 << (2 * MIN (loop_depth, 5));
-
- else if ((GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) != USE
- && GET_CODE (PATTERN (insn)) != CLOBBER
- && GET_CODE (PATTERN (insn)) != ASM_INPUT)
- || (GET_CODE (insn) == JUMP_INSN
- && GET_CODE (PATTERN (insn)) != ADDR_VEC
- && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
- || GET_CODE (insn) == CALL_INSN)
- {
- if (GET_CODE (insn) == INSN
- && (noperands = asm_noperands (PATTERN (insn))) >= 0)
- {
- decode_asm_operands (PATTERN (insn), recog_operand, NULL_PTR,
- constraints, modes);
- nalternatives = (noperands == 0 ? 0
- : n_occurrences (',', constraints[0]) + 1);
- }
- else
- {
- int insn_code_number = recog_memoized (insn);
- rtx note;
-
- set = single_set (insn);
- insn_extract (insn);
-
- nalternatives = insn_n_alternatives[insn_code_number];
- noperands = insn_n_operands[insn_code_number];
-
- /* If this insn loads a parameter from its stack slot, then
- it represents a savings, rather than a cost, if the
- parameter is stored in memory. Record this fact. */
-
- if (set != 0 && GET_CODE (SET_DEST (set)) == REG
- && GET_CODE (SET_SRC (set)) == MEM
- && (note = find_reg_note (insn, REG_EQUIV,
- NULL_RTX)) != 0
- && GET_CODE (XEXP (note, 0)) == MEM)
- {
- costs[REGNO (SET_DEST (set))].mem_cost
- -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)))
- * loop_cost);
- record_address_regs (XEXP (SET_SRC (set), 0),
- BASE_REG_CLASS, loop_cost * 2);
- continue;
- }
-
- /* Improve handling of two-address insns such as
- (set X (ashift CONST Y)) where CONST must be made to
- match X. Change it into two insns: (set X CONST)
- (set X (ashift X Y)). If we left this for reloading, it
- would probably get three insns because X and Y might go
- in the same place. This prevents X and Y from receiving
- the same hard reg.
-
- We can only do this if the modes of operands 0 and 1
- (which might not be the same) are tieable and we only need
- do this during our first pass. */
-
- if (pass == 0 && optimize
- && noperands >= 3
- && insn_operand_constraint[insn_code_number][1][0] == '0'
- && insn_operand_constraint[insn_code_number][1][1] == 0
- && CONSTANT_P (recog_operand[1])
- && ! rtx_equal_p (recog_operand[0], recog_operand[1])
- && ! rtx_equal_p (recog_operand[0], recog_operand[2])
- && GET_CODE (recog_operand[0]) == REG
- && MODES_TIEABLE_P (GET_MODE (recog_operand[0]),
- insn_operand_mode[insn_code_number][1]))
- {
- rtx previnsn = prev_real_insn (insn);
- rtx dest
- = gen_lowpart (insn_operand_mode[insn_code_number][1],
- recog_operand[0]);
- rtx newinsn
- = emit_insn_before (gen_move_insn (dest,
- recog_operand[1]),
- insn);
-
- /* If this insn was the start of a basic block,
- include the new insn in that block.
- We need not check for code_label here;
- while a basic block can start with a code_label,
- INSN could not be at the beginning of that block. */
- if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN)
- {
- int b;
- for (b = 0; b < n_basic_blocks; b++)
- if (insn == basic_block_head[b])
- basic_block_head[b] = newinsn;
- }
-
- /* This makes one more setting of new insns's dest. */
- reg_n_sets[REGNO (recog_operand[0])]++;
-
- *recog_operand_loc[1] = recog_operand[0];
- for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)
- if (recog_dup_num[i] == 1)
- *recog_dup_loc[i] = recog_operand[0];
-
- insn = PREV_INSN (newinsn);
- continue;
- }
-
- for (i = 0; i < noperands; i++)
- {
- constraints[i]
- = insn_operand_constraint[insn_code_number][i];
- modes[i] = insn_operand_mode[insn_code_number][i];
- }
- }
-
- /* If we get here, we are set up to record the costs of all the
- operands for this insn. Start by initializing the costs.
- Then handle any address registers. Finally record the desired
- classes for any pseudos, doing it twice if some pair of
- operands are commutative. */
-
- for (i = 0; i < noperands; i++)
- {
- op_costs[i] = init_cost;
-
- if (GET_CODE (recog_operand[i]) == SUBREG)
- recog_operand[i] = SUBREG_REG (recog_operand[i]);
-
- if (GET_CODE (recog_operand[i]) == MEM)
- record_address_regs (XEXP (recog_operand[i], 0),
- BASE_REG_CLASS, loop_cost * 2);
- else if (constraints[i][0] == 'p')
- record_address_regs (recog_operand[i],
- BASE_REG_CLASS, loop_cost * 2);
- }
-
- /* Check for commutative in a separate loop so everything will
- have been initialized. Don't bother doing anything if the
- second operand is a constant since that is the case
- for which the constraints should have been written. */
-
- for (i = 0; i < noperands - 1; i++)
- if (constraints[i][0] == '%'
- && ! CONSTANT_P (recog_operand[i+1]))
- {
- char *xconstraints[MAX_RECOG_OPERANDS];
- int j;
-
- /* Handle commutative operands by swapping the constraints.
- We assume the modes are the same. */
-
- for (j = 0; j < noperands; j++)
- xconstraints[j] = constraints[j];
-
- xconstraints[i] = constraints[i+1];
- xconstraints[i+1] = constraints[i];
- record_reg_classes (nalternatives, noperands,
- recog_operand, modes, xconstraints,
- insn);
- }
-
- record_reg_classes (nalternatives, noperands, recog_operand,
- modes, constraints, insn);
-
- /* Now add the cost for each operand to the total costs for
- its register. */
-
- for (i = 0; i < noperands; i++)
- if (GET_CODE (recog_operand[i]) == REG
- && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER)
- {
- int regno = REGNO (recog_operand[i]);
- struct costs *p = &costs[regno], *q = &op_costs[i];
-
- p->mem_cost += q->mem_cost * loop_cost;
- for (j = 0; j < N_REG_CLASSES; j++)
- p->cost[j] += q->cost[j] * loop_cost;
- }
- }
+ insn = scan_one_insn (insn, pass);
}
-
+
/* Now for each register look at how desirable each class is
and find which class is preferred. Store that in
`prefclass[REGNO]'. Record in `altclass[REGNO]' the largest register
if (pass == 0)
{
- prefclass = (char *) oballoc (nregs);
- altclass = (char *) oballoc (nregs);
+ prefclass = prefclass_buffer;
+ altclass = altclass_buffer;
}
for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
/* If we don't add any classes, nothing to try. */
if (alt == best)
- alt = (int) NO_REGS;
+ alt = NO_REGS;
/* We cast to (int) because (char) hits bugs in some compilers. */
prefclass[i] = (int) best;
}
}
#endif /* REGISTER_CONSTRAINTS */
+
+ free (costs);
}
\f
#ifdef REGISTER_CONSTRAINTS
int n_ops;
rtx *ops;
enum machine_mode *modes;
- char **constraints;
+ const char **constraints;
rtx insn;
{
int alt;
- enum op_type {OP_READ, OP_WRITE, OP_READ_WRITE} op_types[MAX_RECOG_OPERANDS];
int i, j;
-
- /* By default, each operand is an input operand. */
-
- for (i = 0; i < n_ops; i++)
- op_types[i] = OP_READ;
+ rtx set;
/* Process each alternative, each time minimizing an operand's cost with
the cost for each operand in that alternative. */
for (i = 0; i < n_ops; i++)
{
- char *p = constraints[i];
+ const char *p = constraints[i];
rtx op = ops[i];
enum machine_mode mode = modes[i];
+ int allows_addr = 0;
int allows_mem = 0;
int win = 0;
- char c;
+ unsigned char c;
+
+ /* Initially show we know nothing about the register class. */
+ classes[i] = NO_REGS;
/* If this operand has no constraints at all, we can conclude
nothing about it since anything is valid. */
continue;
}
- if (*p == '%')
- p++;
-
/* If this alternative is only relevant when this operand
matches a previous operand, we do different things depending
- on whether this operand is a pseudo-reg or not. */
+ on whether this operand is a pseudo-reg or not. We must process
+ any modifiers for the operand before we can make this test. */
+
+ while (*p == '%' || *p == '=' || *p == '+' || *p == '&')
+ p++;
if (p[0] >= '0' && p[0] <= '0' + i && (p[1] == ',' || p[1] == 0))
{
if (GET_CODE (op) != REG || REGNO (op) < FIRST_PSEUDO_REGISTER)
{
/* If this matches the other operand, we have no added
- cost. */
+ cost and we win. */
if (rtx_equal_p (ops[j], op))
- ;
+ win = 1;
/* If we can put the other operand into a register, add to
the cost of this alternative the cost to copy this
operand to the register used for the other operand. */
- if (classes[j] != NO_REGS)
+ else if (classes[j] != NO_REGS)
alt_cost += copy_cost (op, mode, classes[j], 1), win = 1;
}
else if (GET_CODE (ops[j]) != REG
any of the constraints. Collect the valid register classes
and see if this operand accepts memory. */
- classes[i] = NO_REGS;
while (*p && (c = *p++) != ',')
switch (c)
{
- case '=':
- op_types[i] = OP_WRITE;
- break;
-
- case '+':
- op_types[i] = OP_READ_WRITE;
- break;
-
case '*':
/* Ignore the next letter for this pass. */
p++;
break;
- case '%':
- case '?': case '!': case '#':
- case '&':
+ case '?':
+ alt_cost += 2;
+ case '!': case '#': case '&':
case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ break;
+
case 'p':
+ allows_addr = 1;
+ win = address_operand (op, GET_MODE (op));
break;
case 'm': case 'o': case 'V':
break;
case 'E':
+#ifndef REAL_ARITHMETIC
/* Match any floating double constant, but only if
we can examine the bits of it reliably. */
if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
|| HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
&& GET_MODE (op) != VOIDmode && ! flag_pretend_float)
break;
+#endif
if (GET_CODE (op) == CONST_DOUBLE)
win = 1;
break;
if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)
{
if (classes[i] == NO_REGS)
- alt_fail = 1;
+ {
+ if (! allows_addr)
+ alt_fail = 1;
+ }
else
{
struct costs *pp = &this_op_costs[i];
a bit cheaper since we won't need an extra insn to
load it. */
- pp->mem_cost = MEMORY_MOVE_COST (mode) - allows_mem;
+ pp->mem_cost = (MEMORY_MOVE_COST (mode, classes[i], 1)
+ - allows_mem);
/* If we have assigned a class to this register in our
first pass, add a cost to this alternative corresponding
if (prefclass)
alt_cost
- += may_move_cost[prefclass[REGNO (op)]][(int) classes[i]];
+ += may_move_cost[(unsigned char)prefclass[REGNO (op)]][(int) classes[i]];
}
}
else if (classes[i] != NO_REGS)
{
- if (op_types[i] != OP_WRITE)
+ if (recog_op_type[i] != OP_OUT)
alt_cost += copy_cost (op, mode, classes[i], 1);
- if (op_types[i] != OP_READ)
+ if (recog_op_type[i] != OP_IN)
alt_cost += copy_cost (op, mode, classes[i], 0);
}
/* The only other way this alternative can be used is if this is a
constant that could be placed into memory. */
- else if (CONSTANT_P (op) && allows_mem)
- alt_cost += MEMORY_MOVE_COST (mode);
+ else if (CONSTANT_P (op) && (allows_addr || allows_mem))
+ alt_cost += MEMORY_MOVE_COST (mode, classes[i], 1);
else
alt_fail = 1;
}
&& REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
{
struct costs *pp = &op_costs[i], *qq = &this_op_costs[i];
- int scale = 1 + (op_types[i] == OP_READ_WRITE);
+ int scale = 1 + (recog_op_type[i] == OP_INOUT);
pp->mem_cost = MIN (pp->mem_cost,
(qq->mem_cost + alt_cost) * scale);
(qq->cost[class] + alt_cost) * scale);
}
}
+
+ /* If this insn is a single set copying operand 1 to operand 0
+ and one is a pseudo with the other a hard reg that is in its
+ own register class, set the cost of that register class to -1. */
+
+ if ((set = single_set (insn)) != 0
+ && ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set)
+ && GET_CODE (ops[0]) == REG && GET_CODE (ops[1]) == REG)
+ for (i = 0; i <= 1; i++)
+ if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
+ {
+ int regno = REGNO (ops[!i]);
+ enum machine_mode mode = GET_MODE (ops[!i]);
+ int class;
+ int nr;
+
+ if (regno >= FIRST_PSEUDO_REGISTER && prefclass != 0
+ && (reg_class_size[(unsigned char)prefclass[regno]]
+ == CLASS_MAX_NREGS (prefclass[regno], mode)))
+ op_costs[i].cost[(unsigned char)prefclass[regno]] = -1;
+ else if (regno < FIRST_PSEUDO_REGISTER)
+ for (class = 0; class < N_REG_CLASSES; class++)
+ if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
+ && reg_class_size[class] == CLASS_MAX_NREGS (class, mode))
+ {
+ if (reg_class_size[class] == 1)
+ op_costs[i].cost[class] = -1;
+ else
+ {
+ for (nr = 0; nr < HARD_REGNO_NREGS(regno, mode); nr++)
+ {
+ if (!TEST_HARD_REG_BIT (reg_class_contents[class], regno + nr))
+ break;
+ }
+
+ if (nr == HARD_REGNO_NREGS(regno,mode))
+ op_costs[i].cost[class] = -1;
+ }
+ }
+ }
}
\f
/* Compute the cost of loading X into (if TO_P is non-zero) or from (if
enum reg_class class;
int to_p;
{
+#ifdef HAVE_SECONDARY_RELOADS
enum reg_class secondary_class = NO_REGS;
+#endif
/* If X is a SCRATCH, there is actually nothing to move since we are
assuming optimal allocation. */
else (constants). */
if (GET_CODE (x) == MEM || class == NO_REGS)
- return MEMORY_MOVE_COST (mode);
+ return MEMORY_MOVE_COST (mode, class, to_p);
else if (GET_CODE (x) == REG)
return move_cost[(int) REGNO_REG_CLASS (REGNO (x))][(int) class];
else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF)
record_address_regs (arg0, INDEX_REG_CLASS, scale);
- /* If this the sum of two registers where the first is known to be a
- pointer, it must be a base register with the second an index. */
+ /* If both operands are registers but one is already a hard register
+ of index or base class, give the other the class that the hard
+ register is not. */
+#ifdef REG_OK_FOR_BASE_P
+ else if (code0 == REG && code1 == REG
+ && REGNO (arg0) < FIRST_PSEUDO_REGISTER
+ && (REG_OK_FOR_BASE_P (arg0) || REG_OK_FOR_INDEX_P (arg0)))
+ record_address_regs (arg1,
+ REG_OK_FOR_BASE_P (arg0)
+ ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ scale);
else if (code0 == REG && code1 == REG
- && REGNO_POINTER_FLAG (REGNO (arg0)))
+ && REGNO (arg1) < FIRST_PSEUDO_REGISTER
+ && (REG_OK_FOR_BASE_P (arg1) || REG_OK_FOR_INDEX_P (arg1)))
+ record_address_regs (arg0,
+ REG_OK_FOR_BASE_P (arg1)
+ ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ scale);
+#endif
+
+ /* If one operand is known to be a pointer, it must be the base
+ with the other operand the index. Likewise if the other operand
+ is a MULT. */
+
+ else if ((code0 == REG && REGNO_POINTER_FLAG (REGNO (arg0)))
+ || code1 == MULT)
{
record_address_regs (arg0, BASE_REG_CLASS, scale);
record_address_regs (arg1, INDEX_REG_CLASS, scale);
}
+ else if ((code1 == REG && REGNO_POINTER_FLAG (REGNO (arg1)))
+ || code0 == MULT)
+ {
+ record_address_regs (arg0, INDEX_REG_CLASS, scale);
+ record_address_regs (arg1, BASE_REG_CLASS, scale);
+ }
- /* If this is the sum of two registers and neither is known to
- be a pointer, count equal chances that each might be a base
+ /* Otherwise, count equal chances that each might be a base
or index register. This case should be rare. */
- else if (code0 == REG && code1 == REG
- && ! REGNO_POINTER_FLAG (REGNO (arg0))
- && ! REGNO_POINTER_FLAG (REGNO (arg1)))
+ else
{
record_address_regs (arg0, BASE_REG_CLASS, scale / 2);
record_address_regs (arg0, INDEX_REG_CLASS, scale / 2);
record_address_regs (arg1, BASE_REG_CLASS, scale / 2);
record_address_regs (arg1, INDEX_REG_CLASS, scale / 2);
}
-
- /* In all other cases, the first operand is an index and the
- second is the base. */
-
- else
- {
- record_address_regs (arg0, INDEX_REG_CLASS, scale);
- record_address_regs (arg1, BASE_REG_CLASS, scale);
- }
}
break;
register struct costs *pp = &costs[REGNO (x)];
register int i;
- pp->mem_cost += (MEMORY_MOVE_COST (Pmode) * scale) / 2;
+ pp->mem_cost += (MEMORY_MOVE_COST (Pmode, class, 1) * scale) / 2;
for (i = 0; i < N_REG_CLASSES; i++)
pp->cost[i] += (may_move_cost[i][(int) class] * scale) / 2;
}
}
}
+\f
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+
+/* Return 1 if REG is valid as an auto-increment memory reference
+ to an object of MODE. */
+
+static int
+auto_inc_dec_reg_p (reg, mode)
+ rtx reg;
+ enum machine_mode mode;
+{
+ if (HAVE_POST_INCREMENT
+ && memory_address_p (mode, gen_rtx_POST_INC (Pmode, reg)))
+ return 1;
+
+ if (HAVE_POST_DECREMENT
+ && memory_address_p (mode, gen_rtx_POST_DEC (Pmode, reg)))
+ return 1;
+
+ if (HAVE_PRE_INCREMENT
+ && memory_address_p (mode, gen_rtx_PRE_INC (Pmode, reg)))
+ return 1;
+
+ if (HAVE_PRE_DECREMENT
+ && memory_address_p (mode, gen_rtx_PRE_DEC (Pmode, reg)))
+ return 1;
+
+ return 0;
+}
+#endif
+
#endif /* REGISTER_CONSTRAINTS */
\f
-/* This is the `regscan' pass of the compiler, run just before cse
- and again just before loop.
+static short *renumber = (short *)0;
+static size_t regno_allocated = 0;
- It finds the first and last use of each pseudo-register
- and records them in the vectors regno_first_uid, regno_last_uid
- and counts the number of sets in the vector reg_n_sets.
+/* Allocate enough space to hold NUM_REGS registers for the tables used for
+ reg_scan and flow_analysis that are indexed by the register number. If
+ NEW_P is non zero, initialize all of the registers, otherwise only
+ initialize the new registers allocated. The same table is kept from
+ function to function, only reallocating it when we need more room. If
+ RENUMBER_P is non zero, allocate the reg_renumber array also. */
- REPEAT is nonzero the second time this is called. */
+void
+allocate_reg_info (num_regs, new_p, renumber_p)
+ size_t num_regs;
+ int new_p;
+ int renumber_p;
+{
+ size_t size_info;
+ size_t size_renumber;
+ size_t min = (new_p) ? 0 : reg_n_max;
+ struct reg_info_data *reg_data;
+ struct reg_info_data *reg_next;
-/* Indexed by pseudo register number, gives uid of first insn using the reg
- (as of the time reg_scan is called). */
+ if (num_regs > regno_allocated)
+ {
+ size_t old_allocated = regno_allocated;
-int *regno_first_uid;
+ regno_allocated = num_regs + (num_regs / 20); /* add some slop space */
+ size_renumber = regno_allocated * sizeof (short);
-/* Indexed by pseudo register number, gives uid of last insn using the reg
- (as of the time reg_scan is called). */
+ if (!reg_n_info)
+ {
+ VARRAY_REG_INIT (reg_n_info, regno_allocated, "reg_n_info");
+ renumber = (short *) xmalloc (size_renumber);
+ prefclass_buffer = (char *) xmalloc (regno_allocated);
+ altclass_buffer = (char *) xmalloc (regno_allocated);
+ }
-int *regno_last_uid;
+ else
+ {
+ VARRAY_GROW (reg_n_info, regno_allocated);
-/* Indexed by pseudo register number, gives uid of last insn using the reg
- or mentioning it in a note (as of the time reg_scan is called). */
+ if (new_p) /* if we're zapping everything, no need to realloc */
+ {
+ free ((char *)renumber);
+ free ((char *)prefclass_buffer);
+ free ((char *)altclass_buffer);
+ renumber = (short *) xmalloc (size_renumber);
+ prefclass_buffer = (char *) xmalloc (regno_allocated);
+ altclass_buffer = (char *) xmalloc (regno_allocated);
+ }
-int *regno_last_note_uid;
+ else
+ {
+ renumber = (short *) xrealloc ((char *)renumber, size_renumber);
+ prefclass_buffer = (char *) xrealloc ((char *)prefclass_buffer,
+ regno_allocated);
-/* Record the number of registers we used when we allocated the above two
- tables. If we are called again with more than this, we must re-allocate
- the tables. */
+ altclass_buffer = (char *) xrealloc ((char *)altclass_buffer,
+ regno_allocated);
+ }
+ }
-static int highest_regno_in_uid_map;
+ size_info = (regno_allocated - old_allocated) * sizeof (reg_info)
+ + sizeof (struct reg_info_data) - sizeof (reg_info);
+ reg_data = (struct reg_info_data *) xcalloc (size_info, 1);
+ reg_data->min_index = old_allocated;
+ reg_data->max_index = regno_allocated - 1;
+ reg_data->next = reg_info_head;
+ reg_info_head = reg_data;
+ }
+
+ reg_n_max = num_regs;
+ if (min < num_regs)
+ {
+ /* Loop through each of the segments allocated for the actual
+ reg_info pages, and set up the pointers, zero the pages, etc. */
+ for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
+ {
+ size_t min_index = reg_data->min_index;
+ size_t max_index = reg_data->max_index;
+
+ reg_next = reg_data->next;
+ if (min <= max_index)
+ {
+ size_t max = max_index;
+ size_t local_min = min - min_index;
+ size_t i;
+
+ if (min < min_index)
+ local_min = 0;
+ if (!reg_data->used_p) /* page just allocated with calloc */
+ reg_data->used_p = 1; /* no need to zero */
+ else
+ bzero ((char *) ®_data->data[local_min],
+ sizeof (reg_info) * (max - min_index - local_min + 1));
+
+ for (i = min_index+local_min; i <= max; i++)
+ {
+ VARRAY_REG (reg_n_info, i) = ®_data->data[i-min_index];
+ REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
+ renumber[i] = -1;
+ prefclass_buffer[i] = (char) NO_REGS;
+ altclass_buffer[i] = (char) NO_REGS;
+ }
+ }
+ }
+ }
+
+ /* If {pref,alt}class have already been allocated, update the pointers to
+ the newly realloced ones. */
+ if (prefclass)
+ {
+ prefclass = prefclass_buffer;
+ altclass = altclass_buffer;
+ }
+
+ if (renumber_p)
+ reg_renumber = renumber;
+
+ /* Tell the regset code about the new number of registers */
+ MAX_REGNO_REG_SET (num_regs, new_p, renumber_p);
+}
+
+/* Free up the space allocated by allocate_reg_info. */
+void
+free_reg_info ()
+{
+ if (reg_n_info)
+ {
+ struct reg_info_data *reg_data;
+ struct reg_info_data *reg_next;
+
+ VARRAY_FREE (reg_n_info);
+ for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
+ {
+ reg_next = reg_data->next;
+ free ((char *)reg_data);
+ }
+
+ free (prefclass_buffer);
+ free (altclass_buffer);
+ prefclass_buffer = (char *)0;
+ altclass_buffer = (char *)0;
+ reg_info_head = (struct reg_info_data *)0;
+ renumber = (short *)0;
+ }
+ regno_allocated = 0;
+ reg_n_max = 0;
+}
+\f
+/* This is the `regscan' pass of the compiler, run just before cse
+ and again just before loop.
+
+ It finds the first and last use of each pseudo-register
+ and records them in the vectors regno_first_uid, regno_last_uid
+ and counts the number of sets in the vector reg_n_sets.
+
+ REPEAT is nonzero the second time this is called. */
/* Maximum number of parallel sets and clobbers in any insn in this fn.
- Always at least 3, since the combiner could put that many togetherm
+ Always at least 3, since the combiner could put that many together
and we want this to remain correct for all the remaining passes. */
int max_parallel;
-void reg_scan_mark_refs ();
-
void
reg_scan (f, nregs, repeat)
rtx f;
{
register rtx insn;
- if (!repeat || nregs > highest_regno_in_uid_map)
- {
- /* Leave some spare space in case more regs are allocated. */
- highest_regno_in_uid_map = nregs + nregs / 20;
- regno_first_uid
- = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
- regno_last_uid
- = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
- regno_last_note_uid
- = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
- reg_n_sets
- = (short *) oballoc (highest_regno_in_uid_map * sizeof (short));
- }
-
- bzero (regno_first_uid, highest_regno_in_uid_map * sizeof (int));
- bzero (regno_last_uid, highest_regno_in_uid_map * sizeof (int));
- bzero (regno_last_note_uid, highest_regno_in_uid_map * sizeof (int));
- bzero (reg_n_sets, highest_regno_in_uid_map * sizeof (short));
-
+ allocate_reg_info (nregs, TRUE, FALSE);
max_parallel = 3;
for (insn = f; insn; insn = NEXT_INSN (insn))
if (GET_CODE (PATTERN (insn)) == PARALLEL
&& XVECLEN (PATTERN (insn), 0) > max_parallel)
max_parallel = XVECLEN (PATTERN (insn), 0);
- reg_scan_mark_refs (PATTERN (insn), insn, 0);
+ reg_scan_mark_refs (PATTERN (insn), insn, 0, 0);
if (REG_NOTES (insn))
- reg_scan_mark_refs (REG_NOTES (insn), insn, 1);
+ reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0);
}
}
-/* X is the expression to scan. INSN is the insn it appears in.
- NOTE_FLAG is nonzero if X is from INSN's notes rather than its body. */
+/* Update 'regscan' information by looking at the insns
+ from FIRST to LAST. Some new REGs have been created,
+ and any REG with number greater than OLD_MAX_REGNO is
+ such a REG. We only update information for those. */
void
-reg_scan_mark_refs (x, insn, note_flag)
+reg_scan_update(first, last, old_max_regno)
+ rtx first;
+ rtx last;
+ int old_max_regno;
+{
+ register rtx insn;
+
+ allocate_reg_info (max_reg_num (), FALSE, FALSE);
+
+ for (insn = first; insn != last; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == INSN
+ || GET_CODE (insn) == CALL_INSN
+ || GET_CODE (insn) == JUMP_INSN)
+ {
+ if (GET_CODE (PATTERN (insn)) == PARALLEL
+ && XVECLEN (PATTERN (insn), 0) > max_parallel)
+ max_parallel = XVECLEN (PATTERN (insn), 0);
+ reg_scan_mark_refs (PATTERN (insn), insn, 0, old_max_regno);
+
+ if (REG_NOTES (insn))
+ reg_scan_mark_refs (REG_NOTES (insn), insn, 1, old_max_regno);
+ }
+}
+
+/* X is the expression to scan. INSN is the insn it appears in.
+ NOTE_FLAG is nonzero if X is from INSN's notes rather than its body.
+ We should only record information for REGs with numbers
+ greater than or equal to MIN_REGNO. */
+
+static void
+reg_scan_mark_refs (x, insn, note_flag, min_regno)
rtx x;
rtx insn;
int note_flag;
+ int min_regno;
{
- register enum rtx_code code = GET_CODE (x);
+ register enum rtx_code code;
register rtx dest;
register rtx note;
+ code = GET_CODE (x);
switch (code)
{
- case CONST_INT:
case CONST:
+ case CONST_INT:
case CONST_DOUBLE:
case CC0:
case PC:
{
register int regno = REGNO (x);
- regno_last_note_uid[regno] = INSN_UID (insn);
- if (!note_flag)
- regno_last_uid[regno] = INSN_UID (insn);
- if (regno_first_uid[regno] == 0)
- regno_first_uid[regno] = INSN_UID (insn);
+ if (regno >= min_regno)
+ {
+ REGNO_LAST_NOTE_UID (regno) = INSN_UID (insn);
+ if (!note_flag)
+ REGNO_LAST_UID (regno) = INSN_UID (insn);
+ if (REGNO_FIRST_UID (regno) == 0)
+ REGNO_FIRST_UID (regno) = INSN_UID (insn);
+ }
}
break;
case EXPR_LIST:
if (XEXP (x, 0))
- reg_scan_mark_refs (XEXP (x, 0), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, 0), insn, note_flag, min_regno);
if (XEXP (x, 1))
- reg_scan_mark_refs (XEXP (x, 1), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
break;
case INSN_LIST:
if (XEXP (x, 1))
- reg_scan_mark_refs (XEXP (x, 1), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
break;
case SET:
dest = XEXP (dest, 0))
;
- if (GET_CODE (dest) == REG)
- reg_n_sets[REGNO (dest)]++;
+ if (GET_CODE (dest) == REG
+ && REGNO (dest) >= min_regno)
+ REG_N_SETS (REGNO (dest))++;
/* If this is setting a pseudo from another pseudo or the sum of a
pseudo and a constant integer and the other pseudo is known to be
if (GET_CODE (SET_DEST (x)) == REG
&& REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER
+ && REGNO (SET_DEST (x)) >= min_regno
+ /* If the destination pseudo is set more than once, then other
+ sets might not be to a pointer value (consider access to a
+ union in two threads of control in the presense of global
+ optimizations). So only set REGNO_POINTER_FLAG on the destination
+ pseudo if this is the only set of that pseudo. */
+ && REG_N_SETS (REGNO (SET_DEST (x))) == 1
&& ! REG_USERVAR_P (SET_DEST (x))
&& ! REGNO_POINTER_FLAG (REGNO (SET_DEST (x)))
&& ((GET_CODE (SET_SRC (x)) == REG
|| GET_CODE (XEXP (note, 0)) == LABEL_REF))))
REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1;
- /* ... fall through ... */
+ /* ... fall through ... */
default:
{
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
- reg_scan_mark_refs (XEXP (x, i), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, i), insn, note_flag, min_regno);
else if (fmt[i] == 'E' && XVEC (x, i) != 0)
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag);
+ reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag, min_regno);
}
}
}
return 0;
}
+/* Release any memory allocated by register sets. */
+
+void
+regset_release_memory ()
+{
+ if (basic_block_live_at_start)
+ {
+ free_regset_vector (basic_block_live_at_start, n_basic_blocks);
+ basic_block_live_at_start = 0;
+ }
+
+ FREE_REG_SET (regs_live_at_setjmp);
+ bitmap_release_memory ();
+}