Commit 61719ba7 by Bernd Schmidt Committed by Jeff Law

regclass.c (regclass): Break out some code into new function scan_one_insn, and into regclass_init.

        * regclass.c (regclass): Break out some code into new function
        scan_one_insn, and into regclass_init.
        (init_cost): New static variable, moved out of regclass.
        (regclass_init): Initialize it here, not in .
        (scan_one_insn): New static function, broken out of regclass.
        * recog.c (apply_change_group): Break out some code into new
        function insn_invalid_p.
        (insn_invalid_p): New static fn, broken out of apply_change_group.

From-SVN: r23236
parent 04bbb0c5
Fri Oct 23 00:07:01 1998 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
* regclass.c (regclass): Break out some code into new function
scan_one_insn, and into regclass_init.
(init_cost): New static variable, moved out of regclass.
(regclass_init): Initialize it here, not in .
(scan_one_insn): New static function, broken out of regclass.
* recog.c (apply_change_group): Break out some code into new
function insn_invalid_p.
(insn_invalid_p): New static fn, broken out of apply_change_group.
Thu Oct 22 22:34:42 1998 Jim Wilson <wilson@cygnus.com>
* reload1.c (reload_as_needed): When rewrite POST_INC, verify
......
......@@ -43,6 +43,7 @@ Boston, MA 02111-1307, USA. */
static void validate_replace_rtx_1 PROTO((rtx *, rtx, rtx, rtx));
static rtx *find_single_use_1 PROTO((rtx, rtx *));
static rtx *find_constant_term_loc PROTO((rtx *));
static int insn_invalid_p PROTO((rtx));
/* Nonzero means allow operands to be volatile.
This should be 0 if you are generating rtl, such as if you are calling
......@@ -252,6 +253,41 @@ validate_change (object, loc, new, in_group)
return apply_change_group ();
}
/* This subroutine of apply_change_group verifies whether the changes to INSN
were valid; i.e. whether INSN can still be recognized. */
static int
insn_invalid_p (insn)
rtx insn;
{
int icode = recog_memoized (insn);
int is_asm = icode < 0 && asm_noperands (PATTERN (insn)) >= 0;
if (is_asm)
{
if (! check_asm_operands (PATTERN (insn)))
return 1;
/* Disallow modification of ASM_OPERANDS after reload; verifying the
constraints is too difficult. */
if (reload_completed)
return 1;
}
else if (icode < 0)
return 1;
/* After reload, verify that all constraints are satisfied. */
if (reload_completed)
{
insn_extract (insn);
if (! constrain_operands (INSN_CODE (insn), 1))
return 1;
}
return 0;
}
/* Apply a group of changes previously issued with `validate_change'.
Return 1 if all changes are valid, zero otherwise. */
......@@ -282,13 +318,7 @@ apply_change_group ()
if (! memory_address_p (GET_MODE (object), XEXP (object, 0)))
break;
}
else if ((recog_memoized (object) < 0
&& (asm_noperands (PATTERN (object)) < 0
|| ! check_asm_operands (PATTERN (object))
|| reload_completed))
|| (reload_completed
&& (insn_extract (object),
! constrain_operands (INSN_CODE (object), 1))))
else if (insn_invalid_p (object))
{
rtx pat = PATTERN (object);
......
......@@ -648,6 +648,10 @@ struct costs
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. */
......@@ -685,6 +689,7 @@ static int loop_depth;
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));
static int copy_cost PROTO((rtx, enum machine_mode,
......@@ -718,12 +723,19 @@ reg_alternate_class (regno)
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;
}
......@@ -739,132 +751,55 @@ n_occurrences (c, s)
return n;
}
/* 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'.
This pass comes just before local register allocation. */
/* 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. */
void
regclass (f, nregs)
rtx f;
int nregs;
{
#ifdef REGISTER_CONSTRAINTS
register rtx insn;
register int i, j;
struct costs init_cost;
rtx set;
static rtx
scan_one_insn (insn, pass)
rtx insn;
int pass;
{
enum rtx_code code = GET_CODE (insn);
enum rtx_code pat_code;
init_recog ();
costs = (struct costs *) xmalloc (nregs * sizeof (struct costs));
#ifdef FORBIDDEN_INC_DEC_CLASSES
in_inc_dec = (char *) alloca (nregs);
/* Initialize information about which register classes can be used for
pseudos that are auto-incremented or auto-decremented. It would
seem better to put this in init_reg_sets, but we need to be able
to allocate rtx, which we can't do that early. */
for (i = 0; i < N_REG_CLASSES; i++)
{
rtx r = gen_rtx_REG (VOIDmode, 0);
enum machine_mode m;
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
{
REGNO (r) = j;
for (m = VOIDmode; (int) m < (int) MAX_MACHINE_MODE;
m = (enum machine_mode) ((int) m + 1))
if (HARD_REGNO_MODE_OK (j, m))
{
PUT_MODE (r, m);
/* 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)
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
|| (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
selection. */
for (pass = 0; pass <= flag_expensive_optimizations; pass++)
{
/* Zero out our accumulation of the cost of each class for each reg. */
bzero ((char *) costs, nregs * sizeof (struct costs));
#ifdef FORBIDDEN_INC_DEC_CLASSES
bzero (in_inc_dec, nregs);
#endif
loop_depth = 0, loop_cost = 1;
/* Scan the instructions and record each time it would
save code to put a certain register in a certain class. */
for (insn = f; insn; insn = NEXT_INSN (insn))
{
char *constraints[MAX_RECOG_OPERANDS];
enum machine_mode modes[MAX_RECOG_OPERANDS];
int nalternatives;
int noperands;
rtx set;
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 (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
if (code == NOTE)
{
if (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)
else if (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
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;
if (code == INSN
&& (noperands = asm_noperands (PATTERN (insn))) >= 0)
{
decode_asm_operands (PATTERN (insn), recog_operand, NULL_PTR,
......@@ -899,7 +834,7 @@ regclass (f, nregs)
* loop_cost);
record_address_regs (XEXP (SET_SRC (set), 0),
BASE_REG_CLASS, loop_cost * 2);
continue;
return insn;
}
/* Improve handling of two-address insns such as
......@@ -955,8 +890,7 @@ regclass (f, nregs)
if (recog_dup_num[i] == 1)
*recog_dup_loc[i] = recog_operand[0];
insn = PREV_INSN (newinsn);
continue;
return PREV_INSN (newinsn);
}
for (i = 0; i < noperands; i++)
......@@ -1028,7 +962,104 @@ regclass (f, nregs)
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'.
This pass comes just before local register allocation. */
void
regclass (f, nregs)
rtx f;
int nregs;
{
#ifdef REGISTER_CONSTRAINTS
register rtx insn;
register int i;
int pass;
init_recog ();
costs = (struct costs *) xmalloc (nregs * sizeof (struct costs));
#ifdef FORBIDDEN_INC_DEC_CLASSES
in_inc_dec = (char *) alloca (nregs);
/* Initialize information about which register classes can be used for
pseudos that are auto-incremented or auto-decremented. It would
seem better to put this in init_reg_sets, but we need to be able
to allocate rtx, which we can't do that early. */
for (i = 0; i < N_REG_CLASSES; i++)
{
rtx r = gen_rtx_REG (VOIDmode, 0);
enum machine_mode m;
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
{
REGNO (r) = j;
for (m = VOIDmode; (int) m < (int) MAX_MACHINE_MODE;
m = (enum machine_mode) ((int) m + 1))
if (HARD_REGNO_MODE_OK (j, m))
{
PUT_MODE (r, m);
/* 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)
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
|| (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 */
/* 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
selection. */
for (pass = 0; pass <= flag_expensive_optimizations; pass++)
{
/* Zero out our accumulation of the cost of each class for each reg. */
bzero ((char *) costs, nregs * sizeof (struct costs));
#ifdef FORBIDDEN_INC_DEC_CLASSES
bzero (in_inc_dec, nregs);
#endif
loop_depth = 0, loop_cost = 1;
/* Scan the instructions and record each time it would
save code to put a certain register in a certain class. */
for (insn = f; insn; insn = NEXT_INSN (insn))
{
insn = scan_one_insn (insn, pass);
}
/* Now for each register look at how desirable each class is
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment