/* Compute register class preferences for pseudo-registers.
- Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
#define REGISTER_MOVE_COST(x, y) 2
#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 pseudos auto-incremented since reload can't handle it. */
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 ((char *) reg_class_size, sizeof reg_class_size);
}
}
- /* 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
- to depend on target flags. */
-
-#ifdef CONDITIONAL_REGISTER_USAGE
- CONDITIONAL_REGISTER_USAGE;
-#endif
-
/* Initialize "constant" tables. */
CLEAR_HARD_REG_SET (fixed_reg_set);
&& (fixed == 0 || call_used == 0))
{
static char* what_option[2][2] = {
- "call-saved", "call-used",
- "no-such-option", "fixed" };
+ { "call-saved", "call-used" },
+ { "no-such-option", "fixed" }};
error ("can't use '%s' as a %s register", name,
what_option[fixed][call_used]);
static int loop_cost;
-static int n_occurrences PROTO((int, char *));
static rtx scan_one_insn PROTO((rtx, int));
static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *,
- char **, rtx));
+ 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));
prefclass = 0;
}
\f
-/* Return the number of times character C occurs in string S. */
-static int
-n_occurrences (c, s)
- int c;
- char *s;
-{
- int n = 0;
- while (*s)
- n += (*s++ == c);
- return n;
-}
-
/* 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
{
enum rtx_code code = GET_CODE (insn);
enum rtx_code pat_code;
-
- char *constraints[MAX_RECOG_OPERANDS];
+ const char *constraints[MAX_RECOG_OPERANDS];
enum machine_mode modes[MAX_RECOG_OPERANDS];
- int nalternatives;
- int noperands;
- rtx set;
+ rtx set, note;
int i, j;
/* Show that an insn inside a loop is likely to be executed three
|| pat_code == ADDR_DIFF_VEC)
return insn;
- if (code == INSN
- && (noperands = asm_noperands (PATTERN (insn))) >= 0)
+ set = single_set (insn);
+ extract_insn (insn);
+
+ for (i = 0; i < recog_n_operands; i++)
{
- decode_asm_operands (PATTERN (insn), recog_operand, NULL_PTR,
- constraints, modes);
- nalternatives = (noperands == 0 ? 0
- : n_occurrences (',', constraints[0]) + 1);
+ constraints[i] = recog_constraints[i];
+ modes[i] = recog_operand_mode[i];
}
- else
- {
- int insn_code_number = recog_memoized (insn);
- rtx note;
- set = single_set (insn);
- insn_extract (insn);
+ /* 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. */
- nalternatives = insn_n_alternatives[insn_code_number];
- noperands = insn_n_operands[insn_code_number];
+ 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;
+ }
- /* 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. */
+ /* 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 (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)
+ /* 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)
{
- 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;
+ int b;
+ for (b = 0; b < n_basic_blocks; b++)
+ if (insn == BLOCK_HEAD (b))
+ BLOCK_HEAD (b) = newinsn;
}
- /* 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]))++;
+ /* 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];
-
- return PREV_INSN (newinsn);
- }
+ *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];
- for (i = 0; i < noperands; i++)
- {
- constraints[i]
- = insn_operand_constraint[insn_code_number][i];
- modes[i] = insn_operand_mode[insn_code_number][i];
- }
+ return PREV_INSN (newinsn);
}
/* If we get here, we are set up to record the costs of all the
classes for any pseudos, doing it twice if some pair of
operands are commutative. */
- for (i = 0; i < noperands; i++)
+ for (i = 0; i < recog_n_operands; i++)
{
op_costs[i] = init_cost;
have been initialized. We must do this even if one operand
is a constant--see addsi3 in m68k.md. */
- for (i = 0; i < noperands - 1; i++)
+ for (i = 0; i < recog_n_operands - 1; i++)
if (constraints[i][0] == '%')
{
- char *xconstraints[MAX_RECOG_OPERANDS];
+ 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 < noperands; j++)
+ 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 (nalternatives, noperands,
+ record_reg_classes (recog_n_alternatives, recog_n_operands,
recog_operand, modes, xconstraints,
insn);
}
- record_reg_classes (nalternatives, noperands, recog_operand,
+ 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 < noperands; i++)
+ for (i = 0; i < recog_n_operands; i++)
if (GET_CODE (recog_operand[i]) == REG
&& REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER)
{
{
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))
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;
rtx set;
- /* By default, each operand is an input operand. */
-
- for (i = 0; i < n_ops; i++)
- op_types[i] = OP_READ;
-
/* 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;
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))
{
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++;
case '?':
alt_cost += 2;
- case '%':
- case '!': case '#':
- case '&':
+ 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':
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];
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)
+ 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);
rtx reg;
enum machine_mode mode;
{
-#ifdef HAVE_POST_INCREMENT
- if (memory_address_p (mode, gen_rtx_POST_INC (Pmode, reg)))
+ if (HAVE_POST_INCREMENT
+ && memory_address_p (mode, gen_rtx_POST_INC (Pmode, reg)))
return 1;
-#endif
-#ifdef HAVE_POST_DECREMENT
- if (memory_address_p (mode, gen_rtx_POST_DEC (Pmode, reg)))
+ if (HAVE_POST_DECREMENT
+ && memory_address_p (mode, gen_rtx_POST_DEC (Pmode, reg)))
return 1;
-#endif
-#ifdef HAVE_PRE_INCREMENT
- if (memory_address_p (mode, gen_rtx_PRE_INC (Pmode, reg)))
+ if (HAVE_PRE_INCREMENT
+ && memory_address_p (mode, gen_rtx_PRE_INC (Pmode, reg)))
return 1;
-#endif
-#ifdef HAVE_PRE_DECREMENT
- if (memory_address_p (mode, gen_rtx_PRE_DEC (Pmode, reg)))
+ if (HAVE_PRE_DECREMENT
+ && memory_address_p (mode, gen_rtx_PRE_DEC (Pmode, reg)))
return 1;
-#endif
return 0;
}
#endif /* REGISTER_CONSTRAINTS */
\f
+static short *renumber = (short *)0;
+static size_t regno_allocated = 0;
+
/* 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
int new_p;
int renumber_p;
{
- static size_t regno_allocated = 0;
- static short *renumber = (short *)0;
- int i;
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;
- /* Free up all storage allocated */
- if (num_regs < 0)
- {
- if (reg_n_info)
- {
- 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;
- return;
- }
-
if (num_regs > regno_allocated)
{
size_t old_allocated = regno_allocated;
{
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 */
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.
code = GET_CODE (x);
switch (code)
{
- case CONST_INT:
case CONST:
+ case CONST_INT:
case CONST_DOUBLE:
case CC0:
case PC: