This is the mail archive of the
mailing list for the GCC project.
[PATCH, rs6000] Fix order of TDmode in FPRs in little-endian mode
- From: "Ulrich Weigand" <uweigand at de dot ibm dot com>
- To: gcc-patches at gcc dot gnu dot org, dje dot gcc at gmail dot com
- Date: Mon, 18 Nov 2013 21:07:33 +0100 (CET)
- Subject: [PATCH, rs6000] Fix order of TDmode in FPRs in little-endian mode
- Authentication-results: sourceware.org; auth=none
when loading a TDmode value into floating-point registers, they need to go
into a register pair with the even register holding the most significant
word and the odd register holding the least significant word, because this
is what the instruction set expects. This hold for both big-endian and
However, in little-endian mode, the usual subreg logic will place the
least significant word into the lower-numbered register, which is wrong.
This causes all _Decimal128 tests to fail when using a --with-cpu that
includes DFP instructions.
To fix this, the patch below:
- disables subregs of TDmode in FPRs in little-endian mode in
rs6000_cannot_change_mode_class, to ensure nobody is using the
generic subreg logic for such values, and
- changes rs6000_split_multireg_move to avoid using simplify_gen_subreg
on such values, but instead create the correct register numbers
Note that this patch implies an ABI change on little-endian for passing
_Decimal128 values in register pairs.
Also note that this patch does not change how TDmode values are loaded
into GPRs: on little-endian, this means we do get the usual LE subreg
order there (least significant word in lowest-numbered register). This
does still seem the right thing to do, because there are no instructions
that operate on DFP values in GPRs, and because this allows us to keep
using subregs on GPRs in that case, and it allows moving TDmode between
memory and GPRs (e.g. for vararg arguments) in the usual way.
Tested on powerpc64le-linux, fixes all remaining DFP-related test suite
OK for mainline?
* 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.
--- gcc/config/rs6000/rs6000.c (revision 204948)
+++ gcc/config/rs6000/rs6000.c (working copy)
@@ -16664,6 +16664,13 @@
if (TARGET_IEEEQUAD && (to == TFmode || from == TFmode))
+ /* 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)
@@ -19606,6 +19613,39 @@
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);
+ 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);
+ p_dst = simplify_gen_subreg (reg_mode, dst, mode,
+ i * reg_mode_size);
+ emit_insn (gen_rtx_SET (VOIDmode, p_dst, p_src));
if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
/* Move register range backwards, if we might have destructive
Dr. Ulrich Weigand
GNU/Linux compilers and toolchain