ia64.c (ia64_register_move_cost): Add mode arguemnt.
* config/ia64/ia64.c (ia64_register_move_cost): Add mode arguemnt. Reorganize. Handle ADDL like GR, add GR_AND_BR. Handle TFmode. (ia64_secondary_reload_class): Need GR between AR/BR and anything. Need GR between FR and not GR_AND_FR. * config/ia64/ia64-protos.h (ia64_register_move_cost): Update. * config/ia64/ia64.h (reg_class): Add GR_AND_BR_REGS, move AR regs before GR regs. (REG_CLASS_NAMES, REG_CLASS_CONTENTS): Update. (PREFERRED_RELOAD_CLASS): Tweak for reordered classes. (REGISTER_MOVE_COST): Update. (MEMORY_MOVE_COST): Add GR_AND_FR_REGS. From-SVN: r45125
This commit is contained in:
parent
26a952a8a4
commit
7109d28642
|
@ -1,3 +1,17 @@
|
|||
2001-08-23 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* config/ia64/ia64.c (ia64_register_move_cost): Add mode arguemnt.
|
||||
Reorganize. Handle ADDL like GR, add GR_AND_BR. Handle TFmode.
|
||||
(ia64_secondary_reload_class): Need GR between AR/BR and anything.
|
||||
Need GR between FR and not GR_AND_FR.
|
||||
* config/ia64/ia64-protos.h (ia64_register_move_cost): Update.
|
||||
* config/ia64/ia64.h (reg_class): Add GR_AND_BR_REGS, move
|
||||
AR regs before GR regs.
|
||||
(REG_CLASS_NAMES, REG_CLASS_CONTENTS): Update.
|
||||
(PREFERRED_RELOAD_CLASS): Tweak for reordered classes.
|
||||
(REGISTER_MOVE_COST): Update.
|
||||
(MEMORY_MOVE_COST): Add GR_AND_FR_REGS.
|
||||
|
||||
2001-08-23 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* regclass.c (init_reg_sets_1): Don't assume cost 2 within
|
||||
|
|
|
@ -119,7 +119,8 @@ extern void ia64_asm_output_external PARAMS((FILE *, tree, const char *));
|
|||
extern void ia64_encode_section_info PARAMS((tree));
|
||||
#endif /* TREE_CODE */
|
||||
|
||||
extern int ia64_register_move_cost PARAMS((enum reg_class, enum reg_class));
|
||||
extern int ia64_register_move_cost PARAMS((enum machine_mode, enum reg_class,
|
||||
enum reg_class));
|
||||
extern int ia64_epilogue_uses PARAMS((int));
|
||||
extern void emit_safe_across_calls PARAMS((FILE *));
|
||||
extern void ia64_init_builtins PARAMS((void));
|
||||
|
|
|
@ -3551,45 +3551,73 @@ ia64_print_operand (file, x, code)
|
|||
}
|
||||
|
||||
/* Calulate the cost of moving data from a register in class FROM to
|
||||
one in class TO. */
|
||||
one in class TO, using MODE. */
|
||||
|
||||
int
|
||||
ia64_register_move_cost (from, to)
|
||||
ia64_register_move_cost (mode, from, to)
|
||||
enum machine_mode mode;
|
||||
enum reg_class from, to;
|
||||
{
|
||||
int from_hard, to_hard;
|
||||
int from_gr, to_gr;
|
||||
int from_fr, to_fr;
|
||||
int from_pr, to_pr;
|
||||
/* ADDL_REGS is the same as GR_REGS for movement purposes. */
|
||||
if (to == ADDL_REGS)
|
||||
to = GR_REGS;
|
||||
if (from == ADDL_REGS)
|
||||
from = GR_REGS;
|
||||
|
||||
from_hard = (from == BR_REGS || from == AR_M_REGS || from == AR_I_REGS);
|
||||
to_hard = (to == BR_REGS || to == AR_M_REGS || to == AR_I_REGS);
|
||||
from_gr = (from == GENERAL_REGS);
|
||||
to_gr = (to == GENERAL_REGS);
|
||||
from_fr = (from == FR_REGS);
|
||||
to_fr = (to == FR_REGS);
|
||||
from_pr = (from == PR_REGS);
|
||||
to_pr = (to == PR_REGS);
|
||||
/* All costs are symmetric, so reduce cases by putting the
|
||||
lower number class as the destination. */
|
||||
if (from < to)
|
||||
{
|
||||
enum reg_class tmp = to;
|
||||
to = from, from = tmp;
|
||||
}
|
||||
|
||||
if (from_hard && to_hard)
|
||||
return 8;
|
||||
else if ((from_hard && !to_gr) || (!from_gr && to_hard))
|
||||
return 6;
|
||||
/* Moving from FR<->GR in TFmode must be more expensive than 2,
|
||||
so that we get secondary memory reloads. Between FR_REGS,
|
||||
we have to make this at least as expensive as MEMORY_MOVE_COST
|
||||
to avoid spectacularly poor register class preferencing. */
|
||||
if (mode == TFmode)
|
||||
{
|
||||
if (to != GR_REGS || from != GR_REGS)
|
||||
return MEMORY_MOVE_COST (mode, to, 0);
|
||||
else
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* Moving between PR registers takes two insns. */
|
||||
else if (from_pr && to_pr)
|
||||
return 3;
|
||||
/* Moving between PR and anything but GR is impossible. */
|
||||
else if ((from_pr && !to_gr) || (!from_gr && to_pr))
|
||||
return 6;
|
||||
switch (to)
|
||||
{
|
||||
case PR_REGS:
|
||||
/* Moving between PR registers takes two insns. */
|
||||
if (from == PR_REGS)
|
||||
return 3;
|
||||
/* Moving between PR and anything but GR is impossible. */
|
||||
if (from != GR_REGS)
|
||||
return MEMORY_MOVE_COST (mode, to, 0);
|
||||
break;
|
||||
|
||||
/* ??? Moving from FR<->GR must be more expensive than 2, so that we get
|
||||
secondary memory reloads for TFmode moves. Unfortunately, we don't
|
||||
have the mode here, so we can't check that. */
|
||||
/* Moreover, we have to make this at least as high as MEMORY_MOVE_COST
|
||||
to avoid spectacularly poor register class preferencing for TFmode. */
|
||||
else if (from_fr != to_fr)
|
||||
return 5;
|
||||
case BR_REGS:
|
||||
/* Moving between BR and anything but GR is impossible. */
|
||||
if (from != GR_REGS && from != GR_AND_BR_REGS)
|
||||
return MEMORY_MOVE_COST (mode, to, 0);
|
||||
break;
|
||||
|
||||
case AR_I_REGS:
|
||||
case AR_M_REGS:
|
||||
/* Moving between AR and anything but GR is impossible. */
|
||||
if (from != GR_REGS)
|
||||
return MEMORY_MOVE_COST (mode, to, 0);
|
||||
break;
|
||||
|
||||
case GR_REGS:
|
||||
case FR_REGS:
|
||||
case GR_AND_FR_REGS:
|
||||
case GR_AND_BR_REGS:
|
||||
case ALL_REGS:
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
@ -3613,17 +3641,21 @@ ia64_secondary_reload_class (class, mode, x)
|
|||
switch (class)
|
||||
{
|
||||
case BR_REGS:
|
||||
/* ??? This is required because of a bad gcse/cse/global interaction.
|
||||
We end up with two pseudos with overlapping lifetimes both of which
|
||||
are equiv to the same constant, and both which need to be in BR_REGS.
|
||||
This results in a BR_REGS to BR_REGS copy which doesn't exist. To
|
||||
reproduce, return NO_REGS here, and compile divdi3 in libgcc2.c.
|
||||
This seems to be a cse bug. cse_basic_block_end changes depending
|
||||
on the path length, which means the qty_first_reg check in
|
||||
make_regs_eqv can give different answers at different times. */
|
||||
/* ??? At some point I'll probably need a reload_indi pattern to handle
|
||||
this. */
|
||||
if (BR_REGNO_P (regno))
|
||||
case AR_M_REGS:
|
||||
case AR_I_REGS:
|
||||
/* ??? BR<->BR register copies can happen due to a bad gcse/cse/global
|
||||
interaction. We end up with two pseudos with overlapping lifetimes
|
||||
both of which are equiv to the same constant, and both which need
|
||||
to be in BR_REGS. This seems to be a cse bug. cse_basic_block_end
|
||||
changes depending on the path length, which means the qty_first_reg
|
||||
check in make_regs_eqv can give different answers at different times.
|
||||
At some point I'll probably need a reload_indi pattern to handle
|
||||
this.
|
||||
|
||||
We can also get GR_AND_FR_REGS to BR_REGS/AR_REGS copies, where we
|
||||
wound up with a FP register from GR_AND_FR_REGS. Extend that to all
|
||||
non-general registers for good measure. */
|
||||
if (regno >= 0 && ! GENERAL_REGNO_P (regno))
|
||||
return GR_REGS;
|
||||
|
||||
/* This is needed if a pseudo used as a call_operand gets spilled to a
|
||||
|
@ -3633,6 +3665,10 @@ ia64_secondary_reload_class (class, mode, x)
|
|||
break;
|
||||
|
||||
case FR_REGS:
|
||||
/* Need to go through general regsters to get to other class regs. */
|
||||
if (regno >= 0 && ! (FR_REGNO_P (regno) || GENERAL_REGNO_P (regno)))
|
||||
return GR_REGS;
|
||||
|
||||
/* This can happen when a paradoxical subreg is an operand to the
|
||||
muldi3 pattern. */
|
||||
/* ??? This shouldn't be necessary after instruction scheduling is
|
||||
|
|
|
@ -907,12 +907,13 @@ enum reg_class
|
|||
NO_REGS,
|
||||
PR_REGS,
|
||||
BR_REGS,
|
||||
AR_M_REGS,
|
||||
AR_I_REGS,
|
||||
ADDL_REGS,
|
||||
GR_REGS,
|
||||
FR_REGS,
|
||||
GR_AND_BR_REGS,
|
||||
GR_AND_FR_REGS,
|
||||
AR_M_REGS,
|
||||
AR_I_REGS,
|
||||
ALL_REGS,
|
||||
LIM_REG_CLASSES
|
||||
};
|
||||
|
@ -925,8 +926,9 @@ enum reg_class
|
|||
/* An initializer containing the names of the register classes as C string
|
||||
constants. These names are used in writing some of the debugging dumps. */
|
||||
#define REG_CLASS_NAMES \
|
||||
{ "NO_REGS", "PR_REGS", "BR_REGS", "ADDL_REGS", "GR_REGS", "FR_REGS", \
|
||||
"GR_AND_FR_REGS", "AR_M_REGS", "AR_I_REGS", "ALL_REGS" }
|
||||
{ "NO_REGS", "PR_REGS", "BR_REGS", "AR_M_REGS", "AR_I_REGS", \
|
||||
"ADDL_REGS", "GR_REGS", "FR_REGS", \
|
||||
"GR_AND_BR_REGS", "GR_AND_FR_REGS", "ALL_REGS" }
|
||||
|
||||
/* An initializer containing the contents of the register classes, as integers
|
||||
which are bit masks. The Nth integer specifies the contents of class N.
|
||||
|
@ -946,6 +948,14 @@ enum reg_class
|
|||
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x00FF }, \
|
||||
/* AR_M_REGS. */ \
|
||||
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x0C00 }, \
|
||||
/* AR_I_REGS. */ \
|
||||
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x7000 }, \
|
||||
/* ADDL_REGS. */ \
|
||||
{ 0x0000000F, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
|
@ -958,18 +968,14 @@ enum reg_class
|
|||
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
|
||||
0x00000000, 0x00000000, 0x0000 }, \
|
||||
/* GR_AND_BR_REGS. */ \
|
||||
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x03FF }, \
|
||||
/* GR_AND_FR_REGS. */ \
|
||||
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
|
||||
0x00000000, 0x00000000, 0x0300 }, \
|
||||
/* AR_M_REGS. */ \
|
||||
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x0C00 }, \
|
||||
/* AR_I_REGS. */ \
|
||||
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, \
|
||||
0x00000000, 0x00000000, 0x7000 }, \
|
||||
/* ALL_REGS. */ \
|
||||
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
|
||||
|
@ -1044,7 +1050,8 @@ enum reg_class
|
|||
#define PREFERRED_RELOAD_CLASS(X, CLASS) \
|
||||
(CLASS == FR_REGS && GET_CODE (X) == MEM && MEM_VOLATILE_P (X) ? NO_REGS \
|
||||
: CLASS == FR_REGS && GET_CODE (X) == CONST_DOUBLE ? NO_REGS \
|
||||
: GET_RTX_CLASS (GET_CODE (X)) != 'o' && CLASS > GR_AND_FR_REGS ? NO_REGS \
|
||||
: GET_RTX_CLASS (GET_CODE (X)) != 'o' \
|
||||
&& (CLASS == AR_M_REGS || CLASS == AR_I_REGS) ? NO_REGS \
|
||||
: CLASS)
|
||||
|
||||
/* You should define this macro to indicate to the reload phase that it may
|
||||
|
@ -1882,15 +1889,15 @@ do { \
|
|||
#define ADDRESS_COST(ADDRESS) 0
|
||||
|
||||
/* A C expression for the cost of moving data from a register in class FROM to
|
||||
one in class TO. */
|
||||
one in class TO, using MODE. */
|
||||
|
||||
#define REGISTER_MOVE_COST(MODE, FROM, TO) \
|
||||
ia64_register_move_cost((FROM), (TO))
|
||||
#define REGISTER_MOVE_COST ia64_register_move_cost
|
||||
|
||||
/* A C expression for the cost of moving data of mode M between a
|
||||
register and memory. */
|
||||
#define MEMORY_MOVE_COST(MODE,CLASS,IN) \
|
||||
((CLASS) == GENERAL_REGS || (CLASS) == FR_REGS ? 4 : 10)
|
||||
((CLASS) == GENERAL_REGS || (CLASS) == FR_REGS \
|
||||
|| (CLASS) == GR_AND_FR_REGS ? 4 : 10)
|
||||
|
||||
/* A C expression for the cost of a branch instruction. A value of 1 is the
|
||||
default; other values are interpreted relative to that. Used by the
|
||||
|
|
Loading…
Reference in New Issue