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
......
......@@ -40,9 +40,10 @@ Boston, MA 02111-1307, USA. */
#endif
#endif
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 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,6 +751,221 @@ n_occurrences (c, s)
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
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;
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 (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;
if (code == 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)),
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
&& 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];
return PREV_INSN (newinsn);
}
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. We must do this even if one operand
is a constant--see addsi3 in m68k.md. */
for (i = 0; i < noperands - 1; i++)
if (constraints[i][0] == '%')
{
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;
}
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'.
......@@ -751,9 +978,7 @@ regclass (f, nregs)
{
#ifdef REGISTER_CONSTRAINTS
register rtx insn;
register int i, j;
struct costs init_cost;
rtx set;
register int i;
int pass;
init_recog ();
......@@ -812,10 +1037,6 @@ regclass (f, nregs)
}
#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
......@@ -838,199 +1059,9 @@ regclass (f, 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)),
GENERAL_REGS, 1)
* 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. We must do this even if one operand
is a constant--see addsi3 in m68k.md. */
for (i = 0; i < noperands - 1; i++)
if (constraints[i][0] == '%')
{
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
......
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