aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Weigand <uweigand@de.ibm.com>2013-11-20 16:22:57 +0000
committerUlrich Weigand <uweigand@gcc.gnu.org>2013-11-20 16:22:57 +0000
commit9abaec9c1ce6de2035637ba50e57f64dcdf5f22f (patch)
treee0e73a67068d231ddcf242ff608a6e33d9fb6bd6
parent547101fb67fb77fb069acd04669e18f6d4684c9f (diff)
downloadgcc-9abaec9c1ce6de2035637ba50e57f64dcdf5f22f.zip
gcc-9abaec9c1ce6de2035637ba50e57f64dcdf5f22f.tar.gz
gcc-9abaec9c1ce6de2035637ba50e57f64dcdf5f22f.tar.bz2
rs6000.c (rs6000_cannot_change_mode_class): Do not allow subregs of TDmode in FPRs of smaller size in little-endian.
* config/rs6000/rs6000.c (rs6000_cannot_change_mode_class): Do not allow subregs of TDmode in FPRs of smaller size in little-endian. (rs6000_split_multireg_move): When splitting an access to TDmode in FPRs, do not use simplify_gen_subreg. From-SVN: r205123
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/config/rs6000/rs6000.c40
2 files changed, 47 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2ffc36a..32a7522 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2013-11-20 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+
+ * config/rs6000/rs6000.c (rs6000_cannot_change_mode_class): Do not
+ allow subregs of TDmode in FPRs of smaller size in little-endian.
+ (rs6000_split_multireg_move): When splitting an access to TDmode
+ in FPRs, do not use simplify_gen_subreg.
+
2013-11-20 Joseph Myers <joseph@codesourcery.com>
PR middle-end/21718
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 4c6a529..bd4e894 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -16676,6 +16676,13 @@ rs6000_cannot_change_mode_class (enum machine_mode from,
if (TARGET_IEEEQUAD && (to == TFmode || from == TFmode))
return true;
+ /* TDmode in floating-mode registers must always go into a register
+ pair with the most significant word in the even-numbered register
+ to match ISA requirements. In little-endian mode, this does not
+ match subreg numbering, so we cannot allow subregs. */
+ if (!BYTES_BIG_ENDIAN && (to == TDmode || from == TDmode))
+ return true;
+
if (from_size < 8 || to_size < 8)
return true;
@@ -19618,6 +19625,39 @@ rs6000_split_multireg_move (rtx dst, rtx src)
gcc_assert (reg_mode_size * nregs == GET_MODE_SIZE (mode));
+ /* TDmode residing in FP registers is special, since the ISA requires that
+ the lower-numbered word of a register pair is always the most significant
+ word, even in little-endian mode. This does not match the usual subreg
+ semantics, so we cannnot use simplify_gen_subreg in those cases. Access
+ the appropriate constituent registers "by hand" in little-endian mode.
+
+ Note we do not need to check for destructive overlap here since TDmode
+ can only reside in even/odd register pairs. */
+ if (FP_REGNO_P (reg) && DECIMAL_FLOAT_MODE_P (mode) && !BYTES_BIG_ENDIAN)
+ {
+ rtx p_src, p_dst;
+ int i;
+
+ for (i = 0; i < nregs; i++)
+ {
+ if (REG_P (src) && FP_REGNO_P (REGNO (src)))
+ p_src = gen_rtx_REG (reg_mode, REGNO (src) + nregs - 1 - i);
+ else
+ p_src = simplify_gen_subreg (reg_mode, src, mode,
+ i * reg_mode_size);
+
+ if (REG_P (dst) && FP_REGNO_P (REGNO (dst)))
+ p_dst = gen_rtx_REG (reg_mode, REGNO (dst) + nregs - 1 - i);
+ else
+ p_dst = simplify_gen_subreg (reg_mode, dst, mode,
+ i * reg_mode_size);
+
+ emit_insn (gen_rtx_SET (VOIDmode, p_dst, p_src));
+ }
+
+ return;
+ }
+
if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
{
/* Move register range backwards, if we might have destructive