Commit 7109d286 by Richard Henderson Committed by Richard Henderson

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