aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2001-08-23 00:44:03 -0700
committerRichard Henderson <rth@gcc.gnu.org>2001-08-23 00:44:03 -0700
commit7109d286421592dd087ae3b397107bf711ac80af (patch)
tree6981dc5ba662bc3f1f10476c5b67d2974ab14191
parent26a952a8a414476401099873c2134b673a8e549e (diff)
downloadgcc-7109d286421592dd087ae3b397107bf711ac80af.zip
gcc-7109d286421592dd087ae3b397107bf711ac80af.tar.gz
gcc-7109d286421592dd087ae3b397107bf711ac80af.tar.bz2
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
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/config/ia64/ia64-protos.h3
-rw-r--r--gcc/config/ia64/ia64.c126
-rw-r--r--gcc/config/ia64/ia64.h41
4 files changed, 121 insertions, 63 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index eb088f3..af192db 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,19 @@
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
a register class.
diff --git a/gcc/config/ia64/ia64-protos.h b/gcc/config/ia64/ia64-protos.h
index 03d2952..fca7f35 100644
--- a/gcc/config/ia64/ia64-protos.h
+++ b/gcc/config/ia64/ia64-protos.h
@@ -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));
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index 5cba624..8b56dad 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -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;
-
- 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;
+ /* 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;
- /* 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;
-
- /* ??? 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;
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+ 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;
}
@@ -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
diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h
index ccd6df7..737b1e7 100644
--- a/gcc/config/ia64/ia64.h
+++ b/gcc/config/ia64/ia64.h
@@ -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