Hi, This patch (diff-le-dfp) backports fixes for TDmode on a little endian target.
Thanks, Bill 2014-03-19 Bill Schmidt <wschm...@linux.vnet.ibm.com> Backport from mainline r205123: 2013-11-20 Ulrich Weigand <ulrich.weig...@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. Backport from mainline r204927: 2013-11-17 Ulrich Weigand <ulrich.weig...@de.ibm.com> * config/rs6000/rs6000.c (rs6000_emit_move): Use low word of sdmode_stack_slot also in little-endian mode. Index: gcc-4_8-test/gcc/config/rs6000/rs6000.c =================================================================== --- gcc-4_8-test.orig/gcc/config/rs6000/rs6000.c +++ gcc-4_8-test/gcc/config/rs6000/rs6000.c @@ -7963,7 +7963,9 @@ rs6000_emit_move (rtx dest, rtx source, } else if (INT_REGNO_P (REGNO (operands[1]))) { - rtx mem = adjust_address_nv (operands[0], mode, 4); + rtx mem = operands[0]; + if (BYTES_BIG_ENDIAN) + mem = adjust_address_nv (mem, mode, 4); mem = eliminate_regs (mem, VOIDmode, NULL_RTX); emit_insn (gen_movsd_hardfloat (mem, operands[1])); } @@ -7986,7 +7988,9 @@ rs6000_emit_move (rtx dest, rtx source, } else if (INT_REGNO_P (REGNO (operands[0]))) { - rtx mem = adjust_address_nv (operands[1], mode, 4); + rtx mem = operands[1]; + if (BYTES_BIG_ENDIAN) + mem = adjust_address_nv (mem, mode, 4); mem = eliminate_regs (mem, VOIDmode, NULL_RTX); emit_insn (gen_movsd_hardfloat (operands[0], mem)); } @@ -16082,6 +16086,13 @@ rs6000_cannot_change_mode_class (enum ma 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; @@ -19028,6 +19039,39 @@ rs6000_split_multireg_move (rtx dst, rtx 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