268 lines
9.1 KiB
Diff
268 lines
9.1 KiB
Diff
|
2009-04-14 Michael Meissner <meissner@linux.vnet.ibm.com>
|
|||
|
|
|||
|
* config/rs6000/rs6000.c (rs6000_secondary_reload_inner): Handle
|
|||
|
more possible combinations of addresses.
|
|||
|
|
|||
|
* config/rs6000/vector.md (vec_reload_and_plus_<mptrsize>): Allow
|
|||
|
register+small constant in addition to register+register, and
|
|||
|
restrict the insn to only match during reload and afterwards.
|
|||
|
(vec_reload_and_reg_<mptrsize>): Allow for and of register
|
|||
|
indirect to not generate insn not found message.
|
|||
|
|
|||
|
--- gcc/config/rs6000/vector.md (revision 146069)
|
|||
|
+++ gcc/config/rs6000/vector.md (revision 146118)
|
|||
|
@@ -129,14 +129,15 @@ (define_expand "reload_<VEC_R:mode>_<P:m
|
|||
|
})
|
|||
|
|
|||
|
;; Reload sometimes tries to move the address to a GPR, and can generate
|
|||
|
-;; invalid RTL for addresses involving AND -16.
|
|||
|
+;; invalid RTL for addresses involving AND -16. Allow addresses involving
|
|||
|
+;; reg+reg, reg+small constant, or just reg, all wrapped in an AND -16.
|
|||
|
|
|||
|
(define_insn_and_split "*vec_reload_and_plus_<mptrsize>"
|
|||
|
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
|
|||
|
(and:P (plus:P (match_operand:P 1 "gpc_reg_operand" "r")
|
|||
|
- (match_operand:P 2 "gpc_reg_operand" "r"))
|
|||
|
+ (match_operand:P 2 "reg_or_cint_operand" "rI"))
|
|||
|
(const_int -16)))]
|
|||
|
- "TARGET_ALTIVEC || TARGET_VSX"
|
|||
|
+ "(TARGET_ALTIVEC || TARGET_VSX) && (reload_in_progress || reload_completed)"
|
|||
|
"#"
|
|||
|
"&& reload_completed"
|
|||
|
[(set (match_dup 0)
|
|||
|
@@ -146,6 +147,21 @@ (define_insn_and_split "*vec_reload_and_
|
|||
|
(and:P (match_dup 0)
|
|||
|
(const_int -16)))
|
|||
|
(clobber:CC (scratch:CC))])])
|
|||
|
+
|
|||
|
+;; The normal ANDSI3/ANDDI3 won't match if reload decides to move an AND -16
|
|||
|
+;; address to a register because there is no clobber of a (scratch), so we add
|
|||
|
+;; it here.
|
|||
|
+(define_insn_and_split "*vec_reload_and_reg_<mptrsize>"
|
|||
|
+ [(set (match_operand:P 0 "gpc_reg_operand" "=b")
|
|||
|
+ (and:P (match_operand:P 1 "gpc_reg_operand" "r")
|
|||
|
+ (const_int -16)))]
|
|||
|
+ "(TARGET_ALTIVEC || TARGET_VSX) && (reload_in_progress || reload_completed)"
|
|||
|
+ "#"
|
|||
|
+ "&& reload_completed"
|
|||
|
+ [(parallel [(set (match_dup 0)
|
|||
|
+ (and:P (match_dup 1)
|
|||
|
+ (const_int -16)))
|
|||
|
+ (clobber:CC (scratch:CC))])])
|
|||
|
|
|||
|
;; Generic floating point vector arithmetic support
|
|||
|
(define_expand "add<mode>3"
|
|||
|
--- gcc/config/rs6000/rs6000.c (revision 146069)
|
|||
|
+++ gcc/config/rs6000/rs6000.c (revision 146118)
|
|||
|
@@ -12574,6 +12574,11 @@ rs6000_secondary_reload_inner (rtx reg,
|
|||
|
enum reg_class rclass;
|
|||
|
rtx addr;
|
|||
|
rtx and_op2 = NULL_RTX;
|
|||
|
+ rtx addr_op1;
|
|||
|
+ rtx addr_op2;
|
|||
|
+ rtx scratch_or_premodify = scratch;
|
|||
|
+ rtx and_rtx;
|
|||
|
+ rtx cc_clobber;
|
|||
|
|
|||
|
if (TARGET_DEBUG_ADDR)
|
|||
|
{
|
|||
|
@@ -12595,7 +12600,8 @@ rs6000_secondary_reload_inner (rtx reg,
|
|||
|
|
|||
|
switch (rclass)
|
|||
|
{
|
|||
|
- /* Move reg+reg addresses into a scratch register for GPRs. */
|
|||
|
+ /* GPRs can handle reg + small constant, all other addresses need to use
|
|||
|
+ the scratch register. */
|
|||
|
case GENERAL_REGS:
|
|||
|
case BASE_REGS:
|
|||
|
if (GET_CODE (addr) == AND)
|
|||
|
@@ -12603,70 +12609,152 @@ rs6000_secondary_reload_inner (rtx reg,
|
|||
|
and_op2 = XEXP (addr, 1);
|
|||
|
addr = XEXP (addr, 0);
|
|||
|
}
|
|||
|
+
|
|||
|
+ if (GET_CODE (addr) == PRE_MODIFY)
|
|||
|
+ {
|
|||
|
+ scratch_or_premodify = XEXP (addr, 0);
|
|||
|
+ gcc_assert (REG_P (scratch_or_premodify));
|
|||
|
+ gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
|
|||
|
+ addr = XEXP (addr, 1);
|
|||
|
+ }
|
|||
|
+
|
|||
|
if (GET_CODE (addr) == PLUS
|
|||
|
&& (!rs6000_legitimate_offset_address_p (TImode, addr, true)
|
|||
|
|| and_op2 != NULL_RTX))
|
|||
|
{
|
|||
|
- if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == CONST
|
|||
|
- || GET_CODE (addr) == CONST_INT)
|
|||
|
- rs6000_emit_move (scratch, addr, GET_MODE (addr));
|
|||
|
- else
|
|||
|
- emit_insn (gen_rtx_SET (VOIDmode, scratch, addr));
|
|||
|
- addr = scratch;
|
|||
|
+ addr_op1 = XEXP (addr, 0);
|
|||
|
+ addr_op2 = XEXP (addr, 1);
|
|||
|
+ gcc_assert (legitimate_indirect_address_p (addr_op1, true));
|
|||
|
+
|
|||
|
+ if (!REG_P (addr_op2)
|
|||
|
+ && (GET_CODE (addr_op2) != CONST_INT
|
|||
|
+ || !satisfies_constraint_I (addr_op2)))
|
|||
|
+ {
|
|||
|
+ rs6000_emit_move (scratch, addr_op2, Pmode);
|
|||
|
+ addr_op2 = scratch;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ emit_insn (gen_rtx_SET (VOIDmode,
|
|||
|
+ scratch_or_premodify,
|
|||
|
+ gen_rtx_PLUS (Pmode,
|
|||
|
+ addr_op1,
|
|||
|
+ addr_op2)));
|
|||
|
+
|
|||
|
+ addr = scratch_or_premodify;
|
|||
|
+ scratch_or_premodify = scratch;
|
|||
|
}
|
|||
|
- else if (GET_CODE (addr) == PRE_MODIFY
|
|||
|
- && REG_P (XEXP (addr, 0))
|
|||
|
- && GET_CODE (XEXP (addr, 1)) == PLUS)
|
|||
|
+ else if (!legitimate_indirect_address_p (addr, true)
|
|||
|
+ && !rs6000_legitimate_offset_address_p (TImode, addr, true))
|
|||
|
{
|
|||
|
- emit_insn (gen_rtx_SET (VOIDmode, XEXP (addr, 0), XEXP (addr, 1)));
|
|||
|
- addr = XEXP (addr, 0);
|
|||
|
+ rs6000_emit_move (scratch_or_premodify, addr, Pmode);
|
|||
|
+ addr = scratch_or_premodify;
|
|||
|
+ scratch_or_premodify = scratch;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
+ /* Float/Altivec registers can only handle reg+reg addressing. Move
|
|||
|
+ other addresses into a scratch register. */
|
|||
|
+ case FLOAT_REGS:
|
|||
|
+ case VSX_REGS:
|
|||
|
+ case ALTIVEC_REGS:
|
|||
|
+
|
|||
|
/* With float regs, we need to handle the AND ourselves, since we can't
|
|||
|
use the Altivec instruction with an implicit AND -16. Allow scalar
|
|||
|
loads to float registers to use reg+offset even if VSX. */
|
|||
|
- case FLOAT_REGS:
|
|||
|
- case VSX_REGS:
|
|||
|
- if (GET_CODE (addr) == AND)
|
|||
|
+ if (GET_CODE (addr) == AND
|
|||
|
+ && (rclass != ALTIVEC_REGS || GET_MODE_SIZE (mode) != 16))
|
|||
|
{
|
|||
|
and_op2 = XEXP (addr, 1);
|
|||
|
addr = XEXP (addr, 0);
|
|||
|
}
|
|||
|
- /* fall through */
|
|||
|
|
|||
|
- /* Move reg+offset addresses into a scratch register. */
|
|||
|
- case ALTIVEC_REGS:
|
|||
|
- if (!legitimate_indirect_address_p (addr, true)
|
|||
|
- && !legitimate_indexed_address_p (addr, true)
|
|||
|
- && (GET_CODE (addr) != PRE_MODIFY
|
|||
|
- || !legitimate_indexed_address_p (XEXP (addr, 1), true))
|
|||
|
- && (rclass != FLOAT_REGS
|
|||
|
- || GET_MODE_SIZE (mode) != 8
|
|||
|
+ /* If we aren't using a VSX load, save the PRE_MODIFY register and use it
|
|||
|
+ as the address later. */
|
|||
|
+ if (GET_CODE (addr) == PRE_MODIFY
|
|||
|
+ && (!VECTOR_MEM_VSX_P (mode)
|
|||
|
|| and_op2 != NULL_RTX
|
|||
|
- || !rs6000_legitimate_offset_address_p (mode, addr, true)))
|
|||
|
+ || !legitimate_indexed_address_p (XEXP (addr, 1), true)))
|
|||
|
{
|
|||
|
- if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == CONST
|
|||
|
- || GET_CODE (addr) == CONST_INT)
|
|||
|
- rs6000_emit_move (scratch, addr, GET_MODE (addr));
|
|||
|
- else
|
|||
|
- emit_insn (gen_rtx_SET (VOIDmode, scratch, addr));
|
|||
|
- addr = scratch;
|
|||
|
+ scratch_or_premodify = XEXP (addr, 0);
|
|||
|
+ gcc_assert (legitimate_indirect_address_p (scratch_or_premodify,
|
|||
|
+ true));
|
|||
|
+ gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
|
|||
|
+ addr = XEXP (addr, 1);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (legitimate_indirect_address_p (addr, true) /* reg */
|
|||
|
+ || legitimate_indexed_address_p (addr, true) /* reg+reg */
|
|||
|
+ || GET_CODE (addr) == PRE_MODIFY /* VSX pre-modify */
|
|||
|
+ || GET_CODE (addr) == AND /* Altivec memory */
|
|||
|
+ || (rclass == FLOAT_REGS /* legacy float mem */
|
|||
|
+ && GET_MODE_SIZE (mode) == 8
|
|||
|
+ && and_op2 == NULL_RTX
|
|||
|
+ && scratch_or_premodify == scratch
|
|||
|
+ && rs6000_legitimate_offset_address_p (mode, addr, true)))
|
|||
|
+ ;
|
|||
|
+
|
|||
|
+ else if (GET_CODE (addr) == PLUS)
|
|||
|
+ {
|
|||
|
+ addr_op1 = XEXP (addr, 0);
|
|||
|
+ addr_op2 = XEXP (addr, 1);
|
|||
|
+ gcc_assert (REG_P (addr_op1));
|
|||
|
+
|
|||
|
+ rs6000_emit_move (scratch, addr_op2, Pmode);
|
|||
|
+ emit_insn (gen_rtx_SET (VOIDmode,
|
|||
|
+ scratch_or_premodify,
|
|||
|
+ gen_rtx_PLUS (Pmode,
|
|||
|
+ addr_op1,
|
|||
|
+ scratch)));
|
|||
|
+ addr = scratch_or_premodify;
|
|||
|
+ scratch_or_premodify = scratch;
|
|||
|
}
|
|||
|
+
|
|||
|
+ else if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == CONST
|
|||
|
+ || GET_CODE (addr) == CONST_INT)
|
|||
|
+ {
|
|||
|
+ rs6000_emit_move (scratch_or_premodify, addr, Pmode);
|
|||
|
+ addr = scratch_or_premodify;
|
|||
|
+ scratch_or_premodify = scratch;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ else
|
|||
|
+ gcc_unreachable ();
|
|||
|
+
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
|
|||
|
- /* If the original address involved an AND -16 that is part of the Altivec
|
|||
|
- addresses, recreate the and now. */
|
|||
|
+ /* If the original address involved a pre-modify that we couldn't use the VSX
|
|||
|
+ memory instruction with update, and we haven't taken care of already,
|
|||
|
+ store the address in the pre-modify register and use that as the
|
|||
|
+ address. */
|
|||
|
+ if (scratch_or_premodify != scratch && scratch_or_premodify != addr)
|
|||
|
+ {
|
|||
|
+ emit_insn (gen_rtx_SET (VOIDmode, scratch_or_premodify, addr));
|
|||
|
+ addr = scratch_or_premodify;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ /* If the original address involved an AND -16 and we couldn't use an ALTIVEC
|
|||
|
+ memory instruction, recreate the AND now, including the clobber which is
|
|||
|
+ generated by the general ANDSI3/ANDDI3 patterns for the
|
|||
|
+ andi. instruction. */
|
|||
|
if (and_op2 != NULL_RTX)
|
|||
|
{
|
|||
|
- rtx and_rtx = gen_rtx_SET (VOIDmode,
|
|||
|
- scratch,
|
|||
|
- gen_rtx_AND (Pmode, addr, and_op2));
|
|||
|
- rtx cc_clobber = gen_rtx_CLOBBER (CCmode, gen_rtx_SCRATCH (CCmode));
|
|||
|
+ if (! legitimate_indirect_address_p (addr, true))
|
|||
|
+ {
|
|||
|
+ emit_insn (gen_rtx_SET (VOIDmode, scratch, addr));
|
|||
|
+ addr = scratch;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ and_rtx = gen_rtx_SET (VOIDmode,
|
|||
|
+ scratch,
|
|||
|
+ gen_rtx_AND (Pmode,
|
|||
|
+ addr,
|
|||
|
+ and_op2));
|
|||
|
+
|
|||
|
+ cc_clobber = gen_rtx_CLOBBER (CCmode, gen_rtx_SCRATCH (CCmode));
|
|||
|
emit_insn (gen_rtx_PARALLEL (VOIDmode,
|
|||
|
gen_rtvec (2, and_rtx, cc_clobber)));
|
|||
|
addr = scratch;
|