mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-26 02:04:06 +08:00
dfp.md: New file.
* config/rs6000/dfp.md: New file. * config/rs6000/rs6000.md: Include dfp.md. (add<mode>3_internal1): Disable for DECIMAL_FLOAT_MODE_P operands. * config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): Handle DDmode and TDmode decimal float modes in FP registers. (num_insns_constant): Likewise. (rs6000_legitimate_offset_address_p): Likewise. (rs6000_legitimize_address): Likewise. (rs6000_legitimize_reload_address): Likewise. (rs6000_legitimate_address): Likewise. (rs6000_emit_move): Likewise. (function_arg_boundary): Likewise. (function_arg_advance): Likewise. (rs6000_darwin64_record_arg_recurse): Likewise. (function_arg): Likewise. (rs6000_gimplify_va_arg): Likewise. (rs6000_split_multireg_move): Likewise. (rs6000_output_function_epilogue): Likewise. (rs6000_output_function_epilogue): Likewise. (rs6000_register_move_cost): Likewise. (rs6000_function_value): Likewise. (rs6000_libcall_value): Likewise. Co-Authored-By: Janis Johnson <janis187@us.ibm.com> Co-Authored-By: Peter Bergner <bergner@vnet.ibm.com> From-SVN: r122477
This commit is contained in:
parent
0fa4c37026
commit
7393f7f8d0
@ -1,3 +1,30 @@
|
||||
2007-03-02 Ben Elliston <bje@au.ibm.com>
|
||||
Peter Bergner <bergner@vnet.ibm.com>
|
||||
Janis Johnson <janis187@us.ibm.com>
|
||||
|
||||
* config/rs6000/dfp.md: New file.
|
||||
* config/rs6000/rs6000.md: Include dfp.md.
|
||||
(add<mode>3_internal1): Disable for DECIMAL_FLOAT_MODE_P operands.
|
||||
* config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): Handle DDmode
|
||||
and TDmode decimal float modes in FP registers.
|
||||
(num_insns_constant): Likewise.
|
||||
(rs6000_legitimate_offset_address_p): Likewise.
|
||||
(rs6000_legitimize_address): Likewise.
|
||||
(rs6000_legitimize_reload_address): Likewise.
|
||||
(rs6000_legitimate_address): Likewise.
|
||||
(rs6000_emit_move): Likewise.
|
||||
(function_arg_boundary): Likewise.
|
||||
(function_arg_advance): Likewise.
|
||||
(rs6000_darwin64_record_arg_recurse): Likewise.
|
||||
(function_arg): Likewise.
|
||||
(rs6000_gimplify_va_arg): Likewise.
|
||||
(rs6000_split_multireg_move): Likewise.
|
||||
(rs6000_output_function_epilogue): Likewise.
|
||||
(rs6000_output_function_epilogue): Likewise.
|
||||
(rs6000_register_move_cost): Likewise.
|
||||
(rs6000_function_value): Likewise.
|
||||
(rs6000_libcall_value): Likewise.
|
||||
|
||||
2007-03-02 Richard Sandiford <richard@codesourcery.com>
|
||||
|
||||
* config/t-vxworks (LIMITS_H_TEST): Define to true for VxWorks.
|
||||
|
316
gcc/config/rs6000/dfp.md
Normal file
316
gcc/config/rs6000/dfp.md
Normal file
@ -0,0 +1,316 @@
|
||||
;; Decimal Floating Point (DFP) patterns.
|
||||
;; Copyright (C) 2007
|
||||
;; Free Software Foundation, Inc.
|
||||
;; Contributed by Ben Elliston (bje@au.ibm.com) and Peter Bergner
|
||||
;; (bergner@vnet.ibm.com).
|
||||
|
||||
;; This file is part of GCC.
|
||||
|
||||
;; GCC is free software; you can redistribute it and/or modify it
|
||||
;; under the terms of the GNU General Public License as published
|
||||
;; by the Free Software Foundation; either version 2, or (at your
|
||||
;; option) any later version.
|
||||
|
||||
;; GCC is distributed in the hope that it will be useful, but WITHOUT
|
||||
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
;; License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GCC; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
|
||||
;; MA 02110-1301, USA.
|
||||
|
||||
(define_expand "movdd"
|
||||
[(set (match_operand:DD 0 "nonimmediate_operand" "")
|
||||
(match_operand:DD 1 "any_operand" ""))]
|
||||
""
|
||||
"{ rs6000_emit_move (operands[0], operands[1], DDmode); DONE; }")
|
||||
|
||||
(define_split
|
||||
[(set (match_operand:DD 0 "gpc_reg_operand" "")
|
||||
(match_operand:DD 1 "const_int_operand" ""))]
|
||||
"! TARGET_POWERPC64 && reload_completed
|
||||
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|
||||
|| (GET_CODE (operands[0]) == SUBREG
|
||||
&& GET_CODE (SUBREG_REG (operands[0])) == REG
|
||||
&& REGNO (SUBREG_REG (operands[0])) <= 31))"
|
||||
[(set (match_dup 2) (match_dup 4))
|
||||
(set (match_dup 3) (match_dup 1))]
|
||||
"
|
||||
{
|
||||
int endian = (WORDS_BIG_ENDIAN == 0);
|
||||
HOST_WIDE_INT value = INTVAL (operands[1]);
|
||||
|
||||
operands[2] = operand_subword (operands[0], endian, 0, DDmode);
|
||||
operands[3] = operand_subword (operands[0], 1 - endian, 0, DDmode);
|
||||
#if HOST_BITS_PER_WIDE_INT == 32
|
||||
operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx;
|
||||
#else
|
||||
operands[4] = GEN_INT (value >> 32);
|
||||
operands[1] = GEN_INT (((value & 0xffffffff) ^ 0x80000000) - 0x80000000);
|
||||
#endif
|
||||
}")
|
||||
|
||||
(define_split
|
||||
[(set (match_operand:DD 0 "gpc_reg_operand" "")
|
||||
(match_operand:DD 1 "const_double_operand" ""))]
|
||||
"! TARGET_POWERPC64 && reload_completed
|
||||
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|
||||
|| (GET_CODE (operands[0]) == SUBREG
|
||||
&& GET_CODE (SUBREG_REG (operands[0])) == REG
|
||||
&& REGNO (SUBREG_REG (operands[0])) <= 31))"
|
||||
[(set (match_dup 2) (match_dup 4))
|
||||
(set (match_dup 3) (match_dup 5))]
|
||||
"
|
||||
{
|
||||
int endian = (WORDS_BIG_ENDIAN == 0);
|
||||
long l[2];
|
||||
REAL_VALUE_TYPE rv;
|
||||
|
||||
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
|
||||
REAL_VALUE_TO_TARGET_DECIMAL64 (rv, l);
|
||||
|
||||
operands[2] = operand_subword (operands[0], endian, 0, DDmode);
|
||||
operands[3] = operand_subword (operands[0], 1 - endian, 0, DDmode);
|
||||
operands[4] = gen_int_mode (l[endian], SImode);
|
||||
operands[5] = gen_int_mode (l[1 - endian], SImode);
|
||||
}")
|
||||
|
||||
(define_split
|
||||
[(set (match_operand:DD 0 "gpc_reg_operand" "")
|
||||
(match_operand:DD 1 "const_double_operand" ""))]
|
||||
"TARGET_POWERPC64 && reload_completed
|
||||
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|
||||
|| (GET_CODE (operands[0]) == SUBREG
|
||||
&& GET_CODE (SUBREG_REG (operands[0])) == REG
|
||||
&& REGNO (SUBREG_REG (operands[0])) <= 31))"
|
||||
[(set (match_dup 2) (match_dup 3))]
|
||||
"
|
||||
{
|
||||
int endian = (WORDS_BIG_ENDIAN == 0);
|
||||
long l[2];
|
||||
REAL_VALUE_TYPE rv;
|
||||
#if HOST_BITS_PER_WIDE_INT >= 64
|
||||
HOST_WIDE_INT val;
|
||||
#endif
|
||||
|
||||
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
|
||||
REAL_VALUE_TO_TARGET_DECIMAL64 (rv, l);
|
||||
|
||||
operands[2] = gen_lowpart (DImode, operands[0]);
|
||||
/* HIGHPART is lower memory address when WORDS_BIG_ENDIAN. */
|
||||
#if HOST_BITS_PER_WIDE_INT >= 64
|
||||
val = ((HOST_WIDE_INT)(unsigned long)l[endian] << 32
|
||||
| ((HOST_WIDE_INT)(unsigned long)l[1 - endian]));
|
||||
|
||||
operands[3] = gen_int_mode (val, DImode);
|
||||
#else
|
||||
operands[3] = immed_double_const (l[1 - endian], l[endian], DImode);
|
||||
#endif
|
||||
}")
|
||||
|
||||
;; Don't have reload use general registers to load a constant. First,
|
||||
;; it might not work if the output operand is the equivalent of
|
||||
;; a non-offsettable memref, but also it is less efficient than loading
|
||||
;; the constant into an FP register, since it will probably be used there.
|
||||
;; The "??" is a kludge until we can figure out a more reasonable way
|
||||
;; of handling these non-offsettable values.
|
||||
(define_insn "*movdd_hardfloat32"
|
||||
[(set (match_operand:DD 0 "nonimmediate_operand" "=!r,??r,m,f,f,m,!r,!r,!r")
|
||||
(match_operand:DD 1 "input_operand" "r,m,r,f,m,f,G,H,F"))]
|
||||
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS
|
||||
&& (gpc_reg_operand (operands[0], DDmode)
|
||||
|| gpc_reg_operand (operands[1], DDmode))"
|
||||
"*
|
||||
{
|
||||
switch (which_alternative)
|
||||
{
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
case 0:
|
||||
/* We normally copy the low-numbered register first. However, if
|
||||
the first register operand 0 is the same as the second register
|
||||
of operand 1, we must copy in the opposite order. */
|
||||
if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
|
||||
return \"mr %L0,%L1\;mr %0,%1\";
|
||||
else
|
||||
return \"mr %0,%1\;mr %L0,%L1\";
|
||||
case 1:
|
||||
if (rs6000_offsettable_memref_p (operands[1])
|
||||
|| (GET_CODE (operands[1]) == MEM
|
||||
&& (GET_CODE (XEXP (operands[1], 0)) == LO_SUM
|
||||
|| GET_CODE (XEXP (operands[1], 0)) == PRE_INC
|
||||
|| GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)))
|
||||
{
|
||||
/* If the low-address word is used in the address, we must load
|
||||
it last. Otherwise, load it first. Note that we cannot have
|
||||
auto-increment in that case since the address register is
|
||||
known to be dead. */
|
||||
if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
|
||||
operands[1], 0))
|
||||
return \"{l|lwz} %L0,%L1\;{l|lwz} %0,%1\";
|
||||
else
|
||||
return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\";
|
||||
}
|
||||
else
|
||||
{
|
||||
rtx addreg;
|
||||
|
||||
addreg = find_addr_reg (XEXP (operands[1], 0));
|
||||
if (refers_to_regno_p (REGNO (operands[0]),
|
||||
REGNO (operands[0]) + 1,
|
||||
operands[1], 0))
|
||||
{
|
||||
output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg);
|
||||
output_asm_insn (\"{lx|lwzx} %L0,%1\", operands);
|
||||
output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg);
|
||||
return \"{lx|lwzx} %0,%1\";
|
||||
}
|
||||
else
|
||||
{
|
||||
output_asm_insn (\"{lx|lwzx} %0,%1\", operands);
|
||||
output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg);
|
||||
output_asm_insn (\"{lx|lwzx} %L0,%1\", operands);
|
||||
output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg);
|
||||
return \"\";
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if (rs6000_offsettable_memref_p (operands[0])
|
||||
|| (GET_CODE (operands[0]) == MEM
|
||||
&& (GET_CODE (XEXP (operands[0], 0)) == LO_SUM
|
||||
|| GET_CODE (XEXP (operands[0], 0)) == PRE_INC
|
||||
|| GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)))
|
||||
return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\";
|
||||
else
|
||||
{
|
||||
rtx addreg;
|
||||
|
||||
addreg = find_addr_reg (XEXP (operands[0], 0));
|
||||
output_asm_insn (\"{stx|stwx} %1,%0\", operands);
|
||||
output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg);
|
||||
output_asm_insn (\"{stx|stwx} %L1,%0\", operands);
|
||||
output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg);
|
||||
return \"\";
|
||||
}
|
||||
case 3:
|
||||
return \"fmr %0,%1\";
|
||||
case 4:
|
||||
return \"lfd%U1%X1 %0,%1\";
|
||||
case 5:
|
||||
return \"stfd%U0%X0 %1,%0\";
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
return \"#\";
|
||||
}
|
||||
}"
|
||||
[(set_attr "type" "two,load,store,fp,fpload,fpstore,*,*,*")
|
||||
(set_attr "length" "8,16,16,4,4,4,8,12,16")])
|
||||
|
||||
(define_insn "*movdd_softfloat32"
|
||||
[(set (match_operand:DD 0 "nonimmediate_operand" "=r,r,m,r,r,r")
|
||||
(match_operand:DD 1 "input_operand" "r,m,r,G,H,F"))]
|
||||
"! TARGET_POWERPC64 && TARGET_SOFT_FLOAT
|
||||
&& (gpc_reg_operand (operands[0], DDmode)
|
||||
|| gpc_reg_operand (operands[1], DDmode))"
|
||||
"*
|
||||
{
|
||||
switch (which_alternative)
|
||||
{
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
case 0:
|
||||
/* We normally copy the low-numbered register first. However, if
|
||||
the first register operand 0 is the same as the second register of
|
||||
operand 1, we must copy in the opposite order. */
|
||||
if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
|
||||
return \"mr %L0,%L1\;mr %0,%1\";
|
||||
else
|
||||
return \"mr %0,%1\;mr %L0,%L1\";
|
||||
case 1:
|
||||
/* If the low-address word is used in the address, we must load
|
||||
it last. Otherwise, load it first. Note that we cannot have
|
||||
auto-increment in that case since the address register is
|
||||
known to be dead. */
|
||||
if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
|
||||
operands[1], 0))
|
||||
return \"{l|lwz} %L0,%L1\;{l|lwz} %0,%1\";
|
||||
else
|
||||
return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\";
|
||||
case 2:
|
||||
return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\";
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
return \"#\";
|
||||
}
|
||||
}"
|
||||
[(set_attr "type" "two,load,store,*,*,*")
|
||||
(set_attr "length" "8,8,8,8,12,16")])
|
||||
|
||||
; ld/std require word-aligned displacements -> 'Y' constraint.
|
||||
; List Y->r and r->Y before r->r for reload.
|
||||
(define_insn "*movdd_hardfloat64"
|
||||
[(set (match_operand:DD 0 "nonimmediate_operand" "=Y,r,!r,f,f,m,*c*l,!r,*h,!r,!r,!r")
|
||||
(match_operand:DD 1 "input_operand" "r,Y,r,f,m,f,r,h,0,G,H,F"))]
|
||||
"TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS
|
||||
&& (gpc_reg_operand (operands[0], DDmode)
|
||||
|| gpc_reg_operand (operands[1], DDmode))"
|
||||
"@
|
||||
std%U0%X0 %1,%0
|
||||
ld%U1%X1 %0,%1
|
||||
mr %0,%1
|
||||
fmr %0,%1
|
||||
lfd%U1%X1 %0,%1
|
||||
stfd%U0%X0 %1,%0
|
||||
mt%0 %1
|
||||
mf%1 %0
|
||||
{cror 0,0,0|nop}
|
||||
#
|
||||
#
|
||||
#"
|
||||
[(set_attr "type" "store,load,*,fp,fpload,fpstore,mtjmpr,mfjmpr,*,*,*,*")
|
||||
(set_attr "length" "4,4,4,4,4,4,4,4,4,8,12,16")])
|
||||
|
||||
(define_insn "*movdd_softfloat64"
|
||||
[(set (match_operand:DD 0 "nonimmediate_operand" "=r,Y,r,cl,r,r,r,r,*h")
|
||||
(match_operand:DD 1 "input_operand" "Y,r,r,r,h,G,H,F,0"))]
|
||||
"TARGET_POWERPC64 && (TARGET_SOFT_FLOAT || !TARGET_FPRS)
|
||||
&& (gpc_reg_operand (operands[0], DDmode)
|
||||
|| gpc_reg_operand (operands[1], DDmode))"
|
||||
"@
|
||||
ld%U1%X1 %0,%1
|
||||
std%U0%X0 %1,%0
|
||||
mr %0,%1
|
||||
mt%0 %1
|
||||
mf%1 %0
|
||||
#
|
||||
#
|
||||
#
|
||||
{cror 0,0,0|nop}"
|
||||
[(set_attr "type" "load,store,*,mtjmpr,mfjmpr,*,*,*,*")
|
||||
(set_attr "length" "4,4,4,4,4,8,12,16,4")])
|
||||
|
||||
(define_expand "movtd"
|
||||
[(set (match_operand:TD 0 "general_operand" "")
|
||||
(match_operand:TD 1 "any_operand" ""))]
|
||||
"TARGET_HARD_FLOAT && TARGET_FPRS"
|
||||
"{ rs6000_emit_move (operands[0], operands[1], TDmode); DONE; }")
|
||||
|
||||
; It's important to list the o->f and f->o moves before f->f because
|
||||
; otherwise reload, given m->f, will try to pick f->f and reload it,
|
||||
; which doesn't make progress. Likewise r->Y must be before r->r.
|
||||
(define_insn_and_split "*movtd_internal"
|
||||
[(set (match_operand:TD 0 "nonimmediate_operand" "=o,f,f,r,Y,r")
|
||||
(match_operand:TD 1 "input_operand" "f,o,f,YGHF,r,r"))]
|
||||
"TARGET_HARD_FLOAT && TARGET_FPRS
|
||||
&& (gpc_reg_operand (operands[0], TDmode)
|
||||
|| gpc_reg_operand (operands[1], TDmode))"
|
||||
"#"
|
||||
"&& reload_completed"
|
||||
[(pc)]
|
||||
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; }
|
||||
[(set_attr "length" "8,8,8,20,20,16")])
|
||||
|
@ -1131,11 +1131,11 @@ rs6000_hard_regno_mode_ok (int regno, enum machine_mode mode)
|
||||
return INT_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1);
|
||||
|
||||
/* The float registers can only hold floating modes and DImode.
|
||||
This also excludes decimal float modes. */
|
||||
This excludes the 32-bit decimal float mode for now. */
|
||||
if (FP_REGNO_P (regno))
|
||||
return
|
||||
(SCALAR_FLOAT_MODE_P (mode)
|
||||
&& !DECIMAL_FLOAT_MODE_P (mode)
|
||||
&& mode != SDmode
|
||||
&& FP_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1))
|
||||
|| (GET_MODE_CLASS (mode) == MODE_INT
|
||||
&& GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD);
|
||||
@ -2314,7 +2314,10 @@ num_insns_constant (rtx op, enum machine_mode mode)
|
||||
REAL_VALUE_TYPE rv;
|
||||
|
||||
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
|
||||
REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
|
||||
if (DECIMAL_FLOAT_MODE_P (mode))
|
||||
REAL_VALUE_TO_TARGET_DECIMAL64 (rv, l);
|
||||
else
|
||||
REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
|
||||
high = l[WORDS_BIG_ENDIAN == 0];
|
||||
low = l[WORDS_BIG_ENDIAN != 0];
|
||||
}
|
||||
@ -3054,6 +3057,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
|
||||
return SPE_CONST_OFFSET_OK (offset);
|
||||
|
||||
case DFmode:
|
||||
case DDmode:
|
||||
if (TARGET_E500_DOUBLE)
|
||||
return SPE_CONST_OFFSET_OK (offset);
|
||||
|
||||
@ -3066,7 +3070,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
|
||||
if (TARGET_E500_DOUBLE)
|
||||
return SPE_CONST_OFFSET_OK (offset);
|
||||
|
||||
if (mode == DFmode || !TARGET_POWERPC64)
|
||||
if (mode == DFmode || mode == DDmode || !TARGET_POWERPC64)
|
||||
extra = 4;
|
||||
else if (offset & 3)
|
||||
return false;
|
||||
@ -3078,7 +3082,8 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
|
||||
&& SPE_CONST_OFFSET_OK (offset + 8));
|
||||
|
||||
case TImode:
|
||||
if (mode == TFmode || !TARGET_POWERPC64)
|
||||
case TDmode:
|
||||
if (mode == TFmode || mode == TDmode || !TARGET_POWERPC64)
|
||||
extra = 12;
|
||||
else if (offset & 3)
|
||||
return false;
|
||||
@ -3233,8 +3238,9 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
|
||||
&& GET_MODE_NUNITS (mode) == 1
|
||||
&& ((TARGET_HARD_FLOAT && TARGET_FPRS)
|
||||
|| TARGET_POWERPC64
|
||||
|| (((mode != DImode && mode != DFmode) || TARGET_E500_DOUBLE)
|
||||
&& mode != TFmode))
|
||||
|| (((mode != DImode && mode != DFmode && mode != DDmode)
|
||||
|| TARGET_E500_DOUBLE)
|
||||
&& mode != TFmode && mode != TDmode))
|
||||
&& (TARGET_POWERPC64 || mode != DImode)
|
||||
&& mode != TImode)
|
||||
{
|
||||
@ -3255,6 +3261,7 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
|
||||
}
|
||||
else if (SPE_VECTOR_MODE (mode)
|
||||
|| (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
|
||||
|| mode == DDmode || mode == TDmode
|
||||
|| mode == DImode)))
|
||||
{
|
||||
if (mode == DImode)
|
||||
@ -3700,10 +3707,11 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
|
||||
&& DEFAULT_ABI == ABI_V4
|
||||
&& !flag_pic
|
||||
#endif
|
||||
/* Don't do this for TFmode, since the result isn't offsettable.
|
||||
/* Don't do this for TFmode or TDmode, since the result isn't offsettable.
|
||||
The same goes for DImode without 64-bit gprs and DFmode
|
||||
without fprs. */
|
||||
&& mode != TFmode
|
||||
&& mode != TDmode
|
||||
&& (mode != DImode || TARGET_POWERPC64)
|
||||
&& (mode != DFmode || TARGET_POWERPC64
|
||||
|| (TARGET_FPRS && TARGET_HARD_FLOAT)))
|
||||
@ -3773,8 +3781,8 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
|
||||
word aligned.
|
||||
|
||||
For modes spanning multiple registers (DFmode in 32-bit GPRs,
|
||||
32-bit DImode, TImode, TFmode), indexed addressing cannot be used because
|
||||
adjacent memory cells are accessed by adding word-sized offsets
|
||||
32-bit DImode, TImode, TFmode, TDmode), indexed addressing cannot be used
|
||||
because adjacent memory cells are accessed by adding word-sized offsets
|
||||
during assembly output. */
|
||||
int
|
||||
rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
|
||||
@ -3795,6 +3803,7 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
|
||||
&& !ALTIVEC_VECTOR_MODE (mode)
|
||||
&& !SPE_VECTOR_MODE (mode)
|
||||
&& mode != TFmode
|
||||
&& mode != TDmode
|
||||
/* Restrict addressing for DI because of our SUBREG hackery. */
|
||||
&& !(TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
|
||||
|| mode == DImode))
|
||||
@ -3817,6 +3826,7 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
|
||||
return 1;
|
||||
if (mode != TImode
|
||||
&& mode != TFmode
|
||||
&& mode != TDmode
|
||||
&& ((TARGET_HARD_FLOAT && TARGET_FPRS)
|
||||
|| TARGET_POWERPC64
|
||||
|| ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
|
||||
@ -4173,7 +4183,7 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
|
||||
}
|
||||
|
||||
/* Helper for the following. Get rid of [r+r] memory refs
|
||||
in cases where it won't work (TImode, TFmode). */
|
||||
in cases where it won't work (TImode, TFmode, TDmode). */
|
||||
|
||||
static void
|
||||
rs6000_eliminate_indexed_memrefs (rtx operands[2])
|
||||
@ -4337,10 +4347,12 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
|
||||
break;
|
||||
|
||||
case TFmode:
|
||||
case TDmode:
|
||||
rs6000_eliminate_indexed_memrefs (operands);
|
||||
/* fall through */
|
||||
|
||||
case DFmode:
|
||||
case DDmode:
|
||||
case SFmode:
|
||||
if (CONSTANT_P (operands[1])
|
||||
&& ! easy_fp_constant (operands[1], mode))
|
||||
@ -4552,7 +4564,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
|
||||
/* Nonzero if we can use a floating-point register to pass this arg. */
|
||||
#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE) \
|
||||
(SCALAR_FLOAT_MODE_P (MODE) \
|
||||
&& !DECIMAL_FLOAT_MODE_P (MODE) \
|
||||
&& (MODE) != SDmode \
|
||||
&& (CUM)->fregno <= FP_ARG_MAX_REG \
|
||||
&& TARGET_HARD_FLOAT && TARGET_FPRS)
|
||||
|
||||
@ -4794,7 +4806,7 @@ function_arg_boundary (enum machine_mode mode, tree type)
|
||||
&& (GET_MODE_SIZE (mode) == 8
|
||||
|| (TARGET_HARD_FLOAT
|
||||
&& TARGET_FPRS
|
||||
&& mode == TFmode)))
|
||||
&& (mode == TFmode || mode == TDmode))))
|
||||
return 64;
|
||||
else if (SPE_VECTOR_MODE (mode)
|
||||
|| (type && TREE_CODE (type) == VECTOR_TYPE
|
||||
@ -5032,14 +5044,20 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
{
|
||||
if (TARGET_HARD_FLOAT && TARGET_FPRS
|
||||
&& (mode == SFmode || mode == DFmode
|
||||
|| mode == DDmode || mode == TDmode
|
||||
|| (mode == TFmode && !TARGET_IEEEQUAD)))
|
||||
{
|
||||
if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG)
|
||||
/* _Decimal128 must use an even/odd register pair. */
|
||||
if (mode == TDmode && cum->fregno % 2)
|
||||
cum->fregno++;
|
||||
|
||||
if (cum->fregno + (mode == TFmode || mode == TDmode ? 1 : 0)
|
||||
<= FP_ARG_V4_MAX_REG)
|
||||
cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
|
||||
else
|
||||
{
|
||||
cum->fregno = FP_ARG_V4_MAX_REG + 1;
|
||||
if (mode == DFmode || mode == TFmode)
|
||||
if (mode == DFmode || mode == TFmode || mode == DDmode || mode == TDmode)
|
||||
cum->words += cum->words & 1;
|
||||
cum->words += rs6000_arg_size (mode, type);
|
||||
}
|
||||
@ -5091,7 +5109,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
cum->words = align_words + n_words;
|
||||
|
||||
if (SCALAR_FLOAT_MODE_P (mode)
|
||||
&& !DECIMAL_FLOAT_MODE_P (mode)
|
||||
&& mode != SDmode
|
||||
&& TARGET_HARD_FLOAT && TARGET_FPRS)
|
||||
cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
|
||||
|
||||
@ -5310,7 +5328,7 @@ rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
|
||||
= gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (mode, cum->fregno++),
|
||||
GEN_INT (bitpos / BITS_PER_UNIT));
|
||||
if (mode == TFmode)
|
||||
if (mode == TFmode || mode == TDmode)
|
||||
cum->fregno++;
|
||||
}
|
||||
else if (cum->named && USE_ALTIVEC_FOR_ARG_P (cum, mode, ftype, 1))
|
||||
@ -5571,8 +5589,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
else if (TARGET_SPE_ABI && TARGET_SPE
|
||||
&& (SPE_VECTOR_MODE (mode)
|
||||
|| (TARGET_E500_DOUBLE && (mode == DFmode
|
||||
|| mode == DDmode
|
||||
|| mode == DCmode
|
||||
|| mode == TFmode
|
||||
|| mode == TDmode
|
||||
|| mode == TCmode))))
|
||||
return rs6000_spe_function_arg (cum, mode, type);
|
||||
|
||||
@ -5580,9 +5600,15 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
{
|
||||
if (TARGET_HARD_FLOAT && TARGET_FPRS
|
||||
&& (mode == SFmode || mode == DFmode
|
||||
|| (mode == TFmode && !TARGET_IEEEQUAD)))
|
||||
|| (mode == TFmode && !TARGET_IEEEQUAD)
|
||||
|| mode == DDmode || mode == TDmode))
|
||||
{
|
||||
if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG)
|
||||
/* _Decimal128 must use an even/odd register pair. */
|
||||
if (mode == TDmode && cum->fregno % 2)
|
||||
cum->fregno++;
|
||||
|
||||
if (cum->fregno + (mode == TFmode || mode == TDmode ? 1 : 0)
|
||||
<= FP_ARG_V4_MAX_REG)
|
||||
return gen_rtx_REG (mode, cum->fregno);
|
||||
else
|
||||
return NULL_RTX;
|
||||
@ -5625,10 +5651,11 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
||||
{
|
||||
/* Currently, we only ever need one reg here because complex
|
||||
doubles are split. */
|
||||
gcc_assert (cum->fregno == FP_ARG_MAX_REG && fmode == TFmode);
|
||||
gcc_assert (cum->fregno == FP_ARG_MAX_REG
|
||||
&& (fmode == TFmode || fmode == TDmode));
|
||||
|
||||
/* Long double split over regs and memory. */
|
||||
fmode = DFmode;
|
||||
/* Long double or _Decimal128 split over regs and memory. */
|
||||
fmode = DECIMAL_FLOAT_MODE_P (fmode) ? DDmode : DFmode;
|
||||
}
|
||||
|
||||
/* Do we also need to pass this arg in the parameter save
|
||||
@ -6183,6 +6210,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
|
||||
tree lab_false, lab_over, addr;
|
||||
int align;
|
||||
tree ptrtype = build_pointer_type (type);
|
||||
int regalign = 0;
|
||||
|
||||
if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
|
||||
{
|
||||
@ -6239,7 +6267,9 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
|
||||
if (TARGET_HARD_FLOAT && TARGET_FPRS
|
||||
&& (TYPE_MODE (type) == SFmode
|
||||
|| TYPE_MODE (type) == DFmode
|
||||
|| TYPE_MODE (type) == TFmode))
|
||||
|| TYPE_MODE (type) == TFmode
|
||||
|| TYPE_MODE (type) == DDmode
|
||||
|| TYPE_MODE (type) == TDmode))
|
||||
{
|
||||
/* FP args go in FP registers, if present. */
|
||||
reg = fpr;
|
||||
@ -6280,10 +6310,19 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
|
||||
u = reg;
|
||||
if (n_reg == 2 && reg == gpr)
|
||||
{
|
||||
regalign = 1;
|
||||
u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg,
|
||||
size_int (n_reg - 1));
|
||||
u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
|
||||
}
|
||||
/* _Decimal128 is passed in even/odd fpr pairs; the stored
|
||||
reg number is 0 for f1, so we want to make it odd. */
|
||||
else if (reg == fpr && TYPE_MODE (type) == TDmode)
|
||||
{
|
||||
regalign = 1;
|
||||
t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), reg, size_int (1));
|
||||
u = build2 (MODIFY_EXPR, void_type_node, reg, t);
|
||||
}
|
||||
|
||||
t = fold_convert (TREE_TYPE (reg), size_int (8 - n_reg + 1));
|
||||
t = build2 (GE_EXPR, boolean_type_node, u, t);
|
||||
@ -6309,10 +6348,10 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
|
||||
t = build1 (LABEL_EXPR, void_type_node, lab_false);
|
||||
append_to_statement_list (t, pre_p);
|
||||
|
||||
if ((n_reg == 2 && reg != gpr) || n_reg > 2)
|
||||
if ((n_reg == 2 && !regalign) || n_reg > 2)
|
||||
{
|
||||
/* Ensure that we don't find any more args in regs.
|
||||
Alignment has taken care of the n_reg == 2 gpr case. */
|
||||
Alignment has taken care of for special cases. */
|
||||
t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (reg), reg, size_int (8));
|
||||
gimplify_and_add (t, pre_p);
|
||||
}
|
||||
@ -12923,7 +12962,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
|
||||
mode = GET_MODE (dst);
|
||||
nregs = hard_regno_nregs[reg][mode];
|
||||
if (FP_REGNO_P (reg))
|
||||
reg_mode = DFmode;
|
||||
reg_mode = DECIMAL_FLOAT_MODE_P (mode) ? DDmode : DFmode;
|
||||
else if (ALTIVEC_REGNO_P (reg))
|
||||
reg_mode = V16QImode;
|
||||
else if (TARGET_E500_DOUBLE && mode == TFmode)
|
||||
@ -15857,7 +15896,9 @@ rs6000_output_function_epilogue (FILE *file,
|
||||
break;
|
||||
|
||||
case DFmode:
|
||||
case DDmode:
|
||||
case TFmode:
|
||||
case TDmode:
|
||||
bits = 0x3;
|
||||
break;
|
||||
|
||||
@ -20196,7 +20237,7 @@ rs6000_register_move_cost (enum machine_mode mode,
|
||||
|
||||
/* Moving between two similar registers is just one instruction. */
|
||||
else if (reg_classes_intersect_p (to, from))
|
||||
return mode == TFmode ? 4 : 2;
|
||||
return (mode == TFmode || mode == TDmode) ? 4 : 2;
|
||||
|
||||
/* Everything else has to go through GENERAL_REGS. */
|
||||
else
|
||||
@ -20529,7 +20570,28 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
|
||||
mode = TYPE_MODE (valtype);
|
||||
|
||||
if (DECIMAL_FLOAT_MODE_P (mode))
|
||||
regno = GP_ARG_RETURN;
|
||||
{
|
||||
if (TARGET_HARD_FLOAT && TARGET_FPRS)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
case SDmode:
|
||||
regno = GP_ARG_RETURN;
|
||||
break;
|
||||
case DDmode:
|
||||
regno = FP_ARG_RETURN;
|
||||
break;
|
||||
case TDmode:
|
||||
/* Use f2:f3 specified by the ABI. */
|
||||
regno = FP_ARG_RETURN + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
regno = GP_ARG_RETURN;
|
||||
}
|
||||
else if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS)
|
||||
regno = FP_ARG_RETURN;
|
||||
else if (TREE_CODE (valtype) == COMPLEX_TYPE
|
||||
@ -20571,7 +20633,28 @@ rs6000_libcall_value (enum machine_mode mode)
|
||||
}
|
||||
|
||||
if (DECIMAL_FLOAT_MODE_P (mode))
|
||||
regno = GP_ARG_RETURN;
|
||||
{
|
||||
if (TARGET_HARD_FLOAT && TARGET_FPRS)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
case SDmode:
|
||||
regno = GP_ARG_RETURN;
|
||||
break;
|
||||
case DDmode:
|
||||
regno = FP_ARG_RETURN;
|
||||
break;
|
||||
case TDmode:
|
||||
/* Use f2:f3 specified by the ABI. */
|
||||
regno = FP_ARG_RETURN + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
regno = GP_ARG_RETURN;
|
||||
}
|
||||
else if (SCALAR_FLOAT_MODE_P (mode)
|
||||
&& TARGET_HARD_FLOAT && TARGET_FPRS)
|
||||
regno = FP_ARG_RETURN;
|
||||
|
@ -1493,7 +1493,7 @@
|
||||
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,?r,r")
|
||||
(plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,r,b")
|
||||
(match_operand:GPR 2 "add_operand" "r,I,I,L")))]
|
||||
""
|
||||
"!DECIMAL_FLOAT_MODE_P (GET_MODE (operands[0])) && !DECIMAL_FLOAT_MODE_P (GET_MODE (operands[1]))"
|
||||
"@
|
||||
{cax|add} %0,%1,%2
|
||||
{cal %0,%2(%1)|addi %0,%1,%2}
|
||||
@ -14531,3 +14531,4 @@
|
||||
(include "sync.md")
|
||||
(include "altivec.md")
|
||||
(include "spe.md")
|
||||
(include "dfp.md")
|
||||
|
Loading…
Reference in New Issue
Block a user