re PR target/53914 (poor code generated for offset addressing on ppc32)

PR target/53914
	PR target/54009
	* config/rs6000/constraints.md (Y): Use mem_operand_gpr.
	* config/rs6000/predicates.md (word_offset_memref_operand): Delete.
	Adjust all rs6000_legitimate_offset_address_p calls.
	* config/rs6000/rs6000-protos.h (mem_operand_gpr): Declare.
	(rs6000_secondary_reload_gpr): Declare.
	(rs6000_legitimate_offset_address_p): Update prototype.
	(rs6000_offsettable_memref_p): Delete.
	(rs6000_secondary_reload_ppc64): Delete.
	* config/rs6000/rs6000.c (address_offset): New function.
	(mem_operand_gpr): Likewise.
	(rs6000_legitimate_offset_address_p): Add worst_case param.  When
	not worst_case assume class of regs with least restrictive offsets.
	Adjust all calls.
	(legitimate_lo_sum_address_p): Simplify register mode tests.
	(rs6000_legitimize_address): Likewise.  Assume best case offset
	addressing.  Combine ELF and MACHO lo_sum code.
	(rs6000_mode_dependent_address): Correct offset addressing limits.
	(rs6000_offsettable_memref_p): Make static, add reg_mode param.
	Use reg_mode to help rs6000_legitimate_offset_address_p.
	(rs6000_secondary_reload): Use address_offset.  Handle 32-bit multi
	gpr load/store when offset too large.
	(rs6000_secondary_reload_gpr): Renamed rs6000_secondary_reload_ppc64.
	(rs6000_split_multireg_move): Adjust rs6000_offsettable_memref_p calls.
	* config/rs6000/rs6000.md (movdf_hardfloat32): Use 'Y' constraint
	for gpr load/store.  Order alternatives as r->Y,Y->r,r->r and
	d->m,m->d,d->d.  Correct size of gpr load/store.
	(movdf_softfloat32): Use 'Y' constraint for gpr load/store.  Order
	alternatives.
	(movti_ppc64): Likewise.
	(movdi_internal32): Likewise.  Also disparage fprs.
	(movdi_mfpgpr, movdi_internal64): Likewise.
	(movtf_internal): Use 'm' for fpr load/store.  Order alternatives.
	(movtf_softfloat): Order alternatives.
	(extenddftf2_internal): Use 'm' and 'Y' for store.
	(movti_power, movti_string): Use 'Y' for gpr load/store.  Order.
	(stack_protect_setdi, stack_protect_testdi): Likewise.
	(movdf_hardfloat64_mfpgpr, movdf_hardfloat64): Order alternatives.
	(movdf_softfloat64): Likewise.
	(reload_<mode>_store): Adjust reload_di_store to provide
	reload_si_store as well.
	(reload_<mode>_load): Likewise.

From-SVN: r189801
This commit is contained in:
Alan Modra 2012-07-24 15:25:50 +09:30 committed by Alan Modra
parent 71922d523d
commit d32d6b75ca
6 changed files with 319 additions and 225 deletions

View file

@ -1,3 +1,49 @@
2012-07-24 Alan Modra <amodra@gmail.com>
PR target/53914
PR target/54009
* config/rs6000/constraints.md (Y): Use mem_operand_gpr.
* config/rs6000/predicates.md (word_offset_memref_operand): Delete.
Adjust all rs6000_legitimate_offset_address_p calls.
* config/rs6000/rs6000-protos.h (mem_operand_gpr): Declare.
(rs6000_secondary_reload_gpr): Declare.
(rs6000_legitimate_offset_address_p): Update prototype.
(rs6000_offsettable_memref_p): Delete.
(rs6000_secondary_reload_ppc64): Delete.
* config/rs6000/rs6000.c (address_offset): New function.
(mem_operand_gpr): Likewise.
(rs6000_legitimate_offset_address_p): Add worst_case param. When
not worst_case assume class of regs with least restrictive offsets.
Adjust all calls.
(legitimate_lo_sum_address_p): Simplify register mode tests.
(rs6000_legitimize_address): Likewise. Assume best case offset
addressing. Combine ELF and MACHO lo_sum code.
(rs6000_mode_dependent_address): Correct offset addressing limits.
(rs6000_offsettable_memref_p): Make static, add reg_mode param.
Use reg_mode to help rs6000_legitimate_offset_address_p.
(rs6000_secondary_reload): Use address_offset. Handle 32-bit multi
gpr load/store when offset too large.
(rs6000_secondary_reload_gpr): Renamed rs6000_secondary_reload_ppc64.
(rs6000_split_multireg_move): Adjust rs6000_offsettable_memref_p calls.
* config/rs6000/rs6000.md (movdf_hardfloat32): Use 'Y' constraint
for gpr load/store. Order alternatives as r->Y,Y->r,r->r and
d->m,m->d,d->d. Correct size of gpr load/store.
(movdf_softfloat32): Use 'Y' constraint for gpr load/store. Order
alternatives.
(movti_ppc64): Likewise.
(movdi_internal32): Likewise. Also disparage fprs.
(movdi_mfpgpr, movdi_internal64): Likewise.
(movtf_internal): Use 'm' for fpr load/store. Order alternatives.
(movtf_softfloat): Order alternatives.
(extenddftf2_internal): Use 'm' and 'Y' for store.
(movti_power, movti_string): Use 'Y' for gpr load/store. Order.
(stack_protect_setdi, stack_protect_testdi): Likewise.
(movdf_hardfloat64_mfpgpr, movdf_hardfloat64): Order alternatives.
(movdf_softfloat64): Likewise.
(reload_<mode>_store): Adjust reload_di_store to provide
reload_si_store as well.
(reload_<mode>_load): Likewise.
2012-07-23 Oleg Endo <olegendo@gcc.gnu.org>
PR target/51244

View file

@ -150,8 +150,9 @@ to use @samp{m} or @samp{es} in @code{asm} statements)"
(match_test "GET_CODE (XEXP (op, 0)) == REG")))
(define_memory_constraint "Y"
"Indexed or word-aligned displacement memory operand"
(match_operand 0 "word_offset_memref_operand"))
"memory operand for 8 byte and 16 byte gpr load/store"
(and (match_code "mem")
(match_operand 0 "mem_operand_gpr")))
(define_memory_constraint "Z"
"Memory operand that is an indexed or indirect from a register (it is

View file

@ -432,29 +432,6 @@
(and (match_operand 0 "memory_operand")
(match_test "offsettable_nonstrict_memref_p (op)")))
;; Return 1 if the operand is a memory operand with an address divisible by 4
(define_predicate "word_offset_memref_operand"
(match_operand 0 "memory_operand")
{
/* Address inside MEM. */
op = XEXP (op, 0);
/* Extract address from auto-inc/dec. */
if (GET_CODE (op) == PRE_INC
|| GET_CODE (op) == PRE_DEC)
op = XEXP (op, 0);
else if (GET_CODE (op) == PRE_MODIFY)
op = XEXP (op, 1);
else if (GET_CODE (op) == LO_SUM
&& GET_CODE (XEXP (op, 0)) == REG
&& GET_CODE (XEXP (op, 1)) == CONST)
op = XEXP (XEXP (op, 1), 0);
return (GET_CODE (op) != PLUS
|| GET_CODE (XEXP (op, 1)) != CONST_INT
|| INTVAL (XEXP (op, 1)) % 4 == 0);
})
;; Return 1 if the operand is an indexed or indirect memory operand.
(define_predicate "indexed_or_indirect_operand"
(match_code "mem")
@ -892,7 +869,8 @@
return input_operand (op, mode);
})
;; Return true if OP is an invalid SUBREG operation on the e500.
;; Return true if OP is a non-immediate operand and not an invalid
;; SUBREG operation on the e500.
(define_predicate "rs6000_nonimmediate_operand"
(match_code "reg,subreg,mem")
{
@ -1325,7 +1303,7 @@
if (base_regno == 0)
return 0;
}
else if (rs6000_legitimate_offset_address_p (SImode, src_addr, 0))
else if (rs6000_legitimate_offset_address_p (SImode, src_addr, false, false))
{
offset = INTVAL (XEXP (src_addr, 1));
base_regno = REGNO (XEXP (src_addr, 0));
@ -1353,7 +1331,7 @@
newoffset = 0;
addr_reg = newaddr;
}
else if (rs6000_legitimate_offset_address_p (SImode, newaddr, 0))
else if (rs6000_legitimate_offset_address_p (SImode, newaddr, false, false))
{
addr_reg = XEXP (newaddr, 0);
newoffset = INTVAL (XEXP (newaddr, 1));
@ -1400,7 +1378,7 @@
if (base_regno == 0)
return 0;
}
else if (rs6000_legitimate_offset_address_p (SImode, dest_addr, 0))
else if (rs6000_legitimate_offset_address_p (SImode, dest_addr, false, false))
{
offset = INTVAL (XEXP (dest_addr, 1));
base_regno = REGNO (XEXP (dest_addr, 0));
@ -1428,7 +1406,7 @@
newoffset = 0;
addr_reg = newaddr;
}
else if (rs6000_legitimate_offset_address_p (SImode, newaddr, 0))
else if (rs6000_legitimate_offset_address_p (SImode, newaddr, false, false))
{
addr_reg = XEXP (newaddr, 0);
newoffset = INTVAL (XEXP (newaddr, 1));

View file

@ -38,6 +38,7 @@ extern bool macho_lo_sum_memory_operand (rtx, enum machine_mode);
extern int num_insns_constant (rtx, enum machine_mode);
extern int num_insns_constant_wide (HOST_WIDE_INT);
extern int small_data_operand (rtx, enum machine_mode);
extern bool mem_operand_gpr (rtx, enum machine_mode);
extern bool toc_relative_expr_p (const_rtx, bool);
extern bool invalid_e500_subreg (rtx, enum machine_mode);
extern void validate_condition_mode (enum rtx_code, enum machine_mode);
@ -83,7 +84,7 @@ extern bool (*rs6000_cannot_change_mode_class_ptr) (enum machine_mode,
enum machine_mode,
enum reg_class);
extern void rs6000_secondary_reload_inner (rtx, rtx, rtx, bool);
extern void rs6000_secondary_reload_ppc64 (rtx, rtx, rtx, bool);
extern void rs6000_secondary_reload_gpr (rtx, rtx, rtx, bool);
extern int paired_emit_vector_cond_expr (rtx, rtx, rtx,
rtx, rtx, rtx);
extern void paired_expand_vector_move (rtx operands[]);
@ -121,9 +122,9 @@ extern void rs6000_emit_move (rtx, rtx, enum machine_mode);
extern rtx rs6000_secondary_memory_needed_rtx (enum machine_mode);
extern rtx (*rs6000_legitimize_reload_address_ptr) (rtx, enum machine_mode,
int, int, int, int *);
extern bool rs6000_legitimate_offset_address_p (enum machine_mode, rtx, int);
extern bool rs6000_legitimate_offset_address_p (enum machine_mode, rtx,
bool, bool);
extern rtx rs6000_find_base_term (rtx);
extern bool rs6000_offsettable_memref_p (rtx);
extern rtx rs6000_return_addr (int, rtx);
extern void rs6000_output_symbol_ref (FILE*, rtx);
extern HOST_WIDE_INT rs6000_initial_elimination_offset (int, int);

View file

@ -5017,6 +5017,64 @@ gpr_or_gpr_p (rtx op0, rtx op1)
|| (REG_P (op1) && INT_REGNO_P (REGNO (op1))));
}
/* Given an address, return a constant offset term if one exists. */
static rtx
address_offset (rtx op)
{
if (GET_CODE (op) == PRE_INC
|| GET_CODE (op) == PRE_DEC)
op = XEXP (op, 0);
else if (GET_CODE (op) == PRE_MODIFY
|| GET_CODE (op) == LO_SUM)
op = XEXP (op, 1);
if (GET_CODE (op) == CONST)
op = XEXP (op, 0);
if (GET_CODE (op) == PLUS)
op = XEXP (op, 1);
if (CONST_INT_P (op))
return op;
return NULL_RTX;
}
/* Return true if the MEM operand is a memory operand suitable for use
with a (full width, possibly multiple) gpr load/store. On
powerpc64 this means the offset must be divisible by 4.
Implements 'Y' constraint.
Accept direct, indexed, offset, lo_sum and tocref. Since this is
a constraint function we know the operand has satisfied a suitable
memory predicate. Also accept some odd rtl generated by reload
(see rs6000_legitimize_reload_address for various forms). It is
important that reload rtl be accepted by appropriate constraints
but not by the operand predicate.
Offsetting a lo_sum should not be allowed, except where we know by
alignment that a 32k boundary is not crossed, but see the ???
comment in rs6000_legitimize_reload_address. */
bool
mem_operand_gpr (rtx op, enum machine_mode mode)
{
unsigned HOST_WIDE_INT offset;
int extra;
op = address_offset (XEXP (op, 0));
if (op == NULL_RTX)
return true;
offset = INTVAL (op);
extra = GET_MODE_SIZE (mode) - UNITS_PER_WORD;
if (extra < 0)
extra = 0;
else if (TARGET_POWERPC64 && (offset & 3) != 0)
return false;
return offset + 0x8000 < 0x10000u - extra;
}
/* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address_p. */
@ -5234,13 +5292,15 @@ legitimate_small_data_p (enum machine_mode mode, rtx x)
#define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
bool
rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x,
bool strict, bool worst_case)
{
unsigned HOST_WIDE_INT offset, extra;
unsigned HOST_WIDE_INT offset;
unsigned int extra;
if (GET_CODE (x) != PLUS)
return false;
if (GET_CODE (XEXP (x, 0)) != REG)
if (!REG_P (XEXP (x, 0)))
return false;
if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
return false;
@ -5263,14 +5323,6 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
return SPE_CONST_OFFSET_OK (offset);
case DFmode:
if (TARGET_E500_DOUBLE)
return SPE_CONST_OFFSET_OK (offset);
/* If we are using VSX scalar loads, restrict ourselves to reg+reg
addressing. */
if (VECTOR_MEM_VSX_P (DFmode))
return false;
case DDmode:
case DImode:
/* On e500v2, we may have:
@ -5281,25 +5333,33 @@ 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 || mode == DDmode || !TARGET_POWERPC64)
/* If we are using VSX scalar loads, restrict ourselves to reg+reg
addressing. */
if (mode == DFmode && VECTOR_MEM_VSX_P (DFmode))
return false;
if (!worst_case)
break;
if (!TARGET_POWERPC64)
extra = 4;
else if (offset & 3)
return false;
break;
case TFmode:
case TDmode:
case TImode:
if (TARGET_E500_DOUBLE)
return (SPE_CONST_OFFSET_OK (offset)
&& SPE_CONST_OFFSET_OK (offset + 8));
case TDmode:
case TImode:
if (mode == TFmode || mode == TDmode || !TARGET_POWERPC64)
extra = 8;
if (!worst_case)
break;
if (!TARGET_POWERPC64)
extra = 12;
else if (offset & 3)
return false;
else
extra = 8;
break;
default:
@ -5379,9 +5439,7 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
return false;
/* Restrict addressing for DI because of our SUBREG hackery. */
if (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
|| mode == DDmode || mode == TDmode
|| mode == DImode))
if (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
return false;
x = XEXP (x, 1);
@ -5393,10 +5451,10 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
return false;
if (GET_MODE_NUNITS (mode) != 1)
return false;
if (GET_MODE_BITSIZE (mode) > 64
|| (GET_MODE_BITSIZE (mode) > 32 && !TARGET_POWERPC64
&& !(TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
&& (mode == DFmode || mode == DDmode))))
if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
&& !(/* ??? Assume floating point reg based on mode? */
TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
&& (mode == DFmode || mode == DDmode)))
return false;
return CONSTANT_P (x);
@ -5431,7 +5489,7 @@ static rtx
rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
enum machine_mode mode)
{
unsigned int extra = 0;
unsigned int extra;
if (!reg_offset_addressing_ok_p (mode))
{
@ -5458,22 +5516,18 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
return rs6000_legitimize_tls_address (x, model);
}
extra = 0;
switch (mode)
{
case DFmode:
case DDmode:
extra = 4;
break;
case DImode:
if (!TARGET_POWERPC64)
extra = 4;
break;
case TFmode:
case TDmode:
extra = 12;
break;
case TImode:
extra = TARGET_POWERPC64 ? 8 : 12;
/* As in legitimate_offset_address_p we do not assume
worst-case. The mode here is just a hint as to the registers
used. A TImode is usually in gprs, but may actually be in
fprs. Leave worst-case scenario for reload to handle via
insn constraints. */
extra = 8;
break;
default:
break;
@ -5484,13 +5538,8 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& ((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000)
>= 0x10000 - extra)
&& !((TARGET_POWERPC64
&& (mode == DImode || mode == TImode)
&& (INTVAL (XEXP (x, 1)) & 3) != 0)
|| SPE_VECTOR_MODE (mode)
|| (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
|| mode == DImode || mode == DDmode
|| mode == TDmode))))
&& !(SPE_VECTOR_MODE (mode)
|| (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD)))
{
HOST_WIDE_INT high_int, low_int;
rtx sum;
@ -5506,23 +5555,17 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
&& GET_CODE (XEXP (x, 0)) == REG
&& GET_CODE (XEXP (x, 1)) != CONST_INT
&& GET_MODE_NUNITS (mode) == 1
&& ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
|| TARGET_POWERPC64
|| ((mode != DImode && mode != DFmode && mode != DDmode)
|| (TARGET_E500_DOUBLE && mode != DDmode)))
&& (TARGET_POWERPC64 || mode != DImode)
&& !avoiding_indexed_address_p (mode)
&& mode != TImode
&& mode != TFmode
&& mode != TDmode)
&& (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
|| (/* ??? Assume floating point reg based on mode? */
(TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
&& (mode == DFmode || mode == DDmode)))
&& !avoiding_indexed_address_p (mode))
{
return gen_rtx_PLUS (Pmode, XEXP (x, 0),
force_reg (Pmode, force_operand (XEXP (x, 1), 0)));
}
else if (SPE_VECTOR_MODE (mode)
|| (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
|| mode == DDmode || mode == TDmode
|| mode == DImode)))
|| (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD))
{
if (mode == DImode)
return x;
@ -5555,7 +5598,11 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
return force_reg (Pmode, x);
}
else if (TARGET_ELF
else if ((TARGET_ELF
#if TARGET_MACHO
|| !MACHO_DYNAMIC_NO_PIC_P
#endif
)
&& TARGET_32BIT
&& TARGET_NO_TOC
&& ! flag_pic
@ -5563,30 +5610,16 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
&& GET_CODE (x) != CONST_DOUBLE
&& CONSTANT_P (x)
&& GET_MODE_NUNITS (mode) == 1
&& (GET_MODE_BITSIZE (mode) <= 32
|| ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
&& (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
|| (/* ??? Assume floating point reg based on mode? */
(TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
&& (mode == DFmode || mode == DDmode))))
{
rtx reg = gen_reg_rtx (Pmode);
emit_insn (gen_elf_high (reg, x));
return gen_rtx_LO_SUM (Pmode, reg, x);
}
else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC
&& ! flag_pic
#if TARGET_MACHO
&& ! MACHO_DYNAMIC_NO_PIC_P
#endif
&& GET_CODE (x) != CONST_INT
&& GET_CODE (x) != CONST_DOUBLE
&& CONSTANT_P (x)
&& GET_MODE_NUNITS (mode) == 1
&& ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
|| (mode != DFmode && mode != DDmode))
&& mode != DImode
&& mode != TImode)
{
rtx reg = gen_reg_rtx (Pmode);
emit_insn (gen_macho_high (reg, x));
if (TARGET_ELF)
emit_insn (gen_elf_high (reg, x));
else
emit_insn (gen_macho_high (reg, x));
return gen_rtx_LO_SUM (Pmode, reg, x);
}
else if (TARGET_TOC
@ -6177,7 +6210,18 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
#endif
/* 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 and DDmode
without fprs. */
without fprs.
??? Assume floating point reg based on mode? This assumption is
violated by eg. powerpc-linux -m32 compile of gcc.dg/pr28796-2.c
where reload ends up doing a DFmode load of a constant from
mem using two gprs. Unfortunately, at this point reload
hasn't yet selected regs so poking around in reload data
won't help and even if we could figure out the regs reliably,
we'd still want to allow this transformation when the mem is
naturally aligned. Since we say the address is good here, we
can't disable offsets from LO_SUMs in mem_operand_gpr.
FIXME: Allow offset from lo_sum for other modes too, when
mem is sufficiently aligned. */
&& mode != TFmode
&& mode != TDmode
&& (mode != DImode || TARGET_POWERPC64)
@ -6327,7 +6371,7 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
|| XEXP (x, 0) == arg_pointer_rtx)
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
return 1;
if (rs6000_legitimate_offset_address_p (mode, x, reg_ok_strict))
if (rs6000_legitimate_offset_address_p (mode, x, reg_ok_strict, false))
return 1;
if (mode != TImode
&& mode != TFmode
@ -6355,7 +6399,8 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
&& (mode == DFmode || mode == DDmode || mode == DImode))
&& TARGET_UPDATE
&& legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict)
&& (rs6000_legitimate_offset_address_p (mode, XEXP (x, 1), reg_ok_strict)
&& (rs6000_legitimate_offset_address_p (mode, XEXP (x, 1),
reg_ok_strict, false)
|| (!avoiding_indexed_address_p (mode)
&& legitimate_indexed_address_p (XEXP (x, 1), reg_ok_strict)))
&& rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
@ -6419,7 +6464,7 @@ rs6000_mode_dependent_address (const_rtx addr)
&& GET_CODE (XEXP (addr, 1)) == CONST_INT)
{
unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
return val + 12 + 0x8000 >= 0x10000;
return val + 0x8000 >= 0x10000 - (TARGET_POWERPC64 ? 8 : 12);
}
break;
@ -6489,14 +6534,16 @@ rs6000_find_base_term (rtx op)
in 32-bit mode, that the recog predicate rejects. */
bool
rs6000_offsettable_memref_p (rtx op)
static bool
rs6000_offsettable_memref_p (rtx op, enum machine_mode reg_mode)
{
bool worst_case;
if (!MEM_P (op))
return false;
/* First mimic offsettable_memref_p. */
if (offsettable_address_p (1, GET_MODE (op), XEXP (op, 0)))
if (offsettable_address_p (true, GET_MODE (op), XEXP (op, 0)))
return true;
/* offsettable_address_p invokes rs6000_mode_dependent_address, but
@ -6504,8 +6551,13 @@ rs6000_offsettable_memref_p (rtx op)
reference and, therefore, assumes that it is the largest supported
mode (TFmode). As a consequence, legitimate offsettable memory
references are rejected. rs6000_legitimate_offset_address_p contains
the correct logic for the PLUS case of rs6000_mode_dependent_address. */
return rs6000_legitimate_offset_address_p (GET_MODE (op), XEXP (op, 0), 1);
the correct logic for the PLUS case of rs6000_mode_dependent_address,
at least with a little bit of help here given that we know the
actual registers used. */
worst_case = ((TARGET_POWERPC64 && GET_MODE_CLASS (reg_mode) == MODE_INT)
|| GET_MODE_SIZE (reg_mode) == 4);
return rs6000_legitimate_offset_address_p (GET_MODE (op), XEXP (op, 0),
true, worst_case);
}
/* Change register usage conditional on target flags. */
@ -13516,7 +13568,8 @@ rs6000_secondary_reload (bool in_p,
if (rclass == GENERAL_REGS || rclass == BASE_REGS)
{
if (!legitimate_indirect_address_p (addr, false)
&& !rs6000_legitimate_offset_address_p (TImode, addr, false))
&& !rs6000_legitimate_offset_address_p (TImode, addr,
false, true))
{
sri->icode = icode;
/* account for splitting the loads, and converting the
@ -13589,18 +13642,9 @@ rs6000_secondary_reload (bool in_p,
&& MEM_P (x)
&& GET_MODE_SIZE (GET_MODE (x)) >= UNITS_PER_WORD)
{
rtx addr = XEXP (x, 0);
rtx off = address_offset (XEXP (x, 0));
if (GET_CODE (addr) == PRE_MODIFY)
addr = XEXP (addr, 1);
else if (GET_CODE (addr) == LO_SUM
&& GET_CODE (XEXP (addr, 0)) == REG
&& GET_CODE (XEXP (addr, 1)) == CONST)
addr = XEXP (XEXP (addr, 1), 0);
if (GET_CODE (addr) == PLUS
&& GET_CODE (XEXP (addr, 1)) == CONST_INT
&& (INTVAL (XEXP (addr, 1)) & 3) != 0)
if (off != NULL_RTX && (INTVAL (off) & 3) != 0)
{
if (in_p)
sri->icode = CODE_FOR_reload_di_load;
@ -13612,6 +13656,27 @@ rs6000_secondary_reload (bool in_p,
else
default_p = true;
}
else if (!TARGET_POWERPC64
&& rs6000_reload_register_type (rclass) == GPR_REGISTER_TYPE
&& MEM_P (x)
&& GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
{
rtx off = address_offset (XEXP (x, 0));
if (off != NULL_RTX
&& ((unsigned HOST_WIDE_INT) INTVAL (off) + 0x8000
>= 0x1000u - (GET_MODE_SIZE (GET_MODE (x)) - UNITS_PER_WORD)))
{
if (in_p)
sri->icode = CODE_FOR_reload_si_load;
else
sri->icode = CODE_FOR_reload_si_store;
sri->extra_cost = 2;
ret = NO_REGS;
}
else
default_p = true;
}
else
default_p = true;
@ -13700,8 +13765,9 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
}
if (GET_CODE (addr) == PLUS
&& (!rs6000_legitimate_offset_address_p (TImode, addr, false)
|| and_op2 != NULL_RTX))
&& (and_op2 != NULL_RTX
|| !rs6000_legitimate_offset_address_p (TImode, addr,
false, true)))
{
addr_op1 = XEXP (addr, 0);
addr_op2 = XEXP (addr, 1);
@ -13733,7 +13799,8 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
scratch_or_premodify = scratch;
}
else if (!legitimate_indirect_address_p (addr, false)
&& !rs6000_legitimate_offset_address_p (TImode, addr, false))
&& !rs6000_legitimate_offset_address_p (TImode, addr,
false, true))
{
if (TARGET_DEBUG_ADDR)
{
@ -13792,7 +13859,7 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
&& GET_MODE_SIZE (mode) == 8
&& and_op2 == NULL_RTX
&& scratch_or_premodify == scratch
&& rs6000_legitimate_offset_address_p (mode, addr, false)))
&& rs6000_legitimate_offset_address_p (mode, addr, false, false)))
;
else if (GET_CODE (addr) == PLUS)
@ -13901,10 +13968,11 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
}
/* Convert reloads involving 64-bit gprs and misaligned offset
addressing to use indirect addressing. */
addressing, or multiple 32-bit gprs and offsets that are too large,
to use indirect addressing. */
void
rs6000_secondary_reload_ppc64 (rtx reg, rtx mem, rtx scratch, bool store_p)
rs6000_secondary_reload_gpr (rtx reg, rtx mem, rtx scratch, bool store_p)
{
int regno = true_regnum (reg);
enum reg_class rclass;
@ -13913,7 +13981,7 @@ rs6000_secondary_reload_ppc64 (rtx reg, rtx mem, rtx scratch, bool store_p)
if (TARGET_DEBUG_ADDR)
{
fprintf (stderr, "\nrs6000_secondary_reload_ppc64, type = %s\n",
fprintf (stderr, "\nrs6000_secondary_reload_gpr, type = %s\n",
store_p ? "store" : "load");
fprintf (stderr, "reg:\n");
debug_rtx (reg);
@ -16993,7 +17061,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
emit_insn (gen_add3_insn (breg, breg, delta_rtx));
src = replace_equiv_address (src, breg);
}
else if (! rs6000_offsettable_memref_p (src))
else if (! rs6000_offsettable_memref_p (src, reg_mode))
{
if (GET_CODE (XEXP (src, 0)) == PRE_MODIFY)
{
@ -17059,7 +17127,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
emit_insn (gen_add3_insn (breg, breg, delta_rtx));
dst = replace_equiv_address (dst, breg);
}
else if (!rs6000_offsettable_memref_p (dst)
else if (!rs6000_offsettable_memref_p (dst, reg_mode)
&& GET_CODE (XEXP (dst, 0)) != LO_SUM)
{
if (GET_CODE (XEXP (dst, 0)) == PRE_MODIFY)
@ -17097,7 +17165,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
}
}
else if (GET_CODE (XEXP (dst, 0)) != LO_SUM)
gcc_assert (rs6000_offsettable_memref_p (dst));
gcc_assert (rs6000_offsettable_memref_p (dst, reg_mode));
}
for (i = 0; i < nregs; i++)
@ -27935,7 +28003,7 @@ rs6000_allocate_stack_temp (enum machine_mode mode,
if (!legitimate_indirect_address_p (addr, strict_p))
{
if (offsettable_p
&& !rs6000_legitimate_offset_address_p (mode, addr, strict_p))
&& !rs6000_legitimate_offset_address_p (mode, addr, strict_p, true))
stack = replace_equiv_address (stack, copy_addr_to_reg (addr));
else if (reg_reg_p && !legitimate_indexed_address_p (addr, strict_p))

View file

@ -9659,15 +9659,12 @@
#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.
;; Don't have reload use general registers to load a constant. It is
;; less efficient than loading the constant into an FP register, since
;; it will probably be used there.
(define_insn "*movdf_hardfloat32"
[(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,m,ws,?wa,ws,?wa,Z,?Z,d,d,m,wa,!r,!r,!r")
(match_operand:DF 1 "input_operand" "r,m,r,ws,wa,Z,Z,ws,wa,d,m,d,j,G,H,F"))]
[(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,ws,?wa,ws,?wa,Z,?Z,m,d,d,wa,!r,!r,!r")
(match_operand:DF 1 "input_operand" "r,Y,r,ws,wa,Z,Z,ws,wa,d,m,d,j,G,H,F"))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
&& (gpc_reg_operand (operands[0], DFmode)
|| gpc_reg_operand (operands[1], DFmode))"
@ -9691,11 +9688,11 @@
case 8:
return \"stxsd%U0x %x1,%y0\";
case 9:
return \"fmr %0,%1\";
return \"stfd%U0%X0 %1,%0\";
case 10:
return \"lfd%U1%X1 %0,%1\";
case 11:
return \"stfd%U0%X0 %1,%0\";
return \"fmr %0,%1\";
case 12:
return \"xxlxor %x0,%x0,%x0\";
case 13:
@ -9704,46 +9701,47 @@
return \"#\";
}
}"
[(set_attr "type" "two,load,store,fp,fp,fpload,fpload,fpstore,fpstore,fp,fpload,fpstore,vecsimple,*,*,*")
(set_attr "length" "8,16,16,4,4,4,4,4,4,4,4,4,4,8,12,16")])
[(set_attr "type" "store,load,two,fp,fp,fpload,fpload,fpstore,fpstore,fpstore,fpload,fp,vecsimple,*,*,*")
(set_attr "length" "8,8,8,4,4,4,4,4,4,4,4,4,4,8,12,16")])
(define_insn "*movdf_softfloat32"
[(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,r,r,r")
(match_operand:DF 1 "input_operand" "r,m,r,G,H,F"))]
[(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,r,r,r,r")
(match_operand:DF 1 "input_operand" "r,Y,r,G,H,F"))]
"! TARGET_POWERPC64
&& ((TARGET_FPRS && TARGET_SINGLE_FLOAT)
|| TARGET_SOFT_FLOAT || TARGET_E500_SINGLE)
&& (gpc_reg_operand (operands[0], DFmode)
|| gpc_reg_operand (operands[1], DFmode))"
"#"
[(set_attr "type" "two,load,store,*,*,*")
[(set_attr "type" "store,load,two,*,*,*")
(set_attr "length" "8,8,8,8,12,16")])
;; Reload patterns to support gpr load/store with misaligned mem.
(define_expand "reload_di_store"
;; and multiple gpr load/store at offset >= 0xfffc
(define_expand "reload_<mode>_store"
[(parallel [(match_operand 0 "memory_operand" "=m")
(match_operand 1 "gpc_reg_operand" "r")
(match_operand:DI 2 "register_operand" "=&b")])]
"TARGET_POWERPC64"
(match_operand:GPR 2 "register_operand" "=&b")])]
""
{
rs6000_secondary_reload_ppc64 (operands[1], operands[0], operands[2], true);
rs6000_secondary_reload_gpr (operands[1], operands[0], operands[2], true);
DONE;
})
(define_expand "reload_di_load"
(define_expand "reload_<mode>_load"
[(parallel [(match_operand 0 "gpc_reg_operand" "=r")
(match_operand 1 "memory_operand" "m")
(match_operand:DI 2 "register_operand" "=b")])]
"TARGET_POWERPC64"
(match_operand:GPR 2 "register_operand" "=b")])]
""
{
rs6000_secondary_reload_ppc64 (operands[0], operands[1], operands[2], false);
rs6000_secondary_reload_gpr (operands[0], operands[1], operands[2], false);
DONE;
})
; ld/std require word-aligned displacements -> 'Y' constraint.
; List Y->r and r->Y before r->r for reload.
(define_insn "*movdf_hardfloat64_mfpgpr"
[(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,ws,?wa,ws,?wa,Z,?Z,d,d,m,wa,*c*l,!r,*h,!r,!r,!r,r,d")
[(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,ws,?wa,ws,?wa,Z,?Z,m,d,d,wa,*c*l,!r,*h,!r,!r,!r,r,d")
(match_operand:DF 1 "input_operand" "r,Y,r,ws,?wa,Z,Z,ws,wa,d,m,d,j,r,h,0,G,H,F,d,r"))]
"TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
&& TARGET_DOUBLE_FLOAT
@ -9759,9 +9757,9 @@
lxsd%U1x %x0,%y1
stxsd%U0x %x1,%y0
stxsd%U0x %x1,%y0
fmr %0,%1
lfd%U1%X1 %0,%1
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
fmr %0,%1
xxlxor %x0,%x0,%x0
mt%0 %1
mf%1 %0
@ -9771,13 +9769,13 @@
#
mftgpr %0,%1
mffgpr %0,%1"
[(set_attr "type" "store,load,*,fp,fp,fpload,fpload,fpstore,fpstore,fp,fpload,fpstore,vecsimple,mtjmpr,mfjmpr,*,*,*,*,mftgpr,mffgpr")
[(set_attr "type" "store,load,*,fp,fp,fpload,fpload,fpstore,fpstore,fpstore,fpload,fp,vecsimple,mtjmpr,mfjmpr,*,*,*,*,mftgpr,mffgpr")
(set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,8,12,16,4,4")])
; ld/std require word-aligned displacements -> 'Y' constraint.
; List Y->r and r->Y before r->r for reload.
(define_insn "*movdf_hardfloat64"
[(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,ws,?wa,ws,?wa,Z,?Z,d,d,m,wa,*c*l,!r,*h,!r,!r,!r")
[(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,ws,?wa,ws,?wa,Z,?Z,m,d,d,wa,*c*l,!r,*h,!r,!r,!r")
(match_operand:DF 1 "input_operand" "r,Y,r,ws,wa,Z,Z,ws,wa,d,m,d,j,r,h,0,G,H,F"))]
"TARGET_POWERPC64 && !TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
&& TARGET_DOUBLE_FLOAT
@ -9793,9 +9791,9 @@
lxsd%U1x %x0,%y1
stxsd%U0x %x1,%y0
stxsd%U0x %x1,%y0
fmr %0,%1
lfd%U1%X1 %0,%1
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
fmr %0,%1
xxlxor %x0,%x0,%x0
mt%0 %1
mf%1 %0
@ -9803,18 +9801,18 @@
#
#
#"
[(set_attr "type" "store,load,*,fp,fp,fpload,fpload,fpstore,fpstore,fp,fpload,fpstore,vecsimple,mtjmpr,mfjmpr,*,*,*,*")
[(set_attr "type" "store,load,*,fp,fp,fpload,fpload,fpstore,fpstore,fpstore,fpload,fp,vecsimple,mtjmpr,mfjmpr,*,*,*,*")
(set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,8,12,16")])
(define_insn "*movdf_softfloat64"
[(set (match_operand:DF 0 "nonimmediate_operand" "=r,Y,r,cl,r,r,r,r,*h")
(match_operand:DF 1 "input_operand" "Y,r,r,r,h,G,H,F,0"))]
[(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,r,cl,r,r,r,r,*h")
(match_operand:DF 1 "input_operand" "r,Y,r,r,h,G,H,F,0"))]
"TARGET_POWERPC64 && (TARGET_SOFT_FLOAT || !TARGET_FPRS)
&& (gpc_reg_operand (operands[0], DFmode)
|| gpc_reg_operand (operands[1], DFmode))"
"@
ld%U1%X1 %0,%1
std%U0%X0 %1,%0
ld%U1%X1 %0,%1
mr %0,%1
mt%0 %1
mf%1 %0
@ -9822,7 +9820,7 @@
#
#
{cror 0,0,0|nop}"
[(set_attr "type" "load,store,*,mtjmpr,mfjmpr,*,*,*,*")
[(set_attr "type" "store,load,*,mtjmpr,mfjmpr,*,*,*,*")
(set_attr "length" "4,4,4,4,4,8,12,16,4")])
(define_expand "movtf"
@ -9831,12 +9829,12 @@
"!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
"{ rs6000_emit_move (operands[0], operands[1], TFmode); 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.
;; It's important to list Y->r and r->Y before r->r because otherwise
;; reload, given m->r, will try to pick r->r and reload it, which
;; doesn't make progress.
(define_insn_and_split "*movtf_internal"
[(set (match_operand:TF 0 "nonimmediate_operand" "=o,d,d,r,Y,r")
(match_operand:TF 1 "input_operand" "d,o,d,YGHF,r,r"))]
[(set (match_operand:TF 0 "nonimmediate_operand" "=m,d,d,Y,r,r")
(match_operand:TF 1 "input_operand" "d,m,d,r,YGHF,r"))]
"!TARGET_IEEEQUAD
&& TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128
&& (gpc_reg_operand (operands[0], TFmode)
@ -9848,8 +9846,8 @@
[(set_attr "length" "8,8,8,20,20,16")])
(define_insn_and_split "*movtf_softfloat"
[(set (match_operand:TF 0 "rs6000_nonimmediate_operand" "=r,Y,r")
(match_operand:TF 1 "input_operand" "YGHF,r,r"))]
[(set (match_operand:TF 0 "rs6000_nonimmediate_operand" "=Y,r,r")
(match_operand:TF 1 "input_operand" "r,YGHF,r"))]
"!TARGET_IEEEQUAD
&& (TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_LONG_DOUBLE_128
&& (gpc_reg_operand (operands[0], TFmode)
@ -9890,9 +9888,9 @@
})
(define_insn_and_split "*extenddftf2_internal"
[(set (match_operand:TF 0 "nonimmediate_operand" "=o,d,&d,r")
(float_extend:TF (match_operand:DF 1 "input_operand" "dr,md,md,rmGHF")))
(use (match_operand:DF 2 "zero_reg_mem_operand" "rd,m,d,n"))]
[(set (match_operand:TF 0 "nonimmediate_operand" "=m,Y,d,&d,r")
(float_extend:TF (match_operand:DF 1 "input_operand" "d,r,md,md,rmGHF")))
(use (match_operand:DF 2 "zero_reg_mem_operand" "d,r,m,d,n"))]
"!TARGET_IEEEQUAD
&& TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
&& TARGET_LONG_DOUBLE_128"
@ -10145,11 +10143,13 @@
;; Next come the multi-word integer load and store and the load and store
;; multiple insns.
; List r->r after r->"o<>", otherwise reload will try to reload a
; non-offsettable address by using r->r which won't make progress.
;; List r->r after r->Y, otherwise reload will try to reload a
;; non-offsettable address by using r->r which won't make progress.
;; Use of fprs is disparaged slightly otherwise reload prefers to reload
;; a gpr into a fpr instead of reloading an invalid 'Y' address
(define_insn "*movdi_internal32"
[(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "=o<>,r,r,*d,*d,m,r,?wa")
(match_operand:DI 1 "input_operand" "r,r,m,d,m,d,IJKnGHF,O"))]
[(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "=Y,r,r,?m,?*d,?*d,r,?wa")
(match_operand:DI 1 "input_operand" "r,Y,r,d,m,d,IJKnGHF,O"))]
"! TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
@ -10157,12 +10157,12 @@
#
#
#
fmr %0,%1
lfd%U1%X1 %0,%1
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
fmr %0,%1
#
xxlxor %x0,%x0,%x0"
[(set_attr "type" "load,*,store,fp,fpload,fpstore,*,vecsimple")])
[(set_attr "type" "store,load,*,fpstore,fpload,fp,*,vecsimple")])
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
@ -10195,50 +10195,50 @@
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
(define_insn "*movdi_mfpgpr"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,*d,*d,m,r,*h,*h,r,*d")
(match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,d,m,d,*h,r,0,*d,r"))]
[(set (match_operand:DI 0 "nonimmediate_operand" "=Y,r,r,r,r,r,?m,?*d,?*d,r,*h,*h,r,?*d")
(match_operand:DI 1 "input_operand" "r,Y,r,I,L,nF,d,m,d,*h,r,0,*d,r"))]
"TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
"@
mr %0,%1
ld%U1%X1 %0,%1
std%U0%X0 %1,%0
ld%U1%X1 %0,%1
mr %0,%1
li %0,%1
lis %0,%v1
#
fmr %0,%1
lfd%U1%X1 %0,%1
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
fmr %0,%1
mf%1 %0
mt%0 %1
{cror 0,0,0|nop}
mftgpr %0,%1
mffgpr %0,%1"
[(set_attr "type" "*,load,store,*,*,*,fp,fpload,fpstore,mfjmpr,mtjmpr,*,mftgpr,mffgpr")
[(set_attr "type" "store,load,*,*,*,*,fpstore,fpload,fp,mfjmpr,mtjmpr,*,mftgpr,mffgpr")
(set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4")])
(define_insn "*movdi_internal64"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,*d,*d,m,r,*h,*h,?wa")
(match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,d,m,d,*h,r,0,O"))]
[(set (match_operand:DI 0 "nonimmediate_operand" "=Y,r,r,r,r,r,?m,?*d,?*d,r,*h,*h,?wa")
(match_operand:DI 1 "input_operand" "r,Y,r,I,L,nF,d,m,d,*h,r,0,O"))]
"TARGET_POWERPC64 && (!TARGET_MFPGPR || !TARGET_HARD_FLOAT || !TARGET_FPRS)
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
"@
mr %0,%1
ld%U1%X1 %0,%1
std%U0%X0 %1,%0
ld%U1%X1 %0,%1
mr %0,%1
li %0,%1
lis %0,%v1
#
fmr %0,%1
lfd%U1%X1 %0,%1
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
fmr %0,%1
mf%1 %0
mt%0 %1
{cror 0,0,0|nop}
xxlxor %x0,%x0,%x0"
[(set_attr "type" "*,load,store,*,*,*,fp,fpload,fpstore,mfjmpr,mtjmpr,*,vecsimple")
[(set_attr "type" "store,load,*,*,*,*,fpstore,fpload,fp,mfjmpr,mtjmpr,*,vecsimple")
(set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4")])
;; immediate value valid for a single instruction hiding in a const_double
@ -10313,8 +10313,8 @@
;; giving the SCRATCH mq.
(define_insn "*movti_power"
[(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r,r")
(match_operand:TI 1 "input_operand" "r,r,r,Q,m,n"))
[(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,Y,????r,????r,????r,r")
(match_operand:TI 1 "input_operand" "r,r,Q,Y,r,n"))
(clobber (match_scratch:SI 2 "=q,q#X,X,X,X,X"))]
"TARGET_POWER && ! TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
@ -10329,25 +10329,25 @@
if (TARGET_STRING)
return \"{stsi|stswi} %1,%P0,16\";
case 1:
case 2:
return \"#\";
case 3:
case 2:
/* If the address is not used in the output, we can use lsi. Otherwise,
fall through to generating four loads. */
if (TARGET_STRING
&& ! reg_overlap_mentioned_p (operands[0], operands[1]))
return \"{lsi|lswi} %0,%P1,16\";
/* ... fall through ... */
case 3:
case 4:
case 5:
return \"#\";
}
}"
[(set_attr "type" "store,store,*,load,load,*")])
[(set_attr "type" "store,store,load,load,*,*")])
(define_insn "*movti_string"
[(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,o<>,????r,????r,????r,r")
(match_operand:TI 1 "input_operand" "r,r,r,Q,m,n"))]
[(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,Y,????r,????r,????r,r")
(match_operand:TI 1 "input_operand" "r,r,Q,Y,r,n"))]
"! TARGET_POWER && ! TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
"*
@ -10360,33 +10360,33 @@
if (TARGET_STRING)
return \"{stsi|stswi} %1,%P0,16\";
case 1:
case 2:
return \"#\";
case 3:
case 2:
/* If the address is not used in the output, we can use lsi. Otherwise,
fall through to generating four loads. */
if (TARGET_STRING
&& ! reg_overlap_mentioned_p (operands[0], operands[1]))
return \"{lsi|lswi} %0,%P1,16\";
/* ... fall through ... */
case 3:
case 4:
case 5:
return \"#\";
}
}"
[(set_attr "type" "store_ux,store_ux,*,load_ux,load_ux,*")
[(set_attr "type" "store_ux,store_ux,load_ux,load_ux,*,*")
(set (attr "cell_micro") (if_then_else (match_test "TARGET_STRING")
(const_string "always")
(const_string "conditional")))])
(define_insn "*movti_ppc64"
[(set (match_operand:TI 0 "nonimmediate_operand" "=r,o<>,r")
(match_operand:TI 1 "input_operand" "r,r,m"))]
[(set (match_operand:TI 0 "nonimmediate_operand" "=Y,r,r")
(match_operand:TI 1 "input_operand" "r,Y,r"))]
"(TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
|| gpc_reg_operand (operands[1], TImode)))
&& VECTOR_MEM_NONE_P (TImode)"
"#"
[(set_attr "type" "*,store,load")])
[(set_attr "type" "store,load,*")])
(define_split
[(set (match_operand:TI 0 "gpc_reg_operand" "")
@ -13215,8 +13215,8 @@
(set_attr "length" "12")])
(define_insn "stack_protect_setdi"
[(set (match_operand:DI 0 "memory_operand" "=m")
(unspec:DI [(match_operand:DI 1 "memory_operand" "m")] UNSPEC_SP_SET))
[(set (match_operand:DI 0 "memory_operand" "=Y")
(unspec:DI [(match_operand:DI 1 "memory_operand" "Y")] UNSPEC_SP_SET))
(set (match_scratch:DI 2 "=&r") (const_int 0))]
"TARGET_64BIT"
"ld%U1%X1 %2,%1\;std%U0%X0 %2,%0\;{lil|li} %2,0"
@ -13257,8 +13257,8 @@
(define_insn "stack_protect_testdi"
[(set (match_operand:CCEQ 0 "cc_reg_operand" "=x,?y")
(unspec:CCEQ [(match_operand:DI 1 "memory_operand" "m,m")
(match_operand:DI 2 "memory_operand" "m,m")]
(unspec:CCEQ [(match_operand:DI 1 "memory_operand" "Y,Y")
(match_operand:DI 2 "memory_operand" "Y,Y")]
UNSPEC_SP_TEST))
(set (match_scratch:DI 4 "=r,r") (const_int 0))
(clobber (match_scratch:DI 3 "=&r,&r"))]