This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[RFC] PowerPC TImode splitters
- From: David Edelsohn <dje at watson dot ibm dot com>
- To: Geoff Keating <geoffk at geoffk dot org>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Sat, 20 Sep 2003 23:15:14 -0400
- Subject: [RFC] PowerPC TImode splitters
Hatmut Penner and I have expanded the splitters for vector values
in GPRs to handle TImode and 32-bit DImode.
Previously TImode only was enabled when the POWER/PowerPC "string"
helper instructions were available for loading and storing multiple
registers. This patch enables TImode uniformly. I'm not sure if TImode
should have the restriction or not. I am not going to commit this patch
immediately so that I can see if there are any comments first.
David
* config/rs6000/rs6000.c (altivec_in_gprs_p): Rename to ...
(gpr_or_gpr_p): Change to bool.
(rs6000_split_altivec_in_gprs): Rename to ...
(rs6000_split_multireg_move): Add support for update addressing.
* config/rs6000/rs6000-protos.h: Same.
* config/rs6000/altivec.md: Same.
* config/rs6000/rs6000.md (movdi_internal32): Use new splitter for
multiple GPRs.
(movti): Remove TARGET_STRING || TARGET_POWERPC64 final condition.
(movti_power): Use new splitter for multiple GPRs.
(movti_string): Same.
(movti_ppc64): Same.
Index: altivec.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/altivec.md,v
retrieving revision 1.8
diff -c -p -r1.8 altivec.md
*** altivec.md 30 Jun 2003 13:30:45 -0000 1.8
--- altivec.md 20 Sep 2003 21:22:57 -0000
***************
*** 114,137 ****
[(set (match_operand:V4SI 0 "nonimmediate_operand" "")
(match_operand:V4SI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
! && altivec_in_gprs_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"{
! rs6000_split_altivec_in_gprs (operands);
}")
(define_split
[(set (match_operand:V4SI 0 "nonimmediate_operand" "")
(match_operand:V4SI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
! && altivec_in_gprs_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 6))
(set (match_dup 3) (match_dup 7))
(set (match_dup 4) (match_dup 8))
(set (match_dup 5) (match_dup 9))]
"{
! rs6000_split_altivec_in_gprs (operands);
}")
(define_split
--- 114,137 ----
[(set (match_operand:V4SI 0 "nonimmediate_operand" "")
(match_operand:V4SI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
! && gpr_or_gpr_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"{
! rs6000_split_multireg_move (operands);
}")
(define_split
[(set (match_operand:V4SI 0 "nonimmediate_operand" "")
(match_operand:V4SI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
! && gpr_or_gpr_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 6))
(set (match_dup 3) (match_dup 7))
(set (match_dup 4) (match_dup 8))
(set (match_dup 5) (match_dup 9))]
"{
! rs6000_split_multireg_move (operands);
}")
(define_split
***************
*** 176,199 ****
[(set (match_operand:V8HI 0 "nonimmediate_operand" "")
(match_operand:V8HI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
! && altivec_in_gprs_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"{
! rs6000_split_altivec_in_gprs (operands);
}")
(define_split
[(set (match_operand:V8HI 0 "nonimmediate_operand" "")
(match_operand:V8HI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
! && altivec_in_gprs_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 6))
(set (match_dup 3) (match_dup 7))
(set (match_dup 4) (match_dup 8))
(set (match_dup 5) (match_dup 9))]
"{
! rs6000_split_altivec_in_gprs (operands);
}")
(define_split
--- 176,199 ----
[(set (match_operand:V8HI 0 "nonimmediate_operand" "")
(match_operand:V8HI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
! && gpr_or_gpr_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"{
! rs6000_split_multireg_move (operands);
}")
(define_split
[(set (match_operand:V8HI 0 "nonimmediate_operand" "")
(match_operand:V8HI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
! && gpr_or_gpr_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 6))
(set (match_dup 3) (match_dup 7))
(set (match_dup 4) (match_dup 8))
(set (match_dup 5) (match_dup 9))]
"{
! rs6000_split_multireg_move (operands);
}")
(define_split
***************
*** 238,261 ****
[(set (match_operand:V16QI 0 "nonimmediate_operand" "")
(match_operand:V16QI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
! && altivec_in_gprs_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"{
! rs6000_split_altivec_in_gprs (operands);
}")
(define_split
[(set (match_operand:V16QI 0 "nonimmediate_operand" "")
(match_operand:V16QI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
! && altivec_in_gprs_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 6))
(set (match_dup 3) (match_dup 7))
(set (match_dup 4) (match_dup 8))
(set (match_dup 5) (match_dup 9))]
"{
! rs6000_split_altivec_in_gprs (operands);
}")
(define_split
--- 238,261 ----
[(set (match_operand:V16QI 0 "nonimmediate_operand" "")
(match_operand:V16QI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
! && gpr_or_gpr_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"{
! rs6000_split_multireg_move (operands);
}")
(define_split
[(set (match_operand:V16QI 0 "nonimmediate_operand" "")
(match_operand:V16QI 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
! && gpr_or_gpr_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 6))
(set (match_dup 3) (match_dup 7))
(set (match_dup 4) (match_dup 8))
(set (match_dup 5) (match_dup 9))]
"{
! rs6000_split_multireg_move (operands);
}")
(define_split
***************
*** 300,323 ****
[(set (match_operand:V4SF 0 "nonimmediate_operand" "")
(match_operand:V4SF 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
! && altivec_in_gprs_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"{
! rs6000_split_altivec_in_gprs (operands);
}")
(define_split
[(set (match_operand:V4SF 0 "nonimmediate_operand" "")
(match_operand:V4SF 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
! && altivec_in_gprs_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 6))
(set (match_dup 3) (match_dup 7))
(set (match_dup 4) (match_dup 8))
(set (match_dup 5) (match_dup 9))]
"{
! rs6000_split_altivec_in_gprs (operands);
}")
(define_insn "get_vrsave_internal"
--- 300,323 ----
[(set (match_operand:V4SF 0 "nonimmediate_operand" "")
(match_operand:V4SF 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64
! && gpr_or_gpr_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"{
! rs6000_split_multireg_move (operands);
}")
(define_split
[(set (match_operand:V4SF 0 "nonimmediate_operand" "")
(match_operand:V4SF 1 "input_operand" ""))]
"TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64
! && gpr_or_gpr_p (operands[0], operands[1])"
[(set (match_dup 2) (match_dup 6))
(set (match_dup 3) (match_dup 7))
(set (match_dup 4) (match_dup 8))
(set (match_dup 5) (match_dup 9))]
"{
! rs6000_split_multireg_move (operands);
}")
(define_insn "get_vrsave_internal"
Index: rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.62
diff -c -p -r1.62 rs6000-protos.h
*** rs6000-protos.h 12 Sep 2003 19:00:45 -0000 1.62
--- rs6000-protos.h 20 Sep 2003 21:22:57 -0000
*************** extern int includes_rldic_lshift_p (rtx,
*** 100,115 ****
extern int includes_rldicr_lshift_p (rtx, rtx);
extern int registers_ok_for_quad_peep (rtx, rtx);
extern int addrs_ok_for_quad_peep (rtx, rtx);
! extern int altivec_in_gprs_p (rtx, rtx);
extern enum reg_class secondary_reload_class (enum reg_class,
! enum machine_mode, rtx);
extern int ccr_bit (rtx, int);
extern int extract_MB (rtx);
extern int extract_ME (rtx);
extern void print_operand (FILE *, rtx, int);
extern void print_operand_address (FILE *, rtx);
extern enum rtx_code rs6000_reverse_condition (enum machine_mode,
! enum rtx_code);
extern void rs6000_emit_sCOND (enum rtx_code, rtx);
extern void rs6000_emit_cbranch (enum rtx_code, rtx);
extern char * output_cbranch (rtx, const char *, int, rtx);
--- 100,115 ----
extern int includes_rldicr_lshift_p (rtx, rtx);
extern int registers_ok_for_quad_peep (rtx, rtx);
extern int addrs_ok_for_quad_peep (rtx, rtx);
! extern bool gpr_or_gpr_p (rtx, rtx);
extern enum reg_class secondary_reload_class (enum reg_class,
! enum machine_mode, rtx);
extern int ccr_bit (rtx, int);
extern int extract_MB (rtx);
extern int extract_ME (rtx);
extern void print_operand (FILE *, rtx, int);
extern void print_operand_address (FILE *, rtx);
extern enum rtx_code rs6000_reverse_condition (enum machine_mode,
! enum rtx_code);
extern void rs6000_emit_sCOND (enum rtx_code, rtx);
extern void rs6000_emit_cbranch (enum rtx_code, rtx);
extern char * output_cbranch (rtx, const char *, int, rtx);
*************** extern int mfcr_operation (rtx, enum mac
*** 125,131 ****
extern int mtcrf_operation (rtx, enum machine_mode);
extern int lmw_operation (rtx, enum machine_mode);
extern struct rtx_def *create_TOC_reference (rtx);
! extern void rs6000_split_altivec_in_gprs (rtx *);
extern void rs6000_emit_move (rtx, rtx, enum machine_mode);
extern rtx rs6000_legitimize_address (rtx, rtx, enum machine_mode);
extern rtx rs6000_legitimize_reload_address (rtx, enum machine_mode,
--- 125,131 ----
extern int mtcrf_operation (rtx, enum machine_mode);
extern int lmw_operation (rtx, enum machine_mode);
extern struct rtx_def *create_TOC_reference (rtx);
! extern void rs6000_split_multireg_move (rtx *);
extern void rs6000_emit_move (rtx, rtx, enum machine_mode);
extern rtx rs6000_legitimize_address (rtx, rtx, enum machine_mode);
extern rtx rs6000_legitimize_reload_address (rtx, enum machine_mode,
Index: rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.519
diff -c -p -r1.519 rs6000.c
*** rs6000.c 15 Sep 2003 20:23:42 -0000 1.519
--- rs6000.c 20 Sep 2003 21:22:57 -0000
*************** small_data_operand (rtx op ATTRIBUTE_UNU
*** 2200,2217 ****
#endif
}
! /* Return 1 for all valid move insn operand combination involving altivec
! vectors in gprs. */
! int
! altivec_in_gprs_p (rtx op0, rtx op1)
{
! if (REG_P (op0) && REGNO_REG_CLASS (REGNO (op0)) == GENERAL_REGS)
! return 1;
!
! if (REG_P (op1) && REGNO_REG_CLASS (REGNO (op1)) == GENERAL_REGS)
! return 1;
! return 0;
}
--- 2200,2212 ----
#endif
}
! /* Return true if either operand is a general purpose register. */
! bool
! gpr_or_gpr_p (rtx op0, rtx op1)
{
! return ((REG_P (op0) && INT_REGNO_P (REGNO (op0)))
! || (REG_P (op1) && INT_REGNO_P (REGNO (op1))));
}
*************** rs6000_emit_minmax (rtx dest, enum rtx_c
*** 9462,9475 ****
emit_move_insn (dest, target);
}
! /* Called by altivec splitter.
Input:
operands[0] : Destination of move
operands[1] : Source of move
! noperands : Size of operands vector
Output:
! operands[2-5] ([2-3] in 64 bit) : Destination slots
! operands[6-9] ([4-5] in 64 bit) : Source slots
Splits the move of operands[1] to operands[0].
This is done, if GPRs are one of the operands. In this case
--- 9457,9472 ----
emit_move_insn (dest, target);
}
! /* Called by splitter for multireg moves.
Input:
operands[0] : Destination of move
operands[1] : Source of move
!
Output:
! operands[2-n] : Destination slots
! operands[n-m] : Source slots
! where n = 2 + HARD_REGNO_NREGS (reg, GET_MODE (operands[0]))
! m = 2 + 2 * HARD_REGNO_NREGS (reg, GET_MODE (operands[0])) - 1
Splits the move of operands[1] to operands[0].
This is done, if GPRs are one of the operands. In this case
*************** rs6000_emit_minmax (rtx dest, enum rtx_c
*** 9479,9488 ****
*/
void
! rs6000_split_altivec_in_gprs (rtx *operands)
{
! int nregs, reg, i, j;
enum machine_mode mode;
/* Calculate number to move (2/4 for 32/64 bit mode). */
--- 9476,9488 ----
*/
void
! rs6000_split_multireg_move (rtx *operands)
{
! int nregs, reg, i, j, used_update = 0;
enum machine_mode mode;
+ rtx dst = operands[0];
+ rtx src = operands[1];
+ rtx insn = 0;
/* Calculate number to move (2/4 for 32/64 bit mode). */
*************** rs6000_split_altivec_in_gprs (rtx *opera
*** 9500,9507 ****
for (i = 0; i < nregs; i++)
{
j--;
! operands[i + 2] = operand_subword (operands[0], j, 0, mode);
! operands[i + 2 + nregs] =
operand_subword (operands[1], j, 0, mode);
}
}
--- 9500,9507 ----
for (i = 0; i < nregs; i++)
{
j--;
! operands[i+2] = operand_subword (operands[0], j, 0, mode);
! operands[i+2+nregs] =
operand_subword (operands[1], j, 0, mode);
}
}
*************** rs6000_split_altivec_in_gprs (rtx *opera
*** 9512,9540 ****
if (GET_CODE (operands[1]) == MEM)
{
rtx breg;
! /* We have offsettable addresses only. If we use one of the
! registers to address memory, we have change that register last. */
! breg = GET_CODE (XEXP (operands[1], 0)) == PLUS ?
! XEXP (XEXP (operands[1], 0), 0) :
! XEXP (operands[1], 0);
!
! if (REGNO (breg) >= REGNO (operands[0])
! && REGNO (breg) < REGNO (operands[0]) + nregs)
! j = REGNO (breg) - REGNO (operands[0]);
}
for (i = 0; i < nregs; i++)
! {
! /* Calculate index to next subword. */
! j++;
! if (j == nregs)
! j = 0;
!
! operands[i + 2] = operand_subword (operands[0], j, 0, mode);
! operands[i + 2 + nregs] =
! operand_subword (operands[1], j, 0, mode);
! }
}
}
--- 9512,9598 ----
if (GET_CODE (operands[1]) == MEM)
{
rtx breg;
!
! if (GET_CODE (XEXP (operands[1], 0)) == PRE_INC
! || GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
! {
! rtx delta_rtx;
! breg = XEXP (XEXP (operands[1], 0), 0);
! delta_rtx = GET_CODE (XEXP (operands[1], 0)) == PRE_INC
! ? GEN_INT (GET_MODE_SIZE (GET_MODE (operands[1])))
! : GEN_INT (-GET_MODE_SIZE (GET_MODE (operands[1])));
! insn = emit_insn (TARGET_32BIT
! ? gen_addsi3 (breg, breg, delta_rtx)
! : gen_adddi3 (breg, breg, delta_rtx));
! src = gen_rtx_MEM (mode, breg);
! }
!
! /* We have now address involving an base register only.
! If we use one of the registers to address memory,
! we have change that register last. */
!
! breg = (GET_CODE (XEXP (src, 0)) == PLUS
! ? XEXP (XEXP (src, 0), 0)
! : XEXP (src, 0));
!
! if (!REG_P (breg))
! abort();
!
! if (REGNO (breg) >= REGNO (dst)
! && REGNO (breg) < REGNO (dst) + nregs)
! j = REGNO (breg) - REGNO (dst);
}
+ if (GET_CODE (operands[0]) == MEM)
+ {
+ rtx breg;
+
+ if (GET_CODE (XEXP (operands[0], 0)) == PRE_INC
+ || GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
+ {
+ rtx delta_rtx;
+ breg = XEXP (XEXP (operands[0], 0), 0);
+ delta_rtx = GET_CODE (XEXP (operands[0], 0)) == PRE_INC
+ ? GEN_INT (GET_MODE_SIZE (GET_MODE (operands[0])))
+ : GEN_INT (-GET_MODE_SIZE (GET_MODE (operands[0])));
+
+ /* We have to update the breg before doing the store.
+ Use store with update, if available. */
+
+ if (TARGET_UPDATE)
+ {
+ insn = emit_insn (TARGET_32BIT
+ ? gen_movsi_update (breg, breg, delta_rtx,
+ operand_subword (src, 0, 0, mode))
+ : gen_movdi_update (breg, breg, delta_rtx,
+ operand_subword (src, 0, 0, mode)));
+ used_update = 1;
+ }
+ else
+ insn = emit_insn (TARGET_32BIT
+ ? gen_addsi3 (breg, breg, delta_rtx)
+ : gen_adddi3 (breg, breg, delta_rtx));
+ dst = gen_rtx_MEM (mode, breg);
+ }
+ }
+
for (i = 0; i < nregs; i++)
! {
! /* Calculate index to next subword. */
! ++j;
! if (j == nregs)
! j = 0;
! operands[i+2] = operand_subword (dst, j, 0, mode);
! operands[i+2+nregs] = operand_subword (src, j, 0, mode);
!
! if (j == 0 && used_update)
! {
! /* Already emited move of first word by
! store with update -> emit dead insn instead (r := r). */
! operands[i+2] = operands[i+2+nregs];
! }
! }
}
}
Index: rs6000.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.265
diff -c -p -r1.265 rs6000.md
*** rs6000.md 13 Aug 2003 17:05:19 -0000 1.265
--- rs6000.md 20 Sep 2003 21:22:57 -0000
***************
*** 8462,8486 ****
default:
abort ();
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:
return \"fmr %0,%1\";
case 4:
--- 8462,8470 ----
default:
abort ();
case 0:
case 1:
case 2:
! return \"#\";
case 3:
return \"fmr %0,%1\";
case 4:
***************
*** 8495,8502 ****
return \"#\";
}
}"
! [(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*,*,*,*")
! (set_attr "length" "8,8,8,4,4,4,8,12,8,12,16")])
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
--- 8479,8485 ----
return \"#\";
}
}"
! [(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*,*,*,*")])
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
***************
*** 8536,8541 ****
--- 8519,8535 ----
}")
(define_split
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (match_operand:DI 1 "input_operand" ""))]
+ "reload_completed && !TARGET_POWERPC64
+ && gpr_or_gpr_p (operands[0], operands[1])"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+ "{
+ rs6000_split_multireg_move (operands);
+ }")
+
+ (define_split
[(set (match_operand:TI 0 "gpc_reg_operand" "")
(match_operand:TI 1 "const_double_operand" ""))]
"TARGET_POWERPC64"
***************
*** 8677,8683 ****
[(parallel [(set (match_operand:TI 0 "general_operand" "")
(match_operand:TI 1 "general_operand" ""))
(clobber (scratch:SI))])]
! "TARGET_STRING || TARGET_POWERPC64"
"{ rs6000_emit_move (operands[0], operands[1], TImode); DONE; }")
;; We say that MQ is clobbered in the last alternative because the first
--- 8671,8677 ----
[(parallel [(set (match_operand:TI 0 "general_operand" "")
(match_operand:TI 1 "general_operand" ""))
(clobber (scratch:SI))])]
! ""
"{ rs6000_emit_move (operands[0], operands[1], TImode); DONE; }")
;; We say that MQ is clobbered in the last alternative because the first
***************
*** 8685,8695 ****
;; while the 2nd alternative would not. We put memory cases first so they
;; are preferred. Otherwise, we'd try to reload the output instead of
;; giving the SCRATCH mq.
(define_insn "*movti_power"
[(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r")
(match_operand:TI 1 "reg_or_mem_operand" "r,r,r,Q,m"))
(clobber (match_scratch:SI 2 "=q,q#X,X,X,X"))]
! "TARGET_STRING && TARGET_POWER && ! TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
"*
{
--- 8679,8690 ----
;; while the 2nd alternative would not. We put memory cases first so they
;; are preferred. Otherwise, we'd try to reload the output instead of
;; giving the SCRATCH mq.
+
(define_insn "*movti_power"
[(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r")
(match_operand:TI 1 "reg_or_mem_operand" "r,r,r,Q,m"))
(clobber (match_scratch:SI 2 "=q,q#X,X,X,X"))]
! "TARGET_POWER && ! TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
"*
{
***************
*** 8699,8716 ****
abort ();
case 0:
! return \"{stsi|stswi} %1,%P0,16\";
case 1:
! return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\;{st|stw} %Y1,%Y0\;{st|stw} %Z1,%Z0\";
case 2:
! /* Normally copy registers with lowest numbered register copied first.
! But copy in the other order if the first register of the output
! is the second, third, or fourth register in the input. */
! if (REGNO (operands[0]) >= REGNO (operands[1]) + 1
! && REGNO (operands[0]) <= REGNO (operands[1]) + 3)
! return \"mr %Z0,%Z1\;mr %Y0,%Y1\;mr %L0,%L1\;mr %0,%1\";
! else
! return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
case 3:
/* If the address is not used in the output, we can use lsi. Otherwise,
fall through to generating four loads. */
--- 8694,8705 ----
abort ();
case 0:
! if (TARGET_STRING)
! return \"{stsi|stswi} %1,%P0,16\";
case 1:
! return \"#\";
case 2:
! return \"#\";
case 3:
/* If the address is not used in the output, we can use lsi. Otherwise,
fall through to generating four loads. */
***************
*** 8718,8746 ****
return \"{lsi|lswi} %0,%P1,16\";
/* ... fall through ... */
case 4:
! /* If the address register is the same as the register for the lowest-
! addressed word, load it last. Similarly for the next two words.
! Otherwise load lowest address to highest. */
! if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
! operands[1], 0))
! return \"{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %0,%1\";
! else if (refers_to_regno_p (REGNO (operands[0]) + 1,
! REGNO (operands[0]) + 2, operands[1], 0))
! return \"{l|lwz} %0,%1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %L0,%L1\";
! else if (refers_to_regno_p (REGNO (operands[0]) + 2,
! REGNO (operands[0]) + 3, operands[1], 0))
! return \"{l|lwz} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Z0,%Z1\;{l|lwz} %Y0,%Y1\";
! else
! return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\";
}
}"
! [(set_attr "type" "store,store,*,load,load")
! (set_attr "length" "4,16,16,4,16")])
(define_insn "*movti_string"
[(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r")
(match_operand:TI 1 "reg_or_mem_operand" "r,r,r,Q,m"))]
! "TARGET_STRING && ! TARGET_POWER && ! TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
"*
{
--- 8707,8721 ----
return \"{lsi|lswi} %0,%P1,16\";
/* ... fall through ... */
case 4:
! return \"#\";
}
}"
! [(set_attr "type" "store,store,*,load,load")])
(define_insn "*movti_string"
[(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r")
(match_operand:TI 1 "reg_or_mem_operand" "r,r,r,Q,m"))]
! "! TARGET_POWER && ! TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
"*
{
***************
*** 8748,8828 ****
{
default:
abort ();
-
case 0:
! return \"{stsi|stswi} %1,%P0,16\";
case 1:
! return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\;{st|stw} %Y1,%Y0\;{st|stw} %Z1,%Z0\";
case 2:
! /* Normally copy registers with lowest numbered register copied first.
! But copy in the other order if the first register of the output
! is the second, third, or fourth register in the input. */
! if (REGNO (operands[0]) >= REGNO (operands[1]) + 1
! && REGNO (operands[0]) <= REGNO (operands[1]) + 3)
! return \"mr %Z0,%Z1\;mr %Y0,%Y1\;mr %L0,%L1\;mr %0,%1\";
! else
! return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
case 3:
/* If the address is not used in the output, we can use lsi. Otherwise,
fall through to generating four loads. */
! if (! reg_overlap_mentioned_p (operands[0], operands[1]))
return \"{lsi|lswi} %0,%P1,16\";
/* ... fall through ... */
case 4:
! /* If the address register is the same as the register for the lowest-
! addressed word, load it last. Similarly for the next two words.
! Otherwise load lowest address to highest. */
! if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
! operands[1], 0))
! return \"{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %0,%1\";
! else if (refers_to_regno_p (REGNO (operands[0]) + 1,
! REGNO (operands[0]) + 2, operands[1], 0))
! return \"{l|lwz} %0,%1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %L0,%L1\";
! else if (refers_to_regno_p (REGNO (operands[0]) + 2,
! REGNO (operands[0]) + 3, operands[1], 0))
! return \"{l|lwz} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Z0,%Z1\;{l|lwz} %Y0,%Y1\";
! else
! return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\";
}
}"
! [(set_attr "type" "store,store,*,load,load")
! (set_attr "length" "4,16,16,4,16")])
(define_insn "*movti_ppc64"
! [(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,m")
! (match_operand:TI 1 "input_operand" "r,m,r"))]
"TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
|| gpc_reg_operand (operands[1], TImode))"
! "*
! {
! switch (which_alternative)
! {
! default:
! abort ();
! 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 \"ld %L0,%L1\;ld %0,%1\";
! else
! return \"ld%U1 %0,%1\;ld %L0,%L1\";
! case 2:
! return \"std%U0 %1,%0\;std %L1,%L0\";
! }
! }"
! [(set_attr "type" "*,load,store")
! (set_attr "length" "8,8,8")])
(define_expand "load_multiple"
[(match_par_dup 3 [(set (match_operand:SI 0 "" "")
--- 8723,8784 ----
{
default:
abort ();
case 0:
! if (TARGET_STRING)
! return \"{stsi|stswi} %1,%P0,16\";
case 1:
! return \"#\";
case 2:
! return \"#\";
case 3:
/* 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 4:
! return \"#\";
}
}"
! [(set_attr "type" "store,store,*,load,load")])
(define_insn "*movti_ppc64"
! [(set (match_operand:TI 0 "nonimmediate_operand" "=r,m,r")
! (match_operand:TI 1 "input_operand" "r,r,o"))]
"TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
|| gpc_reg_operand (operands[1], TImode))"
! "@
! #
! #
! #"
! [(set_attr "type" "*,load,store")])
!
! (define_split
! [(set (match_operand:TI 0 "nonimmediate_operand" "")
! (match_operand:TI 1 "input_operand" ""))]
! "reload_completed && TARGET_POWERPC64
! && gpr_or_gpr_p (operands[0], operands[1])"
! [(set (match_dup 2) (match_dup 4))
! (set (match_dup 3) (match_dup 5))]
! "{
! rs6000_split_multireg_move (operands);
! }")
!
! (define_split
! [(set (match_operand:TI 0 "nonimmediate_operand" "")
! (match_operand:TI 1 "input_operand" ""))]
! "reload_completed && !TARGET_POWERPC64
! && gpr_or_gpr_p (operands[0], operands[1])"
! [(set (match_dup 2) (match_dup 6))
! (set (match_dup 3) (match_dup 7))
! (set (match_dup 4) (match_dup 8))
! (set (match_dup 5) (match_dup 9))]
! "{
! rs6000_split_multireg_move (operands);
! }")
!
!
(define_expand "load_multiple"
[(match_par_dup 3 [(set (match_operand:SI 0 "" "")