/* Compute register class preferences for pseudo-registers.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996
- 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+ 1997, 1998, 1999, 2000, 2001 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. */
/* This file contains two passes of the compiler: reg_scan and reg_class.
#include "config.h"
#include "system.h"
#include "rtl.h"
+#include "expr.h"
#include "tm_p.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "ggc.h"
#ifndef REGISTER_MOVE_COST
-#define REGISTER_MOVE_COST(x, y) 2
+#define REGISTER_MOVE_COST(m, x, y) 2
#endif
static void init_reg_sets_1 PARAMS ((void));
/* Data for initializing the above. */
-static char initial_fixed_regs[] = FIXED_REGISTERS;
+static const char initial_fixed_regs[] = FIXED_REGISTERS;
/* Indexed by hard register number, contains 1 for registers
that are fixed use or are clobbered by function calls.
/* Data for initializing the above. */
-static char initial_call_used_regs[] = CALL_USED_REGISTERS;
+static const char initial_call_used_regs[] = CALL_USED_REGISTERS;
+
+/* This is much like call_used_regs, except it doesn't have to
+ be a superset of FIXED_REGISTERS. This vector indicates
+ what is really call clobbered, and is used when defining
+ regs_invalidated_by_call. */
+
+#ifdef CALL_REALLY_USED_REGISTERS
+char call_really_used_regs[] = CALL_REALLY_USED_REGISTERS;
+#endif
/* Indexed by hard register number, contains 1 for registers that are
fixed use or call used registers that cannot hold quantities across
and are also considered fixed. */
char global_regs[FIRST_PSEUDO_REGISTER];
-
+
+/* Contains 1 for registers that are set or clobbered by calls. */
+/* ??? Ideally, this would be just call_used_regs plus global_regs, but
+ for someone's bright idea to have call_used_regs strictly include
+ fixed_regs. Which leaves us guessing as to the set of fixed_regs
+ that are actually preserved. We know for sure that those associated
+ with the local stack frame are safe, but scant others. */
+
+HARD_REG_SET regs_invalidated_by_call;
+
/* Table of register numbers in the order in which to try to use them. */
#ifdef REG_ALLOC_ORDER
int reg_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER;
/* The same information, but as an array of unsigned ints. We copy from
these unsigned ints to the table above. We do this so the tm.h files
- do not have to be aware of the wordsize for machines with <= 64 regs. */
+ do not have to be aware of the wordsize for machines with <= 64 regs.
+ Note that we hard-code 32 here, not HOST_BITS_PER_INT. */
#define N_REG_INTS \
- ((FIRST_PSEUDO_REGISTER + (HOST_BITS_PER_INT - 1)) / HOST_BITS_PER_INT)
+ ((FIRST_PSEUDO_REGISTER + (32 - 1)) / 32)
static unsigned int_reg_class_contents[N_REG_CLASSES][N_REG_INTS]
= REG_CLASS_CONTENTS;
enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
+/* 1 if class does contain register of given mode. */
+
+static char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
+
/* Maximum cost of moving from a register in one class to a register in
another class. Based on REGISTER_MOVE_COST. */
-static int move_cost[N_REG_CLASSES][N_REG_CLASSES];
+static int move_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
/* Similar, but here we don't have to move if the first index is a subset
of the second so in that case the cost is zero. */
-static int may_move_in_cost[N_REG_CLASSES][N_REG_CLASSES];
+static int may_move_in_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
/* Similar, but here we don't have to move if the first index is a superset
of the second so in that case the cost is zero. */
-static int may_move_out_cost[N_REG_CLASSES][N_REG_CLASSES];
+static int may_move_out_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
#ifdef FORBIDDEN_INC_DEC_CLASSES
static struct reg_info_data *reg_info_head;
/* No more global register variables may be declared; true once
- regclass has been initialized. */
+ regclass has been initialized. */
static int no_global_reg_vars = 0;
void
init_reg_sets ()
{
- register int i, j;
+ int i, j;
/* First copy the register information from the initial int form into
the regsets. */
{
CLEAR_HARD_REG_SET (reg_class_contents[i]);
+ /* Note that we hard-code 32 here, not HOST_BITS_PER_INT. */
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
- if (int_reg_class_contents[i][j / HOST_BITS_PER_INT]
- & ((unsigned) 1 << (j % HOST_BITS_PER_INT)))
+ if (int_reg_class_contents[i][j / 32]
+ & ((unsigned) 1 << (j % 32)))
SET_HARD_REG_BIT (reg_class_contents[i], j);
}
static void
init_reg_sets_1 ()
{
- register unsigned int i, j;
+ unsigned int i, j;
+ unsigned int /* enum machine_mode */ m;
+ char allocatable_regs_of_mode [MAX_MACHINE_MODE];
/* This macro allows the fixed or call-used registers
and the register classes to depend on target flags. */
register /* Declare it register if it's a scalar. */
#endif
HARD_REG_SET c;
- register int k;
+ int k;
COPY_HARD_REG_SET (c, reg_class_contents[i]);
IOR_HARD_REG_SET (c, reg_class_contents[j]);
register /* Declare it register if it's a scalar. */
#endif
HARD_REG_SET c;
- register int k;
+ int k;
COPY_HARD_REG_SET (c, reg_class_contents[i]);
IOR_HARD_REG_SET (c, reg_class_contents[j]);
CLEAR_HARD_REG_SET (fixed_reg_set);
CLEAR_HARD_REG_SET (call_used_reg_set);
CLEAR_HARD_REG_SET (call_fixed_reg_set);
+ CLEAR_HARD_REG_SET (regs_invalidated_by_call);
memcpy (call_fixed_regs, fixed_regs, sizeof call_fixed_regs);
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);
+
+ /* There are a couple of fixed registers that we know are safe to
+ exclude from being clobbered by calls:
+
+ The frame pointer is always preserved across calls. The arg pointer
+ is if it is fixed. The stack pointer usually is, unless
+ RETURN_POPS_ARGS, in which case an explicit CLOBBER will be present.
+ If we are generating PIC code, the PIC offset table register is
+ preserved across calls, though the target can override that. */
+
+ if (i == STACK_POINTER_REGNUM || i == FRAME_POINTER_REGNUM)
+ ;
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ else if (i == HARD_FRAME_POINTER_REGNUM)
+ ;
+#endif
+#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ else if (i == ARG_POINTER_REGNUM && fixed_regs[i])
+ ;
+#endif
+#ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+ else if (i == PIC_OFFSET_TABLE_REGNUM && flag_pic)
+ ;
+#endif
+ else if (0
+#ifdef CALL_REALLY_USED_REGISTERS
+ || call_really_used_regs[i]
+#else
+ || call_used_regs[i]
+#endif
+ || global_regs[i])
+ SET_HARD_REG_BIT (regs_invalidated_by_call, i);
}
+ memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode));
+ memset (allocatable_regs_of_mode, 0, sizeof (allocatable_regs_of_mode));
+ for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
+ for (i = 0; i < N_REG_CLASSES; i++)
+ if (CLASS_MAX_NREGS (i, m) <= reg_class_size[i])
+ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+ if (!fixed_regs [j] && TEST_HARD_REG_BIT (reg_class_contents[i], j)
+ && HARD_REGNO_MODE_OK (j, m))
+ {
+ contains_reg_of_mode [i][m] = 1;
+ allocatable_regs_of_mode [m] = 1;
+ break;
+ }
+
/* Initialize the move cost table. Find every subset of each class
and take the maximum cost of moving any subset to any other. */
- for (i = 0; i < N_REG_CLASSES; i++)
- for (j = 0; j < N_REG_CLASSES; j++)
+ for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
+ if (allocatable_regs_of_mode [m])
{
- int cost = i == j ? 2 : REGISTER_MOVE_COST (i, j);
- enum reg_class *p1, *p2;
-
- for (p2 = ®_class_subclasses[j][0]; *p2 != LIM_REG_CLASSES; p2++)
- if (*p2 != i)
- cost = MAX (cost, REGISTER_MOVE_COST (i, *p2));
-
- for (p1 = ®_class_subclasses[i][0]; *p1 != LIM_REG_CLASSES; p1++)
- {
- if (*p1 != j)
- cost = MAX (cost, REGISTER_MOVE_COST (*p1, j));
-
- for (p2 = ®_class_subclasses[j][0];
- *p2 != LIM_REG_CLASSES; p2++)
- if (*p1 != *p2)
- cost = MAX (cost, REGISTER_MOVE_COST (*p1, *p2));
- }
-
- move_cost[i][j] = cost;
-
- if (reg_class_subset_p (i, j))
- may_move_in_cost[i][j] = 0;
- else
- may_move_in_cost[i][j] = cost;
-
- if (reg_class_subset_p (j, i))
- may_move_out_cost[i][j] = 0;
- else
- may_move_out_cost[i][j] = cost;
+ for (i = 0; i < N_REG_CLASSES; i++)
+ if (contains_reg_of_mode [i][m])
+ for (j = 0; j < N_REG_CLASSES; j++)
+ {
+ int cost;
+ enum reg_class *p1, *p2;
+
+ if (!contains_reg_of_mode [j][m])
+ {
+ move_cost[m][i][j] = 65536;
+ may_move_in_cost[m][i][j] = 65536;
+ may_move_out_cost[m][i][j] = 65536;
+ }
+ else
+ {
+ cost = REGISTER_MOVE_COST (m, i, j);
+
+ for (p2 = ®_class_subclasses[j][0];
+ *p2 != LIM_REG_CLASSES;
+ p2++)
+ if (*p2 != i && contains_reg_of_mode [*p2][m])
+ cost = MAX (cost, move_cost [m][i][*p2]);
+
+ for (p1 = ®_class_subclasses[i][0];
+ *p1 != LIM_REG_CLASSES;
+ p1++)
+ if (*p1 != j && contains_reg_of_mode [*p1][m])
+ cost = MAX (cost, move_cost [m][*p1][j]);
+
+ move_cost[m][i][j] = cost;
+
+ if (reg_class_subset_p (i, j))
+ may_move_in_cost[m][i][j] = 0;
+ else
+ may_move_in_cost[m][i][j] = cost;
+
+ if (reg_class_subset_p (j, i))
+ may_move_out_cost[m][i][j] = 0;
+ else
+ may_move_out_cost[m][i][j] = cost;
+ }
+ }
+ else
+ for (j = 0; j < N_REG_CLASSES; j++)
+ {
+ move_cost[m][i][j] = 65536;
+ may_move_in_cost[m][i][j] = 65536;
+ may_move_out_cost[m][i][j] = 65536;
+ }
}
#ifdef CLASS_CANNOT_CHANGE_MODE
static void
init_reg_modes ()
{
- register int i;
+ int i;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
enum reg_class altclass;
int partial_cost = 0;
/* We need a memory reference to feed to SECONDARY... macros. */
- /* mem may be unused even if the SECONDARY_ macros are defined. */
+ /* mem may be unused even if the SECONDARY_ macros are defined. */
rtx mem ATTRIBUTE_UNUSED = top_of_stack[(int) mode];
return 0;
if (in)
- partial_cost = REGISTER_MOVE_COST (altclass, class);
+ partial_cost = REGISTER_MOVE_COST (mode, altclass, class);
else
- partial_cost = REGISTER_MOVE_COST (class, altclass);
+ partial_cost = REGISTER_MOVE_COST (mode, class, altclass);
if (class == altclass)
/* This isn't simply a copy-to-temporary situation. Can't guess
unsigned int regno ATTRIBUTE_UNUSED;
unsigned int nregs;
{
+ unsigned int /* enum machine_mode */ m;
enum machine_mode found_mode = VOIDmode, mode;
/* We first look for the largest integer mode that can be validly
return found_mode;
/* Iterate over all of the CCmodes. */
- for (mode = CCmode; mode < NUM_MACHINE_MODES; ++mode)
- if (HARD_REGNO_NREGS (regno, mode) == nregs
- && HARD_REGNO_MODE_OK (regno, mode))
- return mode;
+ for (m = (unsigned int) CCmode; m < (unsigned int) NUM_MACHINE_MODES; ++m)
+ {
+ mode = (enum machine_mode) m;
+ if (HARD_REGNO_NREGS (regno, mode) == nregs
+ && HARD_REGNO_MODE_OK (regno, mode))
+ return mode;
+ }
/* We can't find a mode valid for this register. */
return VOIDmode;
{
fixed_regs[i] = fixed;
call_used_regs[i] = call_used;
+#ifdef CALL_REALLY_USED_REGISTERS
+ if (fixed == 0)
+ call_really_used_regs[i] = call_used;
+#endif
}
}
else
static struct reg_pref *reg_pref;
-/* Allocated buffers for reg_pref. */
+/* Allocated buffers for reg_pref. */
static struct reg_pref *reg_pref_buffer;
-/* Account for the fact that insns within a loop are executed very commonly,
- but don't keep doing this as loops go too deep. */
+/* Frequency of executions of current insn. */
-static int loop_cost;
+static int frequency;
static rtx scan_one_insn PARAMS ((rtx, int));
static void record_operand_costs PARAMS ((rtx, struct costs *, struct reg_pref *));
before regclass is run. */
reg_pref = NULL;
- /* No more global register variables may be declared. */
+ /* No more global register variables may be declared. */
no_global_reg_vars = 1;
}
\f
int i;
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
{
- enum reg_class class;
+ int /* enum reg_class */ class;
if (REG_N_REFS (i))
{
fprintf (dump, " Register %i costs:", i);
- for (class = 0; class < N_REG_CLASSES; class++)
- fprintf (dump, " %s:%i", reg_class_names[(int) class],
- costs[i].cost[class]);
+ for (class = 0; class < (int) N_REG_CLASSES; class++)
+ if (contains_reg_of_mode [(enum reg_class) class][PSEUDO_REGNO_MODE (i)]
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+ && (!in_inc_dec[i]
+ || !forbidden_inc_dec_class[(enum reg_class) class])
+#endif
+#ifdef CLASS_CANNOT_CHANGE_MODE
+ && (!REGNO_REG_SET_P (reg_changes_mode, i)
+ || class_can_change_mode [(enum reg_class) class])
+#endif
+ )
+ fprintf (dump, " %s:%i", reg_class_names[class],
+ costs[i].cost[(enum reg_class) class]);
fprintf (dump, " MEM:%i\n", costs[i].mem_cost);
}
}
if (GET_CODE (recog_data.operand[i]) == MEM)
record_address_regs (XEXP (recog_data.operand[i], 0),
- BASE_REG_CLASS, loop_cost * 2);
+ BASE_REG_CLASS, frequency * 2);
else if (constraints[i][0] == 'p')
record_address_regs (recog_data.operand[i],
- BASE_REG_CLASS, loop_cost * 2);
+ BASE_REG_CLASS, frequency * 2);
}
/* Check for commutative in a separate loop so everything will
costs[REGNO (SET_DEST (set))].mem_cost
-= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)),
GENERAL_REGS, 1)
- * loop_cost);
+ * frequency);
record_address_regs (XEXP (SET_SRC (set), 0),
- BASE_REG_CLASS, loop_cost * 2);
+ BASE_REG_CLASS, frequency * 2);
return insn;
}
/* This makes one more setting of new insns's dest. */
REG_N_SETS (REGNO (recog_data.operand[0]))++;
+ REG_N_REFS (REGNO (recog_data.operand[0]))++;
+ REG_FREQ (REGNO (recog_data.operand[0])) += frequency;
*recog_data.operand_loc[1] = recog_data.operand[0];
+ REG_N_REFS (REGNO (recog_data.operand[0]))++;
+ REG_FREQ (REGNO (recog_data.operand[0])) += frequency;
for (i = recog_data.n_dups - 1; i >= 0; i--)
if (recog_data.dup_num[i] == 1)
- *recog_data.dup_loc[i] = recog_data.operand[0];
+ {
+ *recog_data.dup_loc[i] = recog_data.operand[0];
+ REG_N_REFS (REGNO (recog_data.operand[0]))++;
+ REG_FREQ (REGNO (recog_data.operand[0])) += frequency;
+ }
return PREV_INSN (newinsn);
}
int regno = REGNO (recog_data.operand[i]);
struct costs *p = &costs[regno], *q = &op_costs[i];
- p->mem_cost += q->mem_cost * loop_cost;
+ p->mem_cost += q->mem_cost * frequency;
for (j = 0; j < N_REG_CLASSES; j++)
- p->cost[j] += q->cost[j] * loop_cost;
+ p->cost[j] += q->cost[j] * frequency;
}
return insn;
int nregs;
FILE *dump;
{
- register rtx insn;
- register int i;
+ rtx insn;
+ int i;
int pass;
init_recog ();
{
rtx r = gen_rtx_REG (VOIDmode, 0);
enum machine_mode m;
- register int j;
+ int j;
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
if (!optimize)
{
- loop_cost = 1;
+ frequency = REG_FREQ_MAX;
for (insn = f; insn; insn = NEXT_INSN (insn))
insn = scan_one_insn (insn, pass);
}
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 (optimize_size)
- loop_cost = 1;
- else
- loop_cost = 1 << (2 * MIN (bb->loop_depth, 5));
+ frequency = REG_FREQ_FROM_BB (bb);
for (insn = bb->head; ; insn = NEXT_INSN (insn))
{
insn = scan_one_insn (insn, pass);
}
for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
{
- register int best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
+ int best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
enum reg_class best = ALL_REGS, alt = NO_REGS;
/* This is an enum reg_class, but we call it an int
to save lots of casts. */
- register int class;
- register struct costs *p = &costs[i];
+ int class;
+ struct costs *p = &costs[i];
/* In non-optimizing compilation REG_N_REFS is not initialized
yet. */
for (class = (int) ALL_REGS - 1; class > 0; class--)
{
/* Ignore classes that are too small for this operand or
- invalid for a operand that was auto-incremented. */
- if (CLASS_MAX_NREGS (class, PSEUDO_REGNO_MODE (i))
- > reg_class_size[class]
+ invalid for an operand that was auto-incremented. */
+ if (!contains_reg_of_mode [class][PSEUDO_REGNO_MODE (i)]
#ifdef FORBIDDEN_INC_DEC_CLASSES
|| (in_inc_dec[i] && forbidden_inc_dec_class[class])
#endif
for (class = 0; class < N_REG_CLASSES; class++)
pp->cost[class]
= ((recog_data.operand_type[i] != OP_OUT
- ? may_move_in_cost[class][(int) classes[i]]
+ ? may_move_in_cost[mode][class][(int) classes[i]]
: 0)
+ (recog_data.operand_type[i] != OP_IN
- ? may_move_out_cost[(int) classes[i]][class]
+ ? may_move_out_cost[mode][(int) classes[i]][class]
: 0));
/* If the alternative actually allows memory, make things
if (reg_pref)
alt_cost
- += (may_move_in_cost[(unsigned char) reg_pref[REGNO (op)].prefclass]
+ += (may_move_in_cost[mode]
+ [(unsigned char) reg_pref[REGNO (op)].prefclass]
[(int) classes[i]]);
if (REGNO (ops[i]) != REGNO (ops[j])
for (class = 0; class < N_REG_CLASSES; class++)
pp->cost[class]
= ((recog_data.operand_type[i] != OP_OUT
- ? may_move_in_cost[class][(int) classes[i]]
+ ? may_move_in_cost[mode][class][(int) classes[i]]
: 0)
+ (recog_data.operand_type[i] != OP_IN
- ? may_move_out_cost[(int) classes[i]][class]
+ ? may_move_out_cost[mode][(int) classes[i]][class]
: 0));
/* If the alternative actually allows memory, make things
if (reg_pref)
alt_cost
- += (may_move_in_cost[(unsigned char) reg_pref[REGNO (op)].prefclass]
+ += (may_move_in_cost[mode]
+ [(unsigned char) reg_pref[REGNO (op)].prefclass]
[(int) classes[i]]);
}
}
if ((reg_class_size[(unsigned char) pref]
== CLASS_MAX_NREGS (pref, mode))
- && REGISTER_MOVE_COST (pref, pref) < 10 * 2)
+ && REGISTER_MOVE_COST (mode, pref, pref) < 10 * 2)
op_costs[i].cost[(unsigned char) pref] = -1;
}
else if (regno < FIRST_PSEUDO_REGISTER)
#endif
if (secondary_class != NO_REGS)
- return (move_cost[(int) secondary_class][(int) class]
+ return (move_cost[mode][(int) secondary_class][(int) class]
+ copy_cost (x, mode, secondary_class, 2));
#endif /* HAVE_SECONDARY_RELOADS */
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];
+ return move_cost[mode][(int) REGNO_REG_CLASS (REGNO (x))][(int) class];
else
/* If this is a constant, we may eventually want to call rtx_cost here. */
enum reg_class class;
int scale;
{
- register enum rtx_code code = GET_CODE (x);
+ enum rtx_code code = GET_CODE (x);
switch (code)
{
{
rtx arg0 = XEXP (x, 0);
rtx arg1 = XEXP (x, 1);
- register enum rtx_code code0 = GET_CODE (arg0);
- register enum rtx_code code1 = GET_CODE (arg1);
+ enum rtx_code code0 = GET_CODE (arg0);
+ enum rtx_code code1 = GET_CODE (arg1);
/* Look inside subregs. */
if (code0 == SUBREG)
case REG:
{
- register struct costs *pp = &costs[REGNO (x)];
- register int i;
+ struct costs *pp = &costs[REGNO (x)];
+ int i;
pp->mem_cost += (MEMORY_MOVE_COST (Pmode, class, 1) * scale) / 2;
for (i = 0; i < N_REG_CLASSES; i++)
- pp->cost[i] += (may_move_in_cost[i][(int) class] * scale) / 2;
+ pp->cost[i] += (may_move_in_cost[Pmode][i][(int) class] * scale) / 2;
}
break;
default:
{
- register const char *fmt = GET_RTX_FORMAT (code);
- register int i;
+ const char *fmt = GET_RTX_FORMAT (code);
+ int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
record_address_regs (XEXP (x, i), class, scale);
/* Maximum number of parallel sets and clobbers in any insn in this fn.
Always at least 3, since the combiner could put that many together
- and we want this to remain correct for all the remaining passes. */
+ and we want this to remain correct for all the remaining passes.
+ This corresponds to the maximum number of times note_stores will call
+ a function for any insn. */
int max_parallel;
+/* Used as a temporary to record the largest number of registers in
+ PARALLEL in a SET_DEST. This is added to max_parallel. */
+
+static int max_set_parallel;
+
void
reg_scan (f, nregs, repeat)
rtx f;
unsigned int nregs;
int repeat ATTRIBUTE_UNUSED;
{
- register rtx insn;
+ rtx insn;
allocate_reg_info (nregs, TRUE, FALSE);
max_parallel = 3;
+ max_set_parallel = 0;
for (insn = f; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == INSN
if (REG_NOTES (insn))
reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0);
}
+
+ max_parallel += max_set_parallel;
}
/* Update 'regscan' information by looking at the insns
rtx last;
unsigned int old_max_regno;
{
- register rtx insn;
+ rtx insn;
allocate_reg_info (max_reg_num (), FALSE, FALSE);
int note_flag;
unsigned int min_regno;
{
- register enum rtx_code code;
- register rtx dest;
- register rtx note;
+ enum rtx_code code;
+ rtx dest;
+ rtx note;
code = GET_CODE (x);
switch (code)
dest = XEXP (dest, 0))
;
+ /* For a PARALLEL, record the number of things (less the usual one for a
+ SET) that are set. */
+ if (GET_CODE (dest) == PARALLEL)
+ max_set_parallel = MAX (max_set_parallel, XVECLEN (dest, 0) - 1);
+
if (GET_CODE (dest) == REG
&& REGNO (dest) >= min_regno)
- REG_N_SETS (REGNO (dest))++;
+ {
+ REG_N_SETS (REGNO (dest))++;
+ REG_N_REFS (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
|| GET_CODE (XEXP (note, 0)) == LABEL_REF))))
REG_POINTER (SET_DEST (x)) = 1;
+ /* If this is setting a register from a register or from a simple
+ conversion of a register, propagate REG_DECL. */
+ if (GET_CODE (dest) == REG)
+ {
+ rtx src = SET_SRC (x);
+
+ while (GET_CODE (src) == SIGN_EXTEND
+ || GET_CODE (src) == ZERO_EXTEND
+ || GET_CODE (src) == TRUNCATE
+ || (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)))
+ src = XEXP (src, 0);
+
+ if (GET_CODE (src) == REG && REGNO_DECL (REGNO (src)) == 0)
+ REGNO_DECL (REGNO (src)) = REGNO_DECL (REGNO (dest));
+ else if (GET_CODE (src) == REG && REGNO_DECL (REGNO (dest)) == 0)
+ REGNO_DECL (REGNO (dest)) = REGNO_DECL (REGNO (src));
+ }
+
/* ... fall through ... */
default:
{
- register const char *fmt = GET_RTX_FORMAT (code);
- register int i;
+ const char *fmt = GET_RTX_FORMAT (code);
+ int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
reg_scan_mark_refs (XEXP (x, i), insn, note_flag, min_regno);
else if (fmt[i] == 'E' && XVEC (x, i) != 0)
{
- register int j;
+ int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag, min_regno);
}
int
reg_class_subset_p (c1, c2)
- register enum reg_class c1;
- register enum reg_class c2;
+ enum reg_class c1;
+ enum reg_class c2;
{
if (c1 == c2) return 1;
int
reg_classes_intersect_p (c1, c2)
- register enum reg_class c1;
- register enum reg_class c2;
+ enum reg_class c1;
+ enum reg_class c2;
{
#ifdef HARD_REG_SET
register