summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2013-12-09 10:46:24 -0800
committerH.J. Lu <hjl.tools@gmail.com>2013-12-14 09:23:44 -0800
commit5edbfbf0faa221893abb0cc9d1f5a6db7c003d84 (patch)
tree8b5912debe5d107735a714f4fdd318e8c43eadec
parent0cea58f2e5cf0774e56207ea760b052903229547 (diff)
downloadgcc-5edbfbf0faa221893abb0cc9d1f5a6db7c003d84.tar.gz
Add subreg_byte to CANNOT_CHANGE_MODE_CLASS
-rw-r--r--gcc/combine.c2
-rw-r--r--gcc/config/aarch64/aarch64.h6
-rw-r--r--gcc/config/alpha/alpha.h2
-rw-r--r--gcc/config/arm/arm.h8
-rw-r--r--gcc/config/i386/i386-protos.h4
-rw-r--r--gcc/config/i386/i386.c12
-rw-r--r--gcc/config/i386/i386.h7
-rw-r--r--gcc/config/ia64/ia64.h2
-rw-r--r--gcc/config/m32c/m32c.h2
-rw-r--r--gcc/config/mep/mep.h2
-rw-r--r--gcc/config/mips/mips.h2
-rw-r--r--gcc/config/msp430/msp430.h10
-rw-r--r--gcc/config/pa/pa32-regs.h2
-rw-r--r--gcc/config/pa/pa64-regs.h2
-rw-r--r--gcc/config/pdp11/pdp11.h2
-rw-r--r--gcc/config/rs6000/rs6000.h2
-rw-r--r--gcc/config/s390/s390.h2
-rw-r--r--gcc/config/score/score.h4
-rw-r--r--gcc/config/sh/sh.h2
-rw-r--r--gcc/config/sparc/sparc.h2
-rw-r--r--gcc/config/spu/spu.h2
-rw-r--r--gcc/doc/rtl.texi7
-rw-r--r--gcc/doc/tm.texi8
-rw-r--r--gcc/doc/tm.texi.in8
-rw-r--r--gcc/emit-rtl.c2
-rw-r--r--gcc/hard-reg-set.h6
-rw-r--r--gcc/postreload.c4
-rw-r--r--gcc/recog.c3
-rw-r--r--gcc/regcprop.c4
-rw-r--r--gcc/reginfo.c1
-rw-r--r--gcc/reload.c10
-rw-r--r--gcc/reload1.c10
-rw-r--r--gcc/rtlanal.c2
33 files changed, 85 insertions, 59 deletions
diff --git a/gcc/combine.c b/gcc/combine.c
index dea6c2818bb..8e3b9629ab0 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -5084,6 +5084,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
&& REGNO (to) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P (REGNO (to),
GET_MODE (to),
+ SUBREG_BYTE (x),
GET_MODE (x)))
return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
#endif
@@ -6450,6 +6451,7 @@ simplify_set (rtx x)
&& ! (REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P (REGNO (dest),
GET_MODE (SUBREG_REG (src)),
+ SUBREG_BYTE (src),
GET_MODE (src)))
#endif
&& (REG_P (dest)
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index cead022c3c0..7eac69a3556 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -820,9 +820,9 @@ do { \
/* VFP registers may only be accessed in the mode they
were set. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
- (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
- ? reg_classes_intersect_p (FP_REGS, (CLASS)) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
+ (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
+ ? reg_classes_intersect_p (FP_REGS, (CLASS)) \
: 0)
diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h
index 2e7c0789d55..a183a44568c 100644
--- a/gcc/config/alpha/alpha.h
+++ b/gcc/config/alpha/alpha.h
@@ -541,7 +541,7 @@ enum reg_class {
/* Return the class of registers that cannot change mode from FROM to TO. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
(GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
? reg_classes_intersect_p (FLOAT_REGS, CLASS) : 0)
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 8b8b80e19d3..f761a3b0160 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -1247,10 +1247,10 @@ enum reg_class
In big-endian mode, modes greater than word size (i.e. DFmode) are stored in
VFP registers in little-endian order. We can't describe that accurately to
GCC, so avoid taking subregs of such values. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
- (TARGET_VFP && TARGET_BIG_END \
- && (GET_MODE_SIZE (FROM) > UNITS_PER_WORD \
- || GET_MODE_SIZE (TO) > UNITS_PER_WORD) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
+ (TARGET_VFP && TARGET_BIG_END \
+ && (GET_MODE_SIZE (FROM) > UNITS_PER_WORD \
+ || GET_MODE_SIZE (TO) > UNITS_PER_WORD) \
&& reg_classes_intersect_p (VFP_REGS, (CLASS)))
/* The class value for index registers, and the one for base regs. */
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 73feef25144..0cbb9ae7e77 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -167,7 +167,9 @@ extern bool ix86_modes_tieable_p (enum machine_mode, enum machine_mode);
extern bool ix86_secondary_memory_needed (enum reg_class, enum reg_class,
enum machine_mode, int);
extern bool ix86_cannot_change_mode_class (enum machine_mode,
- enum machine_mode, enum reg_class);
+ unsigned int,
+ enum machine_mode,
+ enum reg_class);
extern int ix86_mode_needed (int, rtx);
extern int ix86_mode_after (int, int, rtx);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index ecf5e0b1bc0..b8172c3bd71 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -35035,10 +35035,12 @@ ix86_class_max_nregs (reg_class_t rclass, enum machine_mode mode)
}
/* Return true if the registers in CLASS cannot represent the change from
- modes FROM to TO. */
+ modes FROM at offset SUBREG_BYTE to TO. */
bool
-ix86_cannot_change_mode_class (enum machine_mode from, enum machine_mode to,
+ix86_cannot_change_mode_class (enum machine_mode from,
+ unsigned int subreg_byte,
+ enum machine_mode to,
enum reg_class regclass)
{
if (from == to)
@@ -35059,10 +35061,8 @@ ix86_cannot_change_mode_class (enum machine_mode from, enum machine_mode to,
return true;
/* Vector registers do not support subreg with nonzero offsets, which
- are otherwise valid for integer registers. Since we can't see
- whether we have a nonzero offset from here, prohibit all
- nonparadoxical subregs changing size. */
- if (GET_MODE_SIZE (to) < GET_MODE_SIZE (from))
+ are otherwise valid for integer registers. */
+ if (subreg_byte != 0 && GET_MODE_SIZE (to) < GET_MODE_SIZE (from))
return true;
}
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 7efd1e01f4e..d43dcbd3ad6 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -1522,10 +1522,11 @@ enum reg_class
? mode_for_size (32, GET_MODE_CLASS (MODE), 0) \
: MODE)
-/* Return a class of registers that cannot change FROM mode to TO mode. */
+/* Return a class of registers that cannot change FROM mode to TO mode
+ with SUBREG_BYTE. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
- ix86_cannot_change_mode_class (FROM, TO, CLASS)
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
+ ix86_cannot_change_mode_class (FROM, SUBREG_BYTE, TO, CLASS)
/* Stack layout; function entry, exit and calling. */
diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h
index ae9027c82d5..d3aca621a41 100644
--- a/gcc/config/ia64/ia64.h
+++ b/gcc/config/ia64/ia64.h
@@ -856,7 +856,7 @@ enum reg_class
In FP regs, we can't change FP values to integer values and vice versa,
but we can change e.g. DImode to SImode, and V2SFmode into DImode. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
(reg_classes_intersect_p (CLASS, BR_REGS) \
? (FROM) != (TO) \
: (SCALAR_FLOAT_MODE_P (FROM) != SCALAR_FLOAT_MODE_P (TO) \
diff --git a/gcc/config/m32c/m32c.h b/gcc/config/m32c/m32c.h
index b7b5aa46924..5574223a107 100644
--- a/gcc/config/m32c/m32c.h
+++ b/gcc/config/m32c/m32c.h
@@ -414,7 +414,7 @@ enum reg_class
#define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true
-#define CANNOT_CHANGE_MODE_CLASS(F,T,C) m32c_cannot_change_mode_class(F,T,C)
+#define CANNOT_CHANGE_MODE_CLASS(F,O,T,C) m32c_cannot_change_mode_class(F,T,C)
/* STACK AND CALLING */
diff --git a/gcc/config/mep/mep.h b/gcc/config/mep/mep.h
index 023d73c900e..01bd3cdb617 100644
--- a/gcc/config/mep/mep.h
+++ b/gcc/config/mep/mep.h
@@ -321,7 +321,7 @@ extern char mep_leaf_registers[];
#define MODES_TIEABLE_P(MODE1, MODE2) 1
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
mep_cannot_change_mode_class (FROM, TO, CLASS)
enum reg_class
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 021419c0a6a..ec5e2af6bb0 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -2104,7 +2104,7 @@ enum reg_class
#define CLASS_MAX_NREGS(CLASS, MODE) mips_class_max_nregs (CLASS, MODE)
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
mips_cannot_change_mode_class (FROM, TO, CLASS)
/* Stack layout; function entry, exit and calling. */
diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h
index 953c6387e99..c4cb0fde2a4 100644
--- a/gcc/config/msp430/msp430.h
+++ b/gcc/config/msp430/msp430.h
@@ -394,11 +394,11 @@ typedef struct
((TARGET_LARGE && ((NREGS) <= 2)) ? PSImode : choose_hard_reg_mode ((REGNO), (NREGS), false))
/* Also stop GCC from thinking that it can eliminate (SUBREG:PSI (SI)). */
-#define CANNOT_CHANGE_MODE_CLASS(FROM,TO,CLASS) \
- ( ((TO) == PSImode && (FROM) == SImode) \
- || ((TO) == SImode && (FROM) == PSImode) \
- || ((TO) == DImode && (FROM) == PSImode) \
- || ((TO) == PSImode && (FROM) == DImode) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM,SUBREG_BYTE,TO,CLASS) \
+ ( ((TO) == PSImode && (FROM) == SImode) \
+ || ((TO) == SImode && (FROM) == PSImode) \
+ || ((TO) == DImode && (FROM) == PSImode) \
+ || ((TO) == PSImode && (FROM) == DImode) \
)
#define ACCUMULATE_OUTGOING_ARGS 1
diff --git a/gcc/config/pa/pa32-regs.h b/gcc/config/pa/pa32-regs.h
index 098e9bab561..83681aa1f4f 100644
--- a/gcc/config/pa/pa32-regs.h
+++ b/gcc/config/pa/pa32-regs.h
@@ -296,7 +296,7 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FPUPPER_REGS, FP_REGS,
/* Defines invalid mode changes. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
pa_cannot_change_mode_class (FROM, TO, CLASS)
/* Return the class number of the smallest class containing
diff --git a/gcc/config/pa/pa64-regs.h b/gcc/config/pa/pa64-regs.h
index 002520ab8f4..583ffa3be69 100644
--- a/gcc/config/pa/pa64-regs.h
+++ b/gcc/config/pa/pa64-regs.h
@@ -232,7 +232,7 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FPUPPER_REGS, FP_REGS,
/* Defines invalid mode changes. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
pa_cannot_change_mode_class (FROM, TO, CLASS)
/* Return the class number of the smallest class containing
diff --git a/gcc/config/pdp11/pdp11.h b/gcc/config/pdp11/pdp11.h
index d4bc19a00f1..33d0f9f3a60 100644
--- a/gcc/config/pdp11/pdp11.h
+++ b/gcc/config/pdp11/pdp11.h
@@ -282,7 +282,7 @@ enum reg_class { NO_REGS, MUL_REGS, GENERAL_REGS, LOAD_FPU_REGS, NO_LOAD_FPU_REG
1 \
)
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
pdp11_cannot_change_mode_class (FROM, TO, CLASS)
/* Stack layout; function entry, exit and calling. */
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index eb59235ec61..b88209aaa54 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1505,7 +1505,7 @@ extern enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX];
/* Return nonzero if for CLASS a mode change from FROM to TO is invalid. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
rs6000_cannot_change_mode_class_ptr (FROM, TO, CLASS)
/* Stack layout; function entry, exit and calling. */
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index bca18fe36f5..a947836aab8 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -419,7 +419,7 @@ enum processor_flags
cannot use SUBREGs to switch between modes in FP registers.
Likewise for access registers, since they have only half the
word size on 64-bit. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
(GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
? ((reg_classes_intersect_p (FP_REGS, CLASS) \
&& (GET_MODE_SIZE (FROM) < 8 || GET_MODE_SIZE (TO) < 8)) \
diff --git a/gcc/config/score/score.h b/gcc/config/score/score.h
index ca73401fc59..d5ca021616d 100644
--- a/gcc/config/score/score.h
+++ b/gcc/config/score/score.h
@@ -414,8 +414,8 @@ enum reg_class
#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X) \
score_secondary_reload_class (CLASS, MODE, X)
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
- (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
+ (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
? reg_classes_intersect_p (HI_REG, (CLASS)) : 0)
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index 9f07012941c..1a4c9e81983 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -1149,7 +1149,7 @@ extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
operand of a SUBREG that changes the mode of the object illegally.
??? We need to renumber the internal numbers for the frnn registers
when in little endian in order to allow mode size changes. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
sh_cannot_change_mode_class (FROM, TO, CLASS)
/* Stack layout; function entry, exit and calling. */
diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h
index 7533e88491b..e3d9db8af18 100644
--- a/gcc/config/sparc/sparc.h
+++ b/gcc/config/sparc/sparc.h
@@ -912,7 +912,7 @@ extern enum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER];
Likewise for SFmode, since word-mode paradoxical subregs are
problematic on big-endian architectures. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
(TARGET_ARCH64 \
&& GET_MODE_SIZE (FROM) == 4 \
&& GET_MODE_SIZE (TO) != 4 \
diff --git a/gcc/config/spu/spu.h b/gcc/config/spu/spu.h
index ad4405ae3d9..9b9a399fc92 100644
--- a/gcc/config/spu/spu.h
+++ b/gcc/config/spu/spu.h
@@ -224,7 +224,7 @@ enum reg_class {
/* GCC assumes that modes are in the lowpart of a register, which is
only true for SPU. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
((GET_MODE_SIZE (FROM) > 4 || GET_MODE_SIZE (TO) > 4) \
&& (GET_MODE_SIZE (FROM) < 16 || GET_MODE_SIZE (TO) < 16) \
&& GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 15290f23fba..26ca6088217 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -1979,11 +1979,12 @@ value @samp{(reg:HI 4)}.
@cindex @code{CANNOT_CHANGE_MODE_CLASS} and subreg semantics
The rules above apply to both pseudo @var{reg}s and hard @var{reg}s.
If the semantics are not correct for particular combinations of
-@var{m1}, @var{m2} and hard @var{reg}, the target-specific code
-must ensure that those combinations are never used. For example:
+@var{m1}, @var{subreg_byte}, @var{m2} and hard @var{reg}, the
+target-specific code must ensure that those combinations are never used.
+For example:
@smallexample
-CANNOT_CHANGE_MODE_CLASS (@var{m2}, @var{m1}, @var{class})
+CANNOT_CHANGE_MODE_CLASS (@var{m2}, @var{subreg_byte}, @var{m1}, @var{class})
@end smallexample
must be true for every class @var{class} that includes @var{reg}.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 8abb3effff4..dbc47fbd156 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2880,9 +2880,11 @@ This macro helps control the handling of multiple-word values
in the reload pass.
@end defmac
-@defmac CANNOT_CHANGE_MODE_CLASS (@var{from}, @var{to}, @var{class})
+@defmac CANNOT_CHANGE_MODE_CLASS (@var{from}, @var{subreg_byte}, @var{to}, @var{class})
If defined, a C expression that returns nonzero for a @var{class} for which
-a change from mode @var{from} to mode @var{to} is invalid.
+a change from mode @var{from} at the @code{subreg} offset @var{subreg_byte}
+to mode @var{to} is invalid. If the @code{subreg} offset is unknown, the
+size of the largest mode on the target should be used.
For the example, loading 32-bit integer or floating-point objects into
floating-point registers on the Alpha extends them to 64 bits.
@@ -2892,7 +2894,7 @@ register. Therefore, @file{alpha.h} defines @code{CANNOT_CHANGE_MODE_CLASS}
as below:
@smallexample
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
(GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
? reg_classes_intersect_p (FLOAT_REGS, (CLASS)) : 0)
@end smallexample
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index deedb41d3b2..cce116960c4 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2521,9 +2521,11 @@ This macro helps control the handling of multiple-word values
in the reload pass.
@end defmac
-@defmac CANNOT_CHANGE_MODE_CLASS (@var{from}, @var{to}, @var{class})
+@defmac CANNOT_CHANGE_MODE_CLASS (@var{from}, @var{subreg_byte}, @var{to}, @var{class})
If defined, a C expression that returns nonzero for a @var{class} for which
-a change from mode @var{from} to mode @var{to} is invalid.
+a change from mode @var{from} at the @code{subreg} offset @var{subreg_byte}
+to mode @var{to} is invalid. If the @code{subreg} offset is unknown, the
+size of the largest mode on the target should be used.
For the example, loading 32-bit integer or floating-point objects into
floating-point registers on the Alpha extends them to 64 bits.
@@ -2533,7 +2535,7 @@ register. Therefore, @file{alpha.h} defines @code{CANNOT_CHANGE_MODE_CLASS}
as below:
@smallexample
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, SUBREG_BYTE, TO, CLASS) \
(GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
? reg_classes_intersect_p (FLOAT_REGS, (CLASS)) : 0)
@end smallexample
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index d7fa3a5e0dc..b8e3dfd1c2b 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -748,7 +748,7 @@ validate_subreg (enum machine_mode omode, enum machine_mode imode,
if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode))
&& GET_MODE_INNER (imode) == omode)
;
- else if (REG_CANNOT_CHANGE_MODE_P (regno, imode, omode))
+ else if (REG_CANNOT_CHANGE_MODE_P (regno, imode, offset, omode))
return false;
#endif
diff --git a/gcc/hard-reg-set.h b/gcc/hard-reg-set.h
index ad987f9b354..11a4b3e5bfd 100644
--- a/gcc/hard-reg-set.h
+++ b/gcc/hard-reg-set.h
@@ -716,9 +716,9 @@ extern struct target_hard_regs *this_target_hard_regs;
extern const char * reg_class_names[];
-/* Given a hard REGN a FROM mode and a TO mode, return nonzero if
+/* Given a hard REGN a FROM mode at SUBREG_BYTE and a TO mode, return nonzero if
REGN cannot change modes between the specified modes. */
-#define REG_CANNOT_CHANGE_MODE_P(REGN, FROM, TO) \
- CANNOT_CHANGE_MODE_CLASS (FROM, TO, REGNO_REG_CLASS (REGN))
+#define REG_CANNOT_CHANGE_MODE_P(REGN, FROM, SUBREG_BYTE, TO) \
+ CANNOT_CHANGE_MODE_CLASS (FROM, SUBREG_BYTE, TO, REGNO_REG_CLASS (REGN))
#endif /* ! GCC_HARD_REG_SET_H */
diff --git a/gcc/postreload.c b/gcc/postreload.c
index 37bd9ff6ae3..8fb2f20adb5 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -349,6 +349,8 @@ reload_cse_simplify_set (rtx set, rtx insn)
&& extend_op != UNKNOWN
#ifdef CANNOT_CHANGE_MODE_CLASS
&& !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
+ (GET_CODE (SET_DEST (set)) == SUBREG
+ ? SUBREG_BYTE (SET_DEST (set)) : 0),
word_mode,
REGNO_REG_CLASS (REGNO (SET_DEST (set))))
#endif
@@ -459,6 +461,8 @@ reload_cse_simplify_operands (rtx insn, rtx testreg)
it cannot have been used in word_mode. */
else if (REG_P (SET_DEST (set))
&& CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
+ (GET_CODE (SET_DEST (set)) == SUBREG
+ ? SUBREG_BYTE (SET_DEST (set)) : 0),
word_mode,
REGNO_REG_CLASS (REGNO (SET_DEST (set)))))
; /* Continue ordinary processing. */
diff --git a/gcc/recog.c b/gcc/recog.c
index dbd9a8a5065..e30d81c814b 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -1069,7 +1069,8 @@ register_operand (rtx op, enum machine_mode mode)
#ifdef CANNOT_CHANGE_MODE_CLASS
if (REG_P (sub)
&& REGNO (sub) < FIRST_PSEUDO_REGISTER
- && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode)
+ && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub),
+ SUBREG_BYTE (op), mode)
&& GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT
/* LRA can generate some invalid SUBREGS just for matched
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 3c9ef3d3380..2be57744809 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -389,7 +389,9 @@ mode_change_ok (enum machine_mode orig_mode, enum machine_mode new_mode,
return false;
#ifdef CANNOT_CHANGE_MODE_CLASS
- return !REG_CANNOT_CHANGE_MODE_P (regno, orig_mode, new_mode);
+ return !REG_CANNOT_CHANGE_MODE_P (regno, orig_mode,
+ (MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT),
+ new_mode);
#endif
return true;
diff --git a/gcc/reginfo.c b/gcc/reginfo.c
index 46288ebd181..6a150a4633b 100644
--- a/gcc/reginfo.c
+++ b/gcc/reginfo.c
@@ -1222,6 +1222,7 @@ record_subregs_of_mode (rtx subreg, bitmap subregs_of_mode)
if (!bitmap_bit_p (invalid_mode_changes,
regno * N_REG_CLASSES + rclass)
&& CANNOT_CHANGE_MODE_CLASS (PSEUDO_REGNO_MODE (regno),
+ (MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT),
mode, (enum reg_class) rclass))
bitmap_set_bit (invalid_mode_changes,
regno * N_REG_CLASSES + rclass);
diff --git a/gcc/reload.c b/gcc/reload.c
index 96619f67820..487d4d4122d 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -1064,7 +1064,8 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
if (in != 0 && GET_CODE (in) == SUBREG
&& (subreg_lowpart_p (in) || strict_low)
#ifdef CANNOT_CHANGE_MODE_CLASS
- && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, rclass)
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)),
+ SUBREG_BYTE (in), inmode, rclass)
#endif
&& contains_reg_of_mode[(int) rclass][(int) GET_MODE (SUBREG_REG (in))]
&& (CONSTANT_P (SUBREG_REG (in))
@@ -1113,7 +1114,8 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
|| (REG_P (SUBREG_REG (in))
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P
- (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), inmode))
+ (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)),
+ SUBREG_BYTE (in), inmode))
#endif
))
{
@@ -1174,7 +1176,8 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
if (out != 0 && GET_CODE (out) == SUBREG
&& (subreg_lowpart_p (out) || strict_low)
#ifdef CANNOT_CHANGE_MODE_CLASS
- && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, rclass)
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)),
+ SUBREG_BYTE (out), outmode, rclass)
#endif
&& contains_reg_of_mode[(int) rclass][(int) GET_MODE (SUBREG_REG (out))]
&& (CONSTANT_P (SUBREG_REG (out))
@@ -1209,6 +1212,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)),
GET_MODE (SUBREG_REG (out)),
+ SUBREG_BYTE (out),
outmode))
#endif
))
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 47439ce6ec9..10d5a4e69c1 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -6609,7 +6609,7 @@ choose_reload_regs (struct insn_chain *chain)
mode MODE. */
&& !REG_CANNOT_CHANGE_MODE_P (REGNO (reg_last_reload_reg[regno]),
GET_MODE (reg_last_reload_reg[regno]),
- mode)
+ byte, mode)
#endif
)
{
@@ -8080,8 +8080,12 @@ inherit_piecemeal_p (int dest ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED)
{
#ifdef CANNOT_CHANGE_MODE_CLASS
- return (!REG_CANNOT_CHANGE_MODE_P (dest, mode, reg_raw_mode[dest])
- && !REG_CANNOT_CHANGE_MODE_P (src, mode, reg_raw_mode[src]));
+ return (!REG_CANNOT_CHANGE_MODE_P (dest, mode,
+ (MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT),
+ reg_raw_mode[dest])
+ && !REG_CANNOT_CHANGE_MODE_P (src, mode,
+ (MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT),
+ reg_raw_mode[src]));
#else
return true;
#endif
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 38f9e36593d..96871106d12 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -3533,7 +3533,7 @@ simplify_subreg_regno (unsigned int xregno, enum machine_mode xmode,
/* Give the backend a chance to disallow the mode change. */
if (GET_MODE_CLASS (xmode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (xmode) != MODE_COMPLEX_FLOAT
- && REG_CANNOT_CHANGE_MODE_P (xregno, xmode, ymode)
+ && REG_CANNOT_CHANGE_MODE_P (xregno, xmode, offset, ymode)
/* We can use mode change in LRA for some transformations. */
&& ! lra_in_progress)
return -1;