gcc/gcc44-power7-2.patch

268 lines
9.1 KiB
Diff
Raw Normal View History

2009-05-14 08:52:31 +00:00
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;