aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2002-11-04 16:58:39 +0000
committerAldy Hernandez <aldyh@gcc.gnu.org>2002-11-04 16:58:39 +0000
commitcff9f8d50930e9e8dd627c92ce5255323576ed02 (patch)
tree9864774f05d9aef4abaed8431d0fa7b660a6a998
parentf1c129e309fc1681abecfd655bafa9318306bbb8 (diff)
downloadgcc-cff9f8d50930e9e8dd627c92ce5255323576ed02.zip
gcc-cff9f8d50930e9e8dd627c92ce5255323576ed02.tar.gz
gcc-cff9f8d50930e9e8dd627c92ce5255323576ed02.tar.bz2
hard-reg-set.h (REG_CANNOT_CHANGE_MODE_P): New.
2002-11-04 Aldy Hernandez <aldyh@redhat.com> * hard-reg-set.h (REG_CANNOT_CHANGE_MODE_P): New. * config/rs6000/rs6000.h (CLASS_CANNOT_CHANGE_MODE_P): Remove. (CLASS_CANNOT_CHANGE_MODE): Remove. (CANNOT_CHANGE_MODE_CLASS): New. * config/alpha/alpha.h: Same. * config/ia64/ia64.h: Same. * config/mips/mips.h: Same. * config/s390/s390.h: Same. * config/sh/sh.h: Same. * config/pa/pa64-regs.h: Same. * config/sh/sh-protos.h (sh_cannot_change_mode_class): Add prototype. * config/sh/sh.c (sh_cannot_change_mode_class): New. * config/mips/mips-protos.h (mips_cannot_change_mode_class): Add prototype. * config/mips/mips.c (mips_cannot_change_mode_class): New. * doc/tm.texi (Register Classes): Remove CLASS_CANNOT_CHANGE_MODE and CLASS_CANNOT_CHANGE_MODE_P. Document CANNOT_CHANGE_MODE_CLASS. * reload.c (push_reload): Use CANNOT_CHANGE_MODE_CLASS. (push_reload): Same. * simplify-rtx.c (simplify_subreg): Same. * reload1.c (choose_reload_regs): Same. * recog.c (register_operand): Same. * regrename.c (mode_change_ok): Change to use new CANNOT_CHANGE_MODE_CLASS infrastructure. * regclass.c (cannot_change_mode_set_regs): New. Declare subregs_of_mode. (regclass): Use subregs_of_mode. Remove references to reg_changes_mode. (init_reg_sets_1): Remove class_can_change_mode and reg_changes_mode code. (invalid_mode_change_p): New. (dump_regclass): Use invalid_mode_change_p instead of class_can_change_mode. (regclass): Same. (record_operand_costs): Do not set reg_changes_mode. * local-alloc.c (struct qty): Remove changes_mode field. (alloc_qty): Remove changes_mode initialization. (update_qty_class): Remove set of changes_mode. (find_free_reg): Use subregs_of_mode. * global.c (find_reg): Use subregs_of_mode info. * rtl.h (cannot_change_mode_set_regs): New prototype. (invalid_mode_change_p): Same. (REG_CANNOT_CHANGE_MODE_P): New macro. * flow.c (mark_used_regs): Calculate subregs_of_mode. Remove REG_CHANGES_MODE. (life_analysis): Clear subregs_of_mode. * combine.c (subst): Pass class to CLASS_CANNOT_CHANGE_MODE_P. Remove use of CLASS_CANNOT_CHANGE_MODE. (simplify_set): Same. (gen_lowpart_for_combine): Calculate subregs_of_mode. Remove REG_CHANGES_MODE. * regs.h: Add extern for subregs_of_mode; Include hard-reg-set and basic-block. (REG_CHANGES_MODE): Delete. From-SVN: r58794
-rw-r--r--gcc/ChangeLog82
-rw-r--r--gcc/combine.c29
-rw-r--r--gcc/config/alpha/alpha.h11
-rw-r--r--gcc/config/ia64/ia64.h12
-rw-r--r--gcc/config/mips/mips-protos.h2
-rw-r--r--gcc/config/mips/mips.c17
-rw-r--r--gcc/config/mips/mips.h10
-rw-r--r--gcc/config/pa/pa64-regs.h12
-rw-r--r--gcc/config/rs6000/rs6000.h12
-rw-r--r--gcc/config/s390/s390.h6
-rw-r--r--gcc/config/sh/sh-protos.h2
-rw-r--r--gcc/config/sh/sh.c22
-rw-r--r--gcc/config/sh/sh.h10
-rw-r--r--gcc/doc/tm.texi23
-rw-r--r--gcc/flow.c27
-rw-r--r--gcc/global.c19
-rw-r--r--gcc/hard-reg-set.h7
-rw-r--r--gcc/local-alloc.c24
-rw-r--r--gcc/recog.c7
-rw-r--r--gcc/regclass.c114
-rw-r--r--gcc/regrename.c6
-rw-r--r--gcc/regs.h11
-rw-r--r--gcc/reload.c34
-rw-r--r--gcc/reload1.c15
-rw-r--r--gcc/rtl.h10
-rw-r--r--gcc/simplify-rtx.c11
26 files changed, 303 insertions, 232 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0e0f0ee..9b4c143 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,85 @@
+2002-11-04 Aldy Hernandez <aldyh@redhat.com>
+
+ * hard-reg-set.h (REG_CANNOT_CHANGE_MODE_P): New.
+
+ * config/rs6000/rs6000.h (CLASS_CANNOT_CHANGE_MODE_P): Remove.
+ (CLASS_CANNOT_CHANGE_MODE): Remove.
+ (CANNOT_CHANGE_MODE_CLASS): New.
+
+ * config/alpha/alpha.h: Same.
+
+ * config/ia64/ia64.h: Same.
+
+ * config/mips/mips.h: Same.
+
+ * config/s390/s390.h: Same.
+
+ * config/sh/sh.h: Same.
+
+ * config/pa/pa64-regs.h: Same.
+
+ * config/sh/sh-protos.h (sh_cannot_change_mode_class): Add prototype.
+
+ * config/sh/sh.c (sh_cannot_change_mode_class): New.
+
+ * config/mips/mips-protos.h (mips_cannot_change_mode_class): Add
+ prototype.
+
+ * config/mips/mips.c (mips_cannot_change_mode_class): New.
+
+ * doc/tm.texi (Register Classes): Remove
+ CLASS_CANNOT_CHANGE_MODE and CLASS_CANNOT_CHANGE_MODE_P.
+ Document CANNOT_CHANGE_MODE_CLASS.
+
+ * reload.c (push_reload): Use CANNOT_CHANGE_MODE_CLASS.
+ (push_reload): Same.
+
+ * simplify-rtx.c (simplify_subreg): Same.
+
+ * reload1.c (choose_reload_regs): Same.
+
+ * recog.c (register_operand): Same.
+
+ * regrename.c (mode_change_ok): Change to use new
+ CANNOT_CHANGE_MODE_CLASS infrastructure.
+
+ * regclass.c (cannot_change_mode_set_regs): New.
+ Declare subregs_of_mode.
+ (regclass): Use subregs_of_mode.
+ Remove references to reg_changes_mode.
+ (init_reg_sets_1): Remove class_can_change_mode and
+ reg_changes_mode code.
+ (invalid_mode_change_p): New.
+ (dump_regclass): Use invalid_mode_change_p instead of
+ class_can_change_mode.
+ (regclass): Same.
+ (record_operand_costs): Do not set reg_changes_mode.
+
+ * local-alloc.c (struct qty): Remove changes_mode field.
+ (alloc_qty): Remove changes_mode initialization.
+ (update_qty_class): Remove set of changes_mode.
+ (find_free_reg): Use subregs_of_mode.
+
+ * global.c (find_reg): Use subregs_of_mode info.
+
+ * rtl.h (cannot_change_mode_set_regs): New prototype.
+ (invalid_mode_change_p): Same.
+ (REG_CANNOT_CHANGE_MODE_P): New macro.
+
+ * flow.c (mark_used_regs): Calculate subregs_of_mode. Remove
+ REG_CHANGES_MODE.
+ (life_analysis): Clear subregs_of_mode.
+
+ * combine.c (subst): Pass class to CLASS_CANNOT_CHANGE_MODE_P.
+ Remove use of CLASS_CANNOT_CHANGE_MODE.
+ (simplify_set): Same.
+ (gen_lowpart_for_combine): Calculate subregs_of_mode. Remove
+ REG_CHANGES_MODE.
+
+ * regs.h: Add extern for subregs_of_mode;
+ Include hard-reg-set and basic-block.
+ (REG_CHANGES_MODE): Delete.
+
2002-11-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
* jump.c (never_reached_warning): Don't set contains_insn until the
diff --git a/gcc/combine.c b/gcc/combine.c
index d6dfdf6..8ce9d10 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -3519,15 +3519,13 @@ subst (x, from, to, in_dest, unique_copy)
)
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
if (code == SUBREG
&& GET_CODE (to) == REG
&& REGNO (to) < FIRST_PSEUDO_REGISTER
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (to)))
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (to),
- GET_MODE (x)))
+ && REG_CANNOT_CHANGE_MODE_P (REGNO (to),
+ GET_MODE (to),
+ GET_MODE (x)))
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
#endif
@@ -5198,13 +5196,11 @@ simplify_set (x)
&& (GET_MODE_SIZE (GET_MODE (src))
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
&& ! (GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (dest)))
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (src),
- GET_MODE (SUBREG_REG (src))))
+ && REG_CANNOT_CHANGE_MODE_P (REGNO (dest),
+ GET_MODE (src),
+ GET_MODE (SUBREG_REG (src))))
#endif
&& (GET_CODE (dest) == REG
|| (GET_CODE (dest) == SUBREG
@@ -9937,14 +9933,13 @@ gen_lowpart_for_combine (mode, x)
}
result = gen_lowpart_common (mode, x);
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
if (result != 0
&& GET_CODE (result) == SUBREG
&& GET_CODE (SUBREG_REG (result)) == REG
- && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (result),
- GET_MODE (SUBREG_REG (result))))
- REG_CHANGES_MODE (REGNO (SUBREG_REG (result))) = 1;
+ && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER)
+ SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (result)],
+ REGNO (SUBREG_REG (result)));
#endif
if (result)
diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h
index 3997377..9e39a40 100644
--- a/gcc/config/alpha/alpha.h
+++ b/gcc/config/alpha/alpha.h
@@ -857,15 +857,10 @@ enum reg_class {
#define CLASS_MAX_NREGS(CLASS, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
-/* If defined, gives a class of registers that cannot be used as the
- operand of a SUBREG that changes the mode of the object illegally. */
+/* Return the class of registers that cannot change mode from FROM to TO. */
-#define CLASS_CANNOT_CHANGE_MODE FLOAT_REGS
-
-/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */
-
-#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
- (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \
+ (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) ? FLOAT_REGS : NO_REGS)
/* Define the cost of moving between registers of various classes. Moving
between FLOAT_REGS and anything else except float regs is expensive.
diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h
index 578e354..59d6e23 100644
--- a/gcc/config/ia64/ia64.h
+++ b/gcc/config/ia64/ia64.h
@@ -1008,17 +1008,11 @@ enum reg_class
: ((CLASS) == FR_REGS && (MODE) == TFmode) ? 1 \
: (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
-/* If defined, gives a class of registers that cannot be used as the
- operand of a SUBREG that changes the mode of the object illegally. */
-
-#define CLASS_CANNOT_CHANGE_MODE FR_REGS
-
-/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE.
- In FP regs, we can't change FP values to integer values and vice
+/* In FP regs, we can't change FP values to integer values and vice
versa, but we can change e.g. DImode to SImode. */
-#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
- (GET_MODE_CLASS (FROM) != GET_MODE_CLASS (TO))
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \
+ (GET_MODE_CLASS (FROM) != GET_MODE_CLASS (TO) ? FR_REGS : NO_REGS)
/* A C expression that defines the machine-dependent operand constraint
letters (`I', `J', `K', .. 'P') that specify particular ranges of
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index df943af..d92f7e5 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -122,6 +122,8 @@ extern int mips_adjust_insn_length PARAMS ((rtx, int));
extern enum reg_class mips_secondary_reload_class PARAMS ((enum reg_class,
enum machine_mode,
rtx, int));
+extern enum reg_class mips_cannot_change_mode_class
+ PARAMS ((enum machine_mode, enum machine_mode));
extern int mips_class_max_nregs PARAMS ((enum reg_class,
enum machine_mode));
extern int mips_register_move_cost PARAMS ((enum machine_mode,
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index dafa920..d58afff 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -8399,6 +8399,23 @@ function_arg_pass_by_reference (cum, mode, type, named)
return size == -1 || size > UNITS_PER_WORD;
}
+/* Return the class of registers for which a mode change from FROM to TO
+ is invalid. */
+enum reg_class
+mips_cannot_change_mode_class (from, to)
+ enum machine_mode from, to;
+{
+ if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to))
+ {
+ if (TARGET_BIG_ENDIAN)
+ return FP_REGS;
+ if (TARGET_FLOAT64)
+ return HI_AND_FP_REGS;
+ return HI_REG;
+ }
+ return NO_REGS;
+}
+
/* This function returns the register class required for a secondary
register when copying between one of the registers in CLASS, and X,
using MODE. If IN_P is nonzero, the copy is going from X to the
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 87513a2..bc37a14 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -2343,14 +2343,8 @@ extern enum reg_class mips_char_to_class[256];
We can't allow 64-bit float registers to change from a 32-bit
mode to a 64-bit mode. */
-#define CLASS_CANNOT_CHANGE_MODE \
- (TARGET_BIG_ENDIAN ? FP_REGS \
- : (TARGET_FLOAT64 ? HI_AND_FP_REGS : HI_REG))
-
-/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */
-
-#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
- (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \
+ mips_cannot_change_mode_class (FROM, TO)
/* Stack layout; function entry, exit and calling. */
diff --git a/gcc/config/pa/pa64-regs.h b/gcc/config/pa/pa64-regs.h
index 0af4c5f..2d0ebe3 100644
--- a/gcc/config/pa/pa64-regs.h
+++ b/gcc/config/pa/pa64-regs.h
@@ -232,12 +232,7 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FPUPPER_REGS, FP_REGS,
{0x00000000, 0x10000000}, /* SHIFT_REGS */ \
{0xfffffffe, 0x1fffffff}} /* ALL_REGS */
-/* If defined, gives a class of registers that cannot be used as the
- operand of a SUBREG that changes the mode of the object illegally. */
-
-#define CLASS_CANNOT_CHANGE_MODE (FP_REGS)
-
-/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE.
+/* Defines invalid mode changes.
SImode loads to floating-point registers are not zero-extended.
The definition for LOAD_EXTEND_OP specifies that integer loads
@@ -245,8 +240,9 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FPUPPER_REGS, FP_REGS,
we inhibit changes from SImode unless they are to a mode that is
identical in size. */
-#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
- ((FROM) == SImode && GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \
+ ((FROM) == SImode && GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
+ ? FP_REGS : NO_REGS)
/* Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 5580549..39ef154 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1314,16 +1314,14 @@ enum reg_class
? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
-/* If defined, gives a class of registers that cannot be used as the
- operand of a SUBREG that changes the mode of the object illegally. */
-#define CLASS_CANNOT_CHANGE_MODE FLOAT_REGS
+/* Return a class of registers that cannot change FROM mode to TO mode. */
-/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \
+ (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) ? FLOAT_REGS \
+ : (SPE_VECTOR_MODE (FROM) + SPE_VECTOR_MODE (TO)) == 1 ? GENERAL_REGS \
+ : NO_REGS)
-#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
- (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
-
/* Stack layout; function entry, exit and calling. */
/* Enumeration to give which calling sequence to use. */
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index 009f8a4..268ee2f 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -330,10 +330,8 @@ do \
/* If a 4-byte value is loaded into a FPR, it is placed into the
*upper* half of the register, not the lower. Therefore, we
cannot use SUBREGs to switch between modes in FP registers. */
-#define CLASS_CANNOT_CHANGE_MODE FP_REGS
-#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
- (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
-
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \
+ (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) ? FP_REGS : NO_REGS)
/* Register classes. */
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index a2152ef..a729462 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -126,6 +126,8 @@ extern int sh_pr_n_sets PARAMS ((void));
extern int sh_hard_regno_rename_ok PARAMS ((unsigned int, unsigned int));
extern int sh_cfun_interrupt_handler_p PARAMS ((void));
extern void sh_initialize_trampoline PARAMS ((rtx, rtx, rtx));
+extern enum reg_class sh_cannot_change_mode_class
+ PARAMS ((enum machine_mode, enum machine_mode));
#ifdef HARD_CONST
extern void fpscr_set_from_mem PARAMS ((int, HARD_REG_SET));
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 4e6981b..d2cc471 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -7733,4 +7733,26 @@ sh_expand_binop_v2sf (code, op0, op1, op2)
emit_insn ((*fn) (op0, op1, op2, op, sel1, sel1, sel1));
}
+/* Return the class of registers for which a mode change from FROM to TO
+ is invalid. */
+enum reg_class
+sh_cannot_change_mode_class (from, to)
+ enum machine_mode from, to;
+{
+ if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to))
+ {
+ if (TARGET_LITTLE_ENDIAN)
+ {
+ if (GET_MODE_SIZE (to) < 8 || GET_MODE_SIZE (from) < 8)
+ return DF_REGS;
+ }
+ else
+ {
+ if (GET_MODE_SIZE (from) < 8)
+ return DF_HI_REGS;
+ }
+ }
+ return NO_REGS;
+}
+
#include "gt-sh.h"
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index d0bbbdf..feadbb7 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -1372,14 +1372,8 @@ extern const enum reg_class reg_class_from_letter[];
/* ??? We need to renumber the internal numbers for the frnn registers
when in little endian in order to allow mode size changes. */
-#define CLASS_CANNOT_CHANGE_MODE (TARGET_LITTLE_ENDIAN ? DF_REGS : DF_HI_REGS)
-
-/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */
-
-#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
- (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
- && ((TARGET_LITTLE_ENDIAN && GET_MODE_SIZE (TO) < 8) \
- || GET_MODE_SIZE (FROM) < 8))
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \
+ sh_cannot_change_mode_class (FROM, TO)
/* Stack layout; function entry, exit and calling. */
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 5ca0836..b8f2b93 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2561,25 +2561,22 @@ should be the maximum value of @code{HARD_REGNO_NREGS (@var{regno},
This macro helps control the handling of multiple-word values
in the reload pass.
-@item CLASS_CANNOT_CHANGE_MODE
-If defined, a C expression for a class that contains registers for
-which the compiler may not change modes arbitrarily.
-
-@item CLASS_CANNOT_CHANGE_MODE_P(@var{from}, @var{to})
-A C expression that is true if, for a register in
-@code{CLASS_CANNOT_CHANGE_MODE}, the requested mode punning is invalid.
+@item CANNOT_CHANGE_MODE_CLASS(@var{from}, @var{to})
+If defined, a C expression that returns a register class for which
+a change from mode @var{from} to mode @var{to} is invalid, otherwise the
+macro returns @code{NO_REGS}.
For the example, loading 32-bit integer or floating-point objects into
floating-point registers on the Alpha extends them to 64 bits.
Therefore loading a 64-bit object and then storing it as a 32-bit object
does not store the low-order 32 bits, as would be the case for a normal
-register. Therefore, @file{alpha.h} defines @code{CLASS_CANNOT_CHANGE_MODE}
-as @code{FLOAT_REGS} and @code{CLASS_CANNOT_CHANGE_MODE_P} restricts
-mode changes to same-size modes.
+register. Therefore, @file{alpha.h} defines @code{CANNOT_CHANGE_MODE_CLASS}
+as below:
-Compare this to IA-64, which extends floating-point values to 82-bits,
-and stores 64-bit integers in a different format than 64-bit doubles.
-Therefore @code{CLASS_CANNOT_CHANGE_MODE_P} is always true.
+@example
+#define CANNOT_CHANGE_MODE_CLASS \
+ (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) ? FLOAT_REGS : NO_REGS)
+@end example
@end table
Three other special macros describe which operands fit which constraint
diff --git a/gcc/flow.c b/gcc/flow.c
index d9e3ae3..1807962 100644
--- a/gcc/flow.c
+++ b/gcc/flow.c
@@ -414,8 +414,8 @@ life_analysis (f, file, flags)
FILE *file;
int flags;
{
-#ifdef ELIMINABLE_REGS
int i;
+#ifdef ELIMINABLE_REGS
static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
#endif
@@ -431,6 +431,13 @@ life_analysis (f, file, flags)
SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
#endif
+
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ if (flags & PROP_REG_INFO)
+ for (i=0; i < NUM_MACHINE_MODES; ++i)
+ INIT_REG_SET (&subregs_of_mode[i]);
+#endif
+
if (! optimize)
flags &= ~(PROP_LOG_LINKS | PROP_AUTOINC | PROP_ALLOW_CFG_CHANGES);
@@ -3813,12 +3820,11 @@ mark_used_regs (pbi, x, cond, insn)
break;
case SUBREG:
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
if (GET_CODE (SUBREG_REG (x)) == REG
- && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (x),
- GET_MODE (SUBREG_REG (x))))
- REG_CHANGES_MODE (REGNO (SUBREG_REG (x))) = 1;
+ && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
+ SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (x)],
+ REGNO (SUBREG_REG (x)));
#endif
/* While we're here, optimize this case. */
@@ -3862,13 +3868,12 @@ mark_used_regs (pbi, x, cond, insn)
|| GET_CODE (testreg) == SIGN_EXTRACT
|| GET_CODE (testreg) == SUBREG)
{
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
if (GET_CODE (testreg) == SUBREG
&& GET_CODE (SUBREG_REG (testreg)) == REG
- && REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (testreg)),
- GET_MODE (testreg)))
- REG_CHANGES_MODE (REGNO (SUBREG_REG (testreg))) = 1;
+ && REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER)
+ SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (testreg)],
+ REGNO (SUBREG_REG (testreg)));
#endif
/* Modifying a single register in an alternate mode
diff --git a/gcc/global.c b/gcc/global.c
index a100096..dfbe038 100644
--- a/gcc/global.c
+++ b/gcc/global.c
@@ -974,10 +974,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
int retrying;
{
int i, best_reg, pass;
-#ifdef HARD_REG_SET
- register /* Declare it register if it's a scalar. */
-#endif
- HARD_REG_SET used, used1, used2;
+ HARD_REG_SET used, used1, used2;
enum reg_class class = (alt_regs_p
? reg_alternate_class (allocno[num].reg)
@@ -1001,10 +998,8 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
IOR_HARD_REG_SET (used1, allocno[num].hard_reg_conflicts);
-#ifdef CLASS_CANNOT_CHANGE_MODE
- if (REG_CHANGES_MODE (allocno[num].reg))
- IOR_HARD_REG_SET (used1,
- reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE]);
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ cannot_change_mode_set_regs (&used1, mode, allocno[num].reg);
#endif
/* Try each hard reg to see if it fits. Do this in two passes.
@@ -1200,11 +1195,9 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
&& (allocno[num].calls_crossed == 0
|| accept_call_clobbered
|| ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && ! (REG_CHANGES_MODE (allocno[num].reg)
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- regno)))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && ! invalid_mode_change_p (regno, REGNO_REG_CLASS (regno),
+ mode)
#endif
)
{
diff --git a/gcc/hard-reg-set.h b/gcc/hard-reg-set.h
index 9cdd968..712a267 100644
--- a/gcc/hard-reg-set.h
+++ b/gcc/hard-reg-set.h
@@ -488,4 +488,11 @@ extern int n_non_fixed_regs;
extern const char * reg_names[FIRST_PSEUDO_REGISTER];
+/* Given a hard REGN a FROM mode and a TO mode, return non-zero if
+ REGN cannot change modes between the specified modes. */
+#define REG_CANNOT_CHANGE_MODE_P(REGN, FROM, TO) \
+ (TEST_HARD_REG_BIT \
+ (reg_class_contents[(int) CANNOT_CHANGE_MODE_CLASS (FROM, TO)], \
+ REGN))
+
#endif /* ! GCC_HARD_REG_SET_H */
diff --git a/gcc/local-alloc.c b/gcc/local-alloc.c
index 9c94924..c2d6c0c 100644
--- a/gcc/local-alloc.c
+++ b/gcc/local-alloc.c
@@ -61,10 +61,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "config.h"
#include "system.h"
+#include "hard-reg-set.h"
#include "rtl.h"
#include "tm_p.h"
#include "flags.h"
-#include "hard-reg-set.h"
#include "basic-block.h"
#include "regs.h"
#include "function.h"
@@ -144,12 +144,6 @@ struct qty
or -1 if none was found. */
short phys_reg;
-
- /* Nonzero if this quantity has been used in a SUBREG in some
- way that is illegal. */
-
- char changes_mode;
-
};
static struct qty *qty;
@@ -328,7 +322,6 @@ alloc_qty (regno, mode, size, birth)
qty[qtyno].alternate_class = reg_alternate_class (regno);
qty[qtyno].n_refs = REG_N_REFS (regno);
qty[qtyno].freq = REG_FREQ (regno);
- qty[qtyno].changes_mode = REG_CHANGES_MODE (regno);
}
/* Main entry point of this file. */
@@ -2026,9 +2019,6 @@ update_qty_class (qtyno, reg)
rclass = reg_alternate_class (reg);
if (reg_class_subset_p (rclass, qty[qtyno].alternate_class))
qty[qtyno].alternate_class = rclass;
-
- if (REG_CHANGES_MODE (reg))
- qty[qtyno].changes_mode = 1;
}
/* Handle something which alters the value of an rtx REG.
@@ -2182,11 +2172,7 @@ find_free_reg (class, mode, qtyno, accept_call_clobbered, just_try_suggested,
int born_index, dead_index;
{
int i, ins;
-#ifdef HARD_REG_SET
- /* Declare it register if it's a scalar. */
- register
-#endif
- HARD_REG_SET used, first_used;
+ HARD_REG_SET first_used, used;
#ifdef ELIMINABLE_REGS
static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
#endif
@@ -2234,10 +2220,8 @@ find_free_reg (class, mode, qtyno, accept_call_clobbered, just_try_suggested,
SET_HARD_REG_BIT (used, FRAME_POINTER_REGNUM);
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
- if (qty[qtyno].changes_mode)
- IOR_HARD_REG_SET (used,
- reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE]);
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ cannot_change_mode_set_regs (&used, mode, qty[qtyno].first_reg);
#endif
/* Normally, the registers that can be used for the first register in
diff --git a/gcc/recog.c b/gcc/recog.c
index 6b6117f..b40867b 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -1083,13 +1083,10 @@ register_operand (op, mode)
if (! reload_completed && GET_CODE (sub) == MEM)
return general_operand (op, mode);
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
if (GET_CODE (sub) == REG
&& REGNO (sub) < FIRST_PSEUDO_REGISTER
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (sub)))
- && CLASS_CANNOT_CHANGE_MODE_P (mode, GET_MODE (sub))
+ && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), mode, GET_MODE (sub))
&& GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT)
return 0;
diff --git a/gcc/regclass.c b/gcc/regclass.c
index 28c2a6f..20c7d3b0 100644
--- a/gcc/regclass.c
+++ b/gcc/regclass.c
@@ -26,10 +26,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "config.h"
#include "system.h"
+#include "hard-reg-set.h"
#include "rtl.h"
#include "expr.h"
#include "tm_p.h"
-#include "hard-reg-set.h"
#include "flags.h"
#include "basic-block.h"
#include "regs.h"
@@ -227,20 +227,11 @@ static char *in_inc_dec;
#endif /* FORBIDDEN_INC_DEC_CLASSES */
-#ifdef CLASS_CANNOT_CHANGE_MODE
-
-/* These are the classes containing only registers that can be used in
- a SUBREG expression that changes the mode of the register in some
- way that is illegal. */
-
-static int class_can_change_mode[N_REG_CLASSES];
-
-/* Registers, including pseudos, which change modes in some way that
- is illegal. */
-
-static regset reg_changes_mode;
-
-#endif /* CLASS_CANNOT_CHANGE_MODE */
+#ifdef CANNOT_CHANGE_MODE_CLASS
+/* All registers that have been subreged. Indexed by mode, where each
+ entry is a regset of registers. */
+regset_head subregs_of_mode [NUM_MACHINE_MODES];
+#endif
/* Sample MEM values for use by memory_move_secondary_cost. */
@@ -549,22 +540,6 @@ init_reg_sets_1 ()
may_move_out_cost[m][i][j] = 65536;
}
}
-
-#ifdef CLASS_CANNOT_CHANGE_MODE
- {
- HARD_REG_SET c;
- COMPL_HARD_REG_SET (c, reg_class_contents[CLASS_CANNOT_CHANGE_MODE]);
-
- for (i = 0; i < N_REG_CLASSES; i++)
- {
- GO_IF_HARD_REG_SUBSET (reg_class_contents[i], c, ok_class);
- class_can_change_mode [i] = 0;
- continue;
- ok_class:
- class_can_change_mode [i] = 1;
- }
- }
-#endif /* CLASS_CANNOT_CHANGE_MODE */
}
/* Compute the table of register modes.
@@ -952,9 +927,9 @@ dump_regclass (dump)
&& (!in_inc_dec[i]
|| !forbidden_inc_dec_class[(enum reg_class) class])
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && (!REGNO_REG_SET_P (reg_changes_mode, i)
- || class_can_change_mode [(enum reg_class) class])
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && ! invalid_mode_change_p (i, (enum reg_class) class,
+ PSEUDO_REGNO_MODE (i))
#endif
)
fprintf (dump, " %s:%i", reg_class_names[class],
@@ -994,15 +969,7 @@ record_operand_costs (insn, op_costs, reg_pref)
op_costs[i] = init_cost;
if (GET_CODE (recog_data.operand[i]) == SUBREG)
- {
- rtx inner = SUBREG_REG (recog_data.operand[i]);
-#ifdef CLASS_CANNOT_CHANGE_MODE
- if (GET_CODE (inner) == REG
- && CLASS_CANNOT_CHANGE_MODE_P (modes[i], GET_MODE (inner)))
- SET_REGNO_REG_SET (reg_changes_mode, REGNO (inner));
-#endif
- recog_data.operand[i] = inner;
- }
+ recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]);
if (GET_CODE (recog_data.operand[i]) == MEM)
record_address_regs (XEXP (recog_data.operand[i], 0),
@@ -1193,10 +1160,6 @@ regclass (f, nregs, dump)
costs = (struct costs *) xmalloc (nregs * sizeof (struct costs));
-#ifdef CLASS_CANNOT_CHANGE_MODE
- reg_changes_mode = BITMAP_XMALLOC ();
-#endif
-
#ifdef FORBIDDEN_INC_DEC_CLASSES
in_inc_dec = (char *) xmalloc (nregs);
@@ -1329,9 +1292,9 @@ regclass (f, nregs, dump)
#ifdef FORBIDDEN_INC_DEC_CLASSES
|| (in_inc_dec[i] && forbidden_inc_dec_class[class])
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
- || (REGNO_REG_SET_P (reg_changes_mode, i)
- && ! class_can_change_mode [class])
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ || invalid_mode_change_p (i, (enum reg_class) class,
+ PSEUDO_REGNO_MODE (i))
#endif
)
;
@@ -1359,9 +1322,9 @@ regclass (f, nregs, dump)
#ifdef FORBIDDEN_INC_DEC_CLASSES
&& ! (in_inc_dec[i] && forbidden_inc_dec_class[class])
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && ! (REGNO_REG_SET_P (reg_changes_mode, i)
- && ! class_can_change_mode [class])
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && ! invalid_mode_change_p (i, (enum reg_class) class,
+ PSEUDO_REGNO_MODE (i))
#endif
)
alt = reg_class_subunion[(int) alt][class];
@@ -1395,9 +1358,6 @@ regclass (f, nregs, dump)
#ifdef FORBIDDEN_INC_DEC_CLASSES
free (in_inc_dec);
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
- BITMAP_XFREE (reg_changes_mode);
-#endif
free (costs);
}
@@ -2643,4 +2603,46 @@ regset_release_memory ()
bitmap_release_memory ();
}
+#ifdef CANNOT_CHANGE_MODE_CLASS
+/* Set bits in *USED which correspond to registers which can't change
+ their mode from FROM to any mode in which REGNO was encountered. */
+
+void
+cannot_change_mode_set_regs (used, from, regno)
+ HARD_REG_SET *used;
+ enum machine_mode from;
+ unsigned int regno;
+{
+ enum machine_mode to;
+ enum reg_class class;
+
+ for (to = VOIDmode; to < MAX_MACHINE_MODE; ++to)
+ if (REGNO_REG_SET_P (&subregs_of_mode[to], regno))
+ {
+ class = CANNOT_CHANGE_MODE_CLASS (from, to);
+ if (class != NO_REGS)
+ IOR_HARD_REG_SET (*used, reg_class_contents [(int) class]);
+ }
+}
+
+/* Return 1 if REGNO has had an invalid mode change in CLASS from FROM
+ mode. */
+
+bool
+invalid_mode_change_p (regno, class, from_mode)
+ unsigned int regno;
+ enum reg_class class;
+ enum machine_mode from_mode;
+{
+ enum machine_mode to_mode;
+
+ for (to_mode = 0; to_mode < NUM_MACHINE_MODES; ++to_mode)
+ if (REGNO_REG_SET_P (&subregs_of_mode[(int) to_mode], regno)
+ && reg_classes_intersect_p
+ (class, CANNOT_CHANGE_MODE_CLASS (from_mode, to_mode)))
+ return 1;
+ return 0;
+}
+#endif /* CANNOT_CHANGE_MODE_CLASS */
+
#include "gt-regclass.h"
diff --git a/gcc/regrename.c b/gcc/regrename.c
index ac1043d..9b7dfd6 100644
--- a/gcc/regrename.c
+++ b/gcc/regrename.c
@@ -1313,10 +1313,8 @@ mode_change_ok (orig_mode, new_mode, regno)
if (GET_MODE_SIZE (orig_mode) < GET_MODE_SIZE (new_mode))
return false;
-#ifdef CLASS_CANNOT_CHANGE_MODE
- if (TEST_HARD_REG_BIT (reg_class_contents[CLASS_CANNOT_CHANGE_MODE], regno)
- && CLASS_CANNOT_CHANGE_MODE_P (orig_mode, new_mode))
- return false;
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ return !REG_CANNOT_CHANGE_MODE_P (regno, orig_mode, new_mode);
#endif
return true;
diff --git a/gcc/regs.h b/gcc/regs.h
index 0b35f07..4a78212 100644
--- a/gcc/regs.h
+++ b/gcc/regs.h
@@ -21,6 +21,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "varray.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
#define REG_BYTES(R) mode_size[(int) GET_MODE (R)]
@@ -64,6 +66,8 @@ typedef struct reg_info_def
extern varray_type reg_n_info;
+extern regset_head subregs_of_mode [NUM_MACHINE_MODES];
+
/* Indexed by n, gives number of times (REG n) is used or set. */
#define REG_N_REFS(N) (VARRAY_REG (reg_n_info, N)->refs)
@@ -104,13 +108,6 @@ extern varray_type reg_n_info;
#define REG_N_DEATHS(N) (VARRAY_REG (reg_n_info, N)->deaths)
-/* Indexed by N; says whether a pseudo register N was ever used
- within a SUBREG that changes the mode of the reg in some way
- that is illegal for a given class (usually floating-point)
- of registers. */
-
-#define REG_CHANGES_MODE(N) (VARRAY_REG (reg_n_info, N)->changes_mode)
-
/* Get the number of consecutive words required to hold pseudo-reg N. */
#define PSEUDO_REGNO_SIZE(N) \
diff --git a/gcc/reload.c b/gcc/reload.c
index 97b3521..2b11988 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -967,9 +967,10 @@ push_reload (in, out, inloc, outloc, class,
if (in != 0 && GET_CODE (in) == SUBREG
&& (subreg_lowpart_p (in) || strict_low)
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && (class != CLASS_CANNOT_CHANGE_MODE
- || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), inmode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && !reg_classes_intersect_p
+ (class, CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)),
+ inmode))
#endif
&& (CONSTANT_P (SUBREG_REG (in))
|| GET_CODE (SUBREG_REG (in)) == PLUS
@@ -1016,14 +1017,11 @@ push_reload (in, out, inloc, outloc, class,
SUBREG_REG (in))
== NO_REGS))
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
|| (GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (SUBREG_REG (in))))
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)),
- inmode))
+ && REG_CANNOT_CHANGE_MODE_P
+ (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), inmode))
#endif
))
{
@@ -1081,10 +1079,10 @@ push_reload (in, out, inloc, outloc, class,
and in that case the constraint should label it input-output.) */
if (out != 0 && GET_CODE (out) == SUBREG
&& (subreg_lowpart_p (out) || strict_low)
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && (class != CLASS_CANNOT_CHANGE_MODE
- || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)),
- outmode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && !reg_classes_intersect_p
+ (class, CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)),
+ outmode))
#endif
&& (CONSTANT_P (SUBREG_REG (out))
|| strict_low
@@ -1118,14 +1116,12 @@ push_reload (in, out, inloc, outloc, class,
SUBREG_REG (out))
== NO_REGS))
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
|| (GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (SUBREG_REG (out))))
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)),
- outmode))
+ && REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)),
+ GET_MODE (SUBREG_REG (out)),
+ outmode))
#endif
))
{
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 65ee274..2704dad 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -5490,16 +5490,15 @@ choose_reload_regs (chain)
GET_MODE_CLASS (mode));
if (
-#ifdef CLASS_CANNOT_CHANGE_MODE
- (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], i)
- ? ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (last_reg),
- need_mode)
- : (GET_MODE_SIZE (GET_MODE (last_reg))
- >= GET_MODE_SIZE (need_mode)))
-#else
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ (!REG_CANNOT_CHANGE_MODE_P (i, GET_MODE (last_reg),
+ need_mode)
+ ||
+#endif
(GET_MODE_SIZE (GET_MODE (last_reg))
>= GET_MODE_SIZE (need_mode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ )
#endif
&& reg_reloaded_contents[i] == regno
&& TEST_HARD_REG_BIT (reg_reloaded_valid, i)
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 9aada82..1d71ec9 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2092,6 +2092,7 @@ extern int global_alloc PARAMS ((FILE *));
extern void dump_global_regs PARAMS ((FILE *));
#endif
#ifdef HARD_CONST
+/* Yes, this ifdef is silly, but HARD_REG_SET is not always defined. */
extern void retry_global_alloc PARAMS ((int, HARD_REG_SET));
#endif
extern void build_insn_chain PARAMS ((rtx));
@@ -2109,6 +2110,14 @@ extern void regclass PARAMS ((rtx, int, FILE *));
extern void reg_scan PARAMS ((rtx, unsigned int, int));
extern void reg_scan_update PARAMS ((rtx, rtx, unsigned int));
extern void fix_register PARAMS ((const char *, int, int));
+#ifdef HARD_CONST
+extern void cannot_change_mode_set_regs PARAMS ((HARD_REG_SET *,
+ enum machine_mode,
+ unsigned int));
+#endif
+extern bool invalid_mode_change_p PARAMS ((unsigned int,
+ enum reg_class,
+ enum machine_mode));
extern int delete_null_pointer_checks PARAMS ((rtx));
@@ -2269,4 +2278,5 @@ extern void invert_br_probabilities PARAMS ((rtx));
extern bool expensive_function_p PARAMS ((int));
/* In tracer.c */
extern void tracer PARAMS ((void));
+
#endif /* ! GCC_RTL_H */
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 52a9250..212d3b9 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -2586,15 +2586,12 @@ simplify_subreg (outermode, op, innermode, byte)
if (REG_P (op)
&& (! REG_FUNCTION_VALUE_P (op)
|| ! rtx_equal_function_value_matters)
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && ! (CLASS_CANNOT_CHANGE_MODE_P (outermode, innermode)
+ && REGNO (op) < FIRST_PSEUDO_REGISTER
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && ! (REG_CANNOT_CHANGE_MODE_P (REGNO (op), outermode, innermode)
&& GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT
- && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (op))))
+ && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT)
#endif
- && REGNO (op) < FIRST_PSEUDO_REGISTER
&& ((reload_completed && !frame_pointer_needed)
|| (REGNO (op) != FRAME_POINTER_REGNUM
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM