This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
x86_64 merger part 17 - split-long-move update
- To: Richard Henderson <rth at redhat dot com>, Jan Hubicka <jh at suse dot cz>, gcc-patches at gcc dot gnu dot org, patches at x86-64 dot org
- Subject: x86_64 merger part 17 - split-long-move update
- From: Jan Hubicka <jh at suse dot cz>
- Date: Wed, 14 Mar 2001 18:58:53 +0100
Hi
Another nontrivial part that can get in before push issues are settled down.
It updates split_long_move to support 64bit moves.
This need updating on splitters part, since number of moves produced by
split_long_move is no longer fixed.
The ifdef is needed to avoid warning.
Quite unfortunate complication is that I handle moving of TFmodes by
64bit move followed by cheaper 32bit move. This adds kind of
"ping pong" with modes later in the code, since for example if
I am splitting push, it should be both 64bits anyway.
Honza
Wed Mar 14 18:51:04 CET 2001 Jan Hubicka <jh@suse.cz>
* i386-protos.h (ix86_split_long_move): Return void.
* i386.c (ix86_split_to_parts): Handle 64bit target.
(ix86_split_long_move): Likewise.
* i386.md (all calls to ix86_split_long_move): Update.
Index: egcs/gcc/config/i386/i386-protos.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386-protos.h,v
retrieving revision 1.44
diff -c -3 -p -r1.44 i386-protos.h
*** i386-protos.h 2001/02/28 18:19:22 1.44
--- i386-protos.h 2001/03/14 17:50:37
*************** extern void ix86_expand_branch PARAMS ((
*** 109,115 ****
extern int ix86_expand_setcc PARAMS ((enum rtx_code, rtx));
extern int ix86_expand_int_movcc PARAMS ((rtx[]));
extern int ix86_expand_fp_movcc PARAMS ((rtx[]));
! extern int ix86_split_long_move PARAMS ((rtx[]));
extern void ix86_split_ashldi PARAMS ((rtx *, rtx));
extern void ix86_split_ashrdi PARAMS ((rtx *, rtx));
extern void ix86_split_lshrdi PARAMS ((rtx *, rtx));
--- 109,115 ----
extern int ix86_expand_setcc PARAMS ((enum rtx_code, rtx));
extern int ix86_expand_int_movcc PARAMS ((rtx[]));
extern int ix86_expand_fp_movcc PARAMS ((rtx[]));
! extern void ix86_split_long_move PARAMS ((rtx[]));
extern void ix86_split_ashldi PARAMS ((rtx *, rtx));
extern void ix86_split_ashrdi PARAMS ((rtx *, rtx));
extern void ix86_split_lshrdi PARAMS ((rtx *, rtx));
Index: egcs/gcc/config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.c,v
retrieving revision 1.234
diff -c -3 -p -r1.234 i386.c
*** i386.c 2001/03/12 15:31:51 1.234
--- i386.c 2001/03/14 17:50:40
*************** ix86_split_to_parts (operand, parts, mod
*** 6283,6289 ****
PUT_MODE (operand, SImode);
parts[0] = parts[1] = parts[2] = operand;
}
! else
{
if (mode == DImode)
split_di (&operand, 1, &parts[0], &parts[1]);
--- 6283,6289 ----
PUT_MODE (operand, SImode);
parts[0] = parts[1] = parts[2] = operand;
}
! else if (!TARGET_64BIT)
{
if (mode == DImode)
split_di (&operand, 1, &parts[0], &parts[1]);
*************** ix86_split_to_parts (operand, parts, mod
*** 6332,6337 ****
--- 6332,6373 ----
abort ();
}
}
+ else
+ {
+ if (mode == XFmode || mode == TFmode)
+ {
+ if (REG_P (operand))
+ {
+ if (!reload_completed)
+ abort ();
+ parts[0] = gen_rtx_REG (DImode, REGNO (operand) + 0);
+ parts[1] = gen_rtx_REG (SImode, REGNO (operand) + 1);
+ }
+ else if (offsettable_memref_p (operand))
+ {
+ PUT_MODE (operand, DImode);
+ parts[0] = operand;
+ parts[1] = adj_offsettable_operand (operand, 8);
+ PUT_MODE (parts[1], SImode);
+ }
+ else if (GET_CODE (operand) == CONST_DOUBLE)
+ {
+ REAL_VALUE_TYPE r;
+ long l[3];
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
+ #if HOST_BITS_PER_WIDE_INT >= 64
+ parts[0] = GEN_INT (l[0] + (l[1] << 32));
+ #else
+ parts[0] = immed_double_const (l[0], l[1], DImode);
+ #endif
+ parts[1] = GEN_INT (l[2]);
+ }
+ else
+ abort ();
+ }
+ }
return size;
}
*************** ix86_split_to_parts (operand, parts, mod
*** 6341,6356 ****
insns have been emitted. Operands 2-4 contain the input values
int the correct order; operands 5-7 contain the output values. */
! int
ix86_split_long_move (operands1)
rtx operands1[];
{
rtx part[2][3];
rtx operands[2];
! int size;
int push = 0;
int collisions = 0;
/* Make our own copy to avoid clobbering the operands. */
operands[0] = copy_rtx (operands1[0]);
operands[1] = copy_rtx (operands1[1]);
--- 6377,6418 ----
insns have been emitted. Operands 2-4 contain the input values
int the correct order; operands 5-7 contain the output values. */
! void
ix86_split_long_move (operands1)
rtx operands1[];
{
rtx part[2][3];
rtx operands[2];
! int nparts;
int push = 0;
int collisions = 0;
+ /* The DFmode expanders may ask us to move double.
+ For 64bit target this is single move. By hiding the fact
+ here we simplify somehow i386.md part. */
+ if (GET_MODE_SIZE (GET_MODE (operands1[0])) == 8 && TARGET_64BIT)
+ {
+ /* Optimize constant pool reference to immediates. This is used by fp moves,
+ that force all constants to memory to allow combining. */
+
+ if (GET_CODE (operands1[1]) == MEM
+ && GET_CODE (XEXP (operands1[1], 0)) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (XEXP (operands1[1], 0)))
+ operands[1] = get_pool_constant (XEXP (operands1[1], 0));
+ else
+ operands[1] = operands1[1];
+ if (push_operand (operands1[0], VOIDmode))
+ {
+ operands[0] = copy_rtx (operands1[0]);
+ PUT_MODE (operands[0], DImode);
+ }
+ else
+ operands[0] = gen_lowpart (DImode, operands1[0]);
+ operands[1] = gen_lowpart (DImode, operands[1]);
+ emit_move_insn (operands[0], operands[1]);
+ return;
+ }
+
/* Make our own copy to avoid clobbering the operands. */
operands[0] = copy_rtx (operands1[0]);
operands[1] = copy_rtx (operands1[1]);
*************** ix86_split_long_move (operands1)
*** 6362,6375 ****
&& ! offsettable_memref_p (operands[0]))
abort ();
! size = ix86_split_to_parts (operands[0], part[0], GET_MODE (operands1[0]));
! ix86_split_to_parts (operands[1], part[1], GET_MODE (operands1[0]));
/* When emitting push, take care for source operands on the stack. */
if (push && GET_CODE (operands[1]) == MEM
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
{
! if (size == 3)
part[1][1] = part[1][2];
part[1][0] = part[1][1];
}
--- 6424,6437 ----
&& ! offsettable_memref_p (operands[0]))
abort ();
! nparts = ix86_split_to_parts (operands[1], part[1], GET_MODE (operands1[0]));
! ix86_split_to_parts (operands[0], part[0], GET_MODE (operands1[0]));
/* When emitting push, take care for source operands on the stack. */
if (push && GET_CODE (operands[1]) == MEM
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
{
! if (nparts == 3)
part[1][1] = part[1][2];
part[1][0] = part[1][1];
}
*************** ix86_split_long_move (operands1)
*** 6382,6393 ****
collisions++;
if (reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
collisions++;
! if (size == 3
&& reg_overlap_mentioned_p (part[0][2], XEXP (part[1][0], 0)))
collisions++;
/* Collision in the middle part can be handled by reordering. */
! if (collisions == 1 && size == 3
&& reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
{
rtx tmp;
--- 6444,6455 ----
collisions++;
if (reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
collisions++;
! if (nparts == 3
&& reg_overlap_mentioned_p (part[0][2], XEXP (part[1][0], 0)))
collisions++;
/* Collision in the middle part can be handled by reordering. */
! if (collisions == 1 && nparts == 3
&& reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
{
rtx tmp;
*************** ix86_split_long_move (operands1)
*** 6400,6441 ****
else if (collisions > 1)
{
collisions = 1;
! emit_insn (gen_rtx_SET (VOIDmode, part[0][size - 1],
XEXP (part[1][0], 0)));
! part[1][0] = change_address (part[1][0], SImode, part[0][size - 1]);
! part[1][1] = adj_offsettable_operand (part[1][0], 4);
! if (size == 3)
part[1][2] = adj_offsettable_operand (part[1][0], 8);
}
}
if (push)
{
! if (size == 3)
{
/* We use only first 12 bytes of TFmode value, but for pushing we
are required to adjust stack as if we were pushing real 16byte
value. */
! if (GET_MODE (operands1[0]) == TFmode)
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (-4)));
emit_insn (gen_push (part[1][2]));
}
emit_insn (gen_push (part[1][1]));
emit_insn (gen_push (part[1][0]));
! return 1;
}
/* Choose correct order to not overwrite the source before it is copied. */
if ((REG_P (part[0][0])
&& REG_P (part[1][1])
&& (REGNO (part[0][0]) == REGNO (part[1][1])
! || (size == 3
&& REGNO (part[0][0]) == REGNO (part[1][2]))))
|| (collisions > 0
&& reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0))))
{
! if (size == 3)
{
operands1[2] = part[0][2];
operands1[3] = part[0][1];
--- 6462,6520 ----
else if (collisions > 1)
{
collisions = 1;
! emit_insn (gen_rtx_SET (VOIDmode, part[0][nparts - 1],
XEXP (part[1][0], 0)));
! part[1][0] = change_address (part[1][0],
! TARGET_64BIT ? DImode : SImode,
! part[0][nparts - 1]);
! part[1][1] = adj_offsettable_operand (part[1][0],
! TARGET_64BIT ? 8 : 4);
! PUT_MODE (part[1][1], SImode);
! if (nparts == 3)
part[1][2] = adj_offsettable_operand (part[1][0], 8);
}
}
if (push)
{
! if (nparts == 3)
{
/* We use only first 12 bytes of TFmode value, but for pushing we
are required to adjust stack as if we were pushing real 16byte
value. */
! if (GET_MODE (operands1[0]) == TFmode && !TARGET_64BIT)
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (-4)));
emit_insn (gen_push (part[1][2]));
}
+ /* In 64bit mode we don't have 32bit push available. In case this is
+ register, it is OK - we will just use larger counterpart. We also
+ retype memory - these comes from attempt to avoid REX prefix on
+ moving of second half of TFmode value. */
+ if (TARGET_64BIT && GET_MODE (part[1][1]) == SImode)
+ {
+ if (GET_CODE (part[1][1]) == MEM)
+ PUT_MODE (part[1][1], DImode);
+ else if (!REG_P (part[1][1]))
+ abort();
+ else
+ part[1][1] = gen_rtx_REG (DImode, REGNO (part[1][1]));
+ }
emit_insn (gen_push (part[1][1]));
emit_insn (gen_push (part[1][0]));
! return;
}
/* Choose correct order to not overwrite the source before it is copied. */
if ((REG_P (part[0][0])
&& REG_P (part[1][1])
&& (REGNO (part[0][0]) == REGNO (part[1][1])
! || (nparts == 3
&& REGNO (part[0][0]) == REGNO (part[1][2]))))
|| (collisions > 0
&& reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0))))
{
! if (nparts == 3)
{
operands1[2] = part[0][2];
operands1[3] = part[0][1];
*************** ix86_split_long_move (operands1)
*** 6454,6460 ****
}
else
{
! if (size == 3)
{
operands1[2] = part[0][0];
operands1[3] = part[0][1];
--- 6533,6539 ----
}
else
{
! if (nparts == 3)
{
operands1[2] = part[0][0];
operands1[3] = part[0][1];
*************** ix86_split_long_move (operands1)
*** 6471,6478 ****
operands1[6] = part[1][1];
}
}
! return 0;
}
void
--- 6550,6568 ----
operands1[6] = part[1][1];
}
}
+ if (nparts == 3)
+ {
+ emit_move_insn (operands1[2], operands1[5]);
+ emit_move_insn (operands1[3], operands1[6]);
+ emit_move_insn (operands1[4], operands1[7]);
+ }
+ else
+ {
+ emit_move_insn (operands1[2], operands1[5]);
+ emit_move_insn (operands1[3], operands1[6]);
+ }
! return;
}
void
Index: egcs/gcc/config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.md,v
retrieving revision 1.236
diff -c -3 -p -r1.236 i386.md
*** i386.md 2001/03/14 15:38:55 1.236
--- i386.md 2001/03/14 17:50:42
***************
*** 2197,2212 ****
(match_operand:DI 1 "general_operand" ""))]
"reload_completed && ! MMX_REG_P (operands[1]) && !TARGET_64BIT"
[(const_int 0)]
! "if (!ix86_split_long_move (operands)) abort (); DONE;")
;; %%% This multiword shite has got to go.
(define_split
[(set (match_operand:DI 0 "nonimmediate_operand" "")
(match_operand:DI 1 "general_operand" ""))]
"reload_completed && ! MMX_REG_P (operands[0]) && ! MMX_REG_P (operands[1])"
! [(set (match_dup 2) (match_dup 5))
! (set (match_dup 3) (match_dup 6))]
! "if (ix86_split_long_move (operands)) DONE;")
(define_expand "movsf"
[(set (match_operand:SF 0 "nonimmediate_operand" "")
--- 2197,2211 ----
(match_operand:DI 1 "general_operand" ""))]
"reload_completed && ! MMX_REG_P (operands[1]) && !TARGET_64BIT"
[(const_int 0)]
! "ix86_split_long_move (operands);")
;; %%% This multiword shite has got to go.
(define_split
[(set (match_operand:DI 0 "nonimmediate_operand" "")
(match_operand:DI 1 "general_operand" ""))]
"reload_completed && ! MMX_REG_P (operands[0]) && ! MMX_REG_P (operands[1])"
! [(const_int 0)]
! "ix86_split_long_move (operands);")
(define_expand "movsf"
[(set (match_operand:SF 0 "nonimmediate_operand" "")
***************
*** 2421,2427 ****
(match_operand:DF 1 "general_operand" ""))]
"reload_completed"
[(const_int 0)]
! "if (!ix86_split_long_move (operands)) abort (); DONE;")
;; Moving is usually shorter when only FP registers are used. This separate
;; movdf pattern avoids the use of integer registers for FP operations
--- 2420,2426 ----
(match_operand:DF 1 "general_operand" ""))]
"reload_completed"
[(const_int 0)]
! "ix86_split_long_move (operands);")
;; Moving is usually shorter when only FP registers are used. This separate
;; movdf pattern avoids the use of integer registers for FP operations
***************
*** 2555,2563 ****
&& ! (ANY_FP_REG_P (operands[1]) ||
(GET_CODE (operands[1]) == SUBREG
&& ANY_FP_REG_P (SUBREG_REG (operands[1]))))"
! [(set (match_dup 2) (match_dup 5))
! (set (match_dup 3) (match_dup 6))]
! "if (ix86_split_long_move (operands)) DONE;")
(define_insn "*swapdf"
[(set (match_operand:DF 0 "register_operand" "+f")
--- 2554,2561 ----
&& ! (ANY_FP_REG_P (operands[1]) ||
(GET_CODE (operands[1]) == SUBREG
&& ANY_FP_REG_P (SUBREG_REG (operands[1]))))"
! [(const_int 0)]
! "ix86_split_long_move (operands);")
(define_insn "*swapdf"
[(set (match_operand:DF 0 "register_operand" "+f")
***************
*** 2717,2723 ****
|| GET_MODE (operands[0]) == DFmode)
&& (!REG_P (operands[1]) || !ANY_FP_REGNO_P (REGNO (operands[1])))"
[(const_int 0)]
! "if (!ix86_split_long_move (operands)) abort (); DONE;")
(define_split
[(set (match_operand:XF 0 "push_operand" "")
--- 2715,2721 ----
|| GET_MODE (operands[0]) == DFmode)
&& (!REG_P (operands[1]) || !ANY_FP_REGNO_P (REGNO (operands[1])))"
[(const_int 0)]
! "ix86_split_long_move (operands);")
(define_split
[(set (match_operand:XF 0 "push_operand" "")
***************
*** 2936,2945 ****
&& ! (ANY_FP_REG_P (operands[1]) ||
(GET_CODE (operands[1]) == SUBREG
&& ANY_FP_REG_P (SUBREG_REG (operands[1]))))"
! [(set (match_dup 2) (match_dup 5))
! (set (match_dup 3) (match_dup 6))
! (set (match_dup 4) (match_dup 7))]
! "if (ix86_split_long_move (operands)) DONE;")
(define_split
[(set (match_operand 0 "register_operand" "")
--- 2934,2941 ----
&& ! (ANY_FP_REG_P (operands[1]) ||
(GET_CODE (operands[1]) == SUBREG
&& ANY_FP_REG_P (SUBREG_REG (operands[1]))))"
! [(const_int 0)]
! "ix86_split_long_move (operands);")
(define_split
[(set (match_operand 0 "register_operand" "")