]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
* config/rs6000/rs6000.c (rs6000_cannot_change_mode_class): Do not
authoruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 20 Nov 2013 16:22:57 +0000 (16:22 +0000)
committeruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 20 Nov 2013 16:22:57 +0000 (16:22 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205123 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/rs6000/rs6000.c

index 2ffc36a1edd01470388540147f85652f1b8b2347..32a75226727542aa3bff5aaf780008e1fc81156b 100644 (file)
@@ -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
index 4c6a529c430cc7661fb7d4f2acba4b7ba3f7744a..bd4e8943413dd95fdb5a29a1d64700550334d3e8 100644 (file)
@@ -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