s390.c: (legitimize_la_operand): Remove, replace by ...

* config/s390/s390.c: (legitimize_la_operand): Remove, replace by ...
	(s390_load_address): ... this new function.
	(s390_decompose_address): Allow the argument pointer and all
	virtual registers as 'pointer' registers.
	(s390_expand_plus_operand): Use s390_load_address.
	config/s390/s390.md (movti, movdi, movdf splitters): Likewise.
	("force_la_31"): New insn pattern.
	config/s390/s390-protos.h (legitimize_la_operand): Remove.
	(s390_load_address): Add prototype.

	* config/s390/s390.c: Include "optabs.h".
	(s390_expand_movstr, s390_expand_clrstr, s390_expand_cmpstr): New.
	config/s390/s390-protos.h (s390_expand_movstr, s390_expand_clrstr,
	s390_expand_cmpstr): Add prototypes.
	config/s390/s390.md ("movstrdi", "movstrsi"): Call s390_expand_movstr.
	("movstrdi_short"): Rename to "movstr_short_64".  Change predicates
	for operands 0 and 1 to "memory_operand".  Add type attribute.
	("movstrsi_short"): Rename to "movstr_short_31".  Change predicates
	for operands 0 and 1 to "memory_operand".  Add type attribute.
	("movstrdi_long", "movstrsi_long"): Remove.
	("movstrdi_64"): Rename to "movstr_long_64". Add type attribute.
	("movstrsi_31"): Rename to "movstr_long_31". Add type attribute.
	("clrstrdi", "clrstrsi"): Call s390_expand_clrstr.
	("clrstrsico"): Remove, replace by ...
	("clrstr_short_64", "clrstr_short_31"): ... these new patterns.
	("clrstrsi_64"): Rename to "clrstr_long_64".
	("clrstrsi_31"): Rename to "clrstr_long_31".
	("cmpstrdi", "cmpstrsi"): Call s390_expand_cmpstr.
	("cmpstr_const"): Remove, replace by ...
	("cmpstr_short_64", "cmpstr_short_31"): ... these new patterns.
	("cmpstr_64"): Rename to "cmpstr_long_64".
	("cmpstr_31"): Rename to "cmpstr_long_31".

From-SVN: r57191
This commit is contained in:
Ulrich Weigand 2002-09-16 14:13:12 +00:00 committed by Ulrich Weigand
parent 2a4ecff3cb
commit a41c6c533d
4 changed files with 567 additions and 484 deletions

View File

@ -1,3 +1,38 @@
2002-09-16 Ulrich Weigand <uweigand@de.ibm.com>
* config/s390/s390.c: (legitimize_la_operand): Remove, replace by ...
(s390_load_address): ... this new function.
(s390_decompose_address): Allow the argument pointer and all
virtual registers as 'pointer' registers.
(s390_expand_plus_operand): Use s390_load_address.
config/s390/s390.md (movti, movdi, movdf splitters): Likewise.
("force_la_31"): New insn pattern.
config/s390/s390-protos.h (legitimize_la_operand): Remove.
(s390_load_address): Add prototype.
* config/s390/s390.c: Include "optabs.h".
(s390_expand_movstr, s390_expand_clrstr, s390_expand_cmpstr): New.
config/s390/s390-protos.h (s390_expand_movstr, s390_expand_clrstr,
s390_expand_cmpstr): Add prototypes.
config/s390/s390.md ("movstrdi", "movstrsi"): Call s390_expand_movstr.
("movstrdi_short"): Rename to "movstr_short_64". Change predicates
for operands 0 and 1 to "memory_operand". Add type attribute.
("movstrsi_short"): Rename to "movstr_short_31". Change predicates
for operands 0 and 1 to "memory_operand". Add type attribute.
("movstrdi_long", "movstrsi_long"): Remove.
("movstrdi_64"): Rename to "movstr_long_64". Add type attribute.
("movstrsi_31"): Rename to "movstr_long_31". Add type attribute.
("clrstrdi", "clrstrsi"): Call s390_expand_clrstr.
("clrstrsico"): Remove, replace by ...
("clrstr_short_64", "clrstr_short_31"): ... these new patterns.
("clrstrsi_64"): Rename to "clrstr_long_64".
("clrstrsi_31"): Rename to "clrstr_long_31".
("cmpstrdi", "cmpstrsi"): Call s390_expand_cmpstr.
("cmpstr_const"): Remove, replace by ...
("cmpstr_short_64", "cmpstr_short_31"): ... these new patterns.
("cmpstr_64"): Rename to "cmpstr_long_64".
("cmpstr_31"): Rename to "cmpstr_long_31".
2002-09-16 Kazu Hirata <kazu@cs.umass.edu>
* ABOUT-NLS: Follow spelling conventions.

View File

@ -49,7 +49,6 @@ extern enum machine_mode s390_tm_ccmode PARAMS ((rtx, rtx, int));
extern enum machine_mode s390_select_ccmode PARAMS ((enum rtx_code, rtx, rtx));
extern int symbolic_reference_mentioned_p PARAMS ((rtx));
extern int legitimate_la_operand_p PARAMS ((rtx));
extern rtx legitimize_la_operand PARAMS ((rtx));
extern int legitimate_pic_operand_p PARAMS ((rtx));
extern int legitimate_constant_p PARAMS ((rtx));
extern int legitimate_reload_constant_p PARAMS ((rtx));
@ -61,6 +60,10 @@ extern enum reg_class s390_secondary_input_reload_class PARAMS ((enum reg_class,
extern int s390_plus_operand PARAMS ((rtx, enum machine_mode));
extern void s390_expand_plus_operand PARAMS ((rtx, rtx, rtx));
extern void emit_pic_move PARAMS ((rtx *, enum machine_mode));
extern void s390_load_address PARAMS ((rtx, rtx));
extern void s390_expand_movstr PARAMS ((rtx, rtx, rtx));
extern void s390_expand_clrstr PARAMS ((rtx, rtx));
extern void s390_expand_cmpstr PARAMS ((rtx, rtx, rtx, rtx));
extern void s390_output_symbolic_const PARAMS ((FILE *, rtx));
extern void print_operand_address PARAMS ((FILE *, rtx));

View File

@ -46,6 +46,7 @@ Boston, MA 02111-1307, USA. */
#include "target-def.h"
#include "debug.h"
#include "langhooks.h"
#include "optabs.h"
static bool s390_assemble_integer PARAMS ((rtx, unsigned int, int));
static int s390_adjust_cost PARAMS ((rtx, rtx, rtx, int));
@ -1458,8 +1459,7 @@ s390_expand_plus_operand (target, src, scratch)
/* Emit the LOAD ADDRESS pattern. Note that reload of PLUS
is only ever performed on addresses, so we can mark the
sum as legitimate for LA in any case. */
src = legitimize_la_operand (src);
emit_insn (gen_rtx_SET (VOIDmode, target, src));
s390_load_address (target, src);
}
@ -1548,6 +1548,9 @@ s390_decompose_address (addr, out)
|| ((reload_completed || reload_in_progress)
&& frame_pointer_needed
&& REGNO (base) == HARD_FRAME_POINTER_REGNUM)
|| REGNO (base) == ARG_POINTER_REGNUM
|| (REGNO (base) >= FIRST_VIRTUAL_REGISTER
&& REGNO (base) <= LAST_VIRTUAL_REGISTER)
|| (flag_pic
&& REGNO (base) == PIC_OFFSET_TABLE_REGNUM))
pointer = TRUE;
@ -1573,6 +1576,9 @@ s390_decompose_address (addr, out)
|| ((reload_completed || reload_in_progress)
&& frame_pointer_needed
&& REGNO (indx) == HARD_FRAME_POINTER_REGNUM)
|| REGNO (indx) == ARG_POINTER_REGNUM
|| (REGNO (indx) >= FIRST_VIRTUAL_REGISTER
&& REGNO (indx) <= LAST_VIRTUAL_REGISTER)
|| (flag_pic
&& REGNO (indx) == PIC_OFFSET_TABLE_REGNUM))
pointer = TRUE;
@ -1737,30 +1743,19 @@ legitimate_la_operand_p (op)
return FALSE;
}
/* Return a modified variant of OP that is guaranteed to
be accepted by legitimate_la_operand_p. */
/* Emit a forced load-address operation to load SRC into DST.
This will use the LOAD ADDRESS instruction even in situations
where legitimate_la_operand_p (SRC) returns false. */
rtx
legitimize_la_operand (op)
register rtx op;
void
s390_load_address (dst, src)
rtx dst;
rtx src;
{
struct s390_address addr;
if (!s390_decompose_address (op, &addr))
abort ();
if (TARGET_64BIT || addr.pointer)
return op;
if (!addr.base)
abort ();
op = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr.base), 101);
if (addr.indx)
op = gen_rtx_PLUS (Pmode, op, addr.indx);
if (addr.disp)
op = gen_rtx_PLUS (Pmode, op, addr.disp);
return op;
if (TARGET_64BIT)
emit_move_insn (dst, src);
else
emit_insn (gen_force_la_31 (dst, src));
}
/* Return a legitimate reference for ORIG (an address) using the
@ -2148,6 +2143,312 @@ legitimize_address (x, oldx, mode)
return x;
}
/* Emit code to move LEN bytes from DST to SRC. */
void
s390_expand_movstr (dst, src, len)
rtx dst;
rtx src;
rtx len;
{
rtx (*gen_short) PARAMS ((rtx, rtx, rtx)) =
TARGET_64BIT ? gen_movstr_short_64 : gen_movstr_short_31;
rtx (*gen_long) PARAMS ((rtx, rtx, rtx, rtx)) =
TARGET_64BIT ? gen_movstr_long_64 : gen_movstr_long_31;
if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
{
if (INTVAL (len) > 0)
emit_insn ((*gen_short) (dst, src, GEN_INT (INTVAL (len) - 1)));
}
else if (TARGET_MVCLE)
{
enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode;
enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode;
rtx reg0 = gen_reg_rtx (double_mode);
rtx reg1 = gen_reg_rtx (double_mode);
emit_move_insn (gen_highpart (single_mode, reg0),
force_operand (XEXP (dst, 0), NULL_RTX));
emit_move_insn (gen_highpart (single_mode, reg1),
force_operand (XEXP (src, 0), NULL_RTX));
convert_move (gen_lowpart (single_mode, reg0), len, 1);
convert_move (gen_lowpart (single_mode, reg1), len, 1);
emit_insn ((*gen_long) (reg0, reg1, reg0, reg1));
}
else
{
rtx dst_addr, src_addr, count, blocks, temp;
rtx end_label = gen_label_rtx ();
enum machine_mode mode;
tree type;
mode = GET_MODE (len);
if (mode == VOIDmode)
mode = word_mode;
type = (*lang_hooks.types.type_for_mode) (mode, 1);
if (!type)
abort ();
dst_addr = gen_reg_rtx (Pmode);
src_addr = gen_reg_rtx (Pmode);
count = gen_reg_rtx (mode);
blocks = gen_reg_rtx (mode);
convert_move (count, len, 1);
emit_cmp_and_jump_insns (count, const0_rtx,
EQ, NULL_RTX, mode, 1, end_label);
emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX));
emit_move_insn (src_addr, force_operand (XEXP (src, 0), NULL_RTX));
dst = change_address (dst, VOIDmode, dst_addr);
src = change_address (src, VOIDmode, src_addr);
temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
if (temp != count)
emit_move_insn (count, temp);
temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
if (temp != blocks)
emit_move_insn (blocks, temp);
expand_start_loop (1);
expand_exit_loop_top_cond (0, build (NE_EXPR, type,
make_tree (type, blocks),
make_tree (type, const0_rtx)));
emit_insn ((*gen_short) (dst, src, GEN_INT (255)));
s390_load_address (dst_addr,
gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
s390_load_address (src_addr,
gen_rtx_PLUS (Pmode, src_addr, GEN_INT (256)));
temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0);
if (temp != blocks)
emit_move_insn (blocks, temp);
expand_end_loop ();
emit_insn ((*gen_short) (dst, src, convert_to_mode (word_mode, count, 1)));
emit_label (end_label);
}
}
/* Emit code to clear LEN bytes at DST. */
void
s390_expand_clrstr (dst, len)
rtx dst;
rtx len;
{
rtx (*gen_short) PARAMS ((rtx, rtx)) =
TARGET_64BIT ? gen_clrstr_short_64 : gen_clrstr_short_31;
rtx (*gen_long) PARAMS ((rtx, rtx, rtx)) =
TARGET_64BIT ? gen_clrstr_long_64 : gen_clrstr_long_31;
if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
{
if (INTVAL (len) > 0)
emit_insn ((*gen_short) (dst, GEN_INT (INTVAL (len) - 1)));
}
else if (TARGET_MVCLE)
{
enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode;
enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode;
rtx reg0 = gen_reg_rtx (double_mode);
rtx reg1 = gen_reg_rtx (double_mode);
emit_move_insn (gen_highpart (single_mode, reg0),
force_operand (XEXP (dst, 0), NULL_RTX));
convert_move (gen_lowpart (single_mode, reg0), len, 1);
emit_move_insn (gen_highpart (single_mode, reg1), const0_rtx);
emit_move_insn (gen_lowpart (single_mode, reg1), const0_rtx);
emit_insn ((*gen_long) (reg0, reg1, reg0));
}
else
{
rtx dst_addr, src_addr, count, blocks, temp;
rtx end_label = gen_label_rtx ();
enum machine_mode mode;
tree type;
mode = GET_MODE (len);
if (mode == VOIDmode)
mode = word_mode;
type = (*lang_hooks.types.type_for_mode) (mode, 1);
if (!type)
abort ();
dst_addr = gen_reg_rtx (Pmode);
src_addr = gen_reg_rtx (Pmode);
count = gen_reg_rtx (mode);
blocks = gen_reg_rtx (mode);
convert_move (count, len, 1);
emit_cmp_and_jump_insns (count, const0_rtx,
EQ, NULL_RTX, mode, 1, end_label);
emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX));
dst = change_address (dst, VOIDmode, dst_addr);
temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
if (temp != count)
emit_move_insn (count, temp);
temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
if (temp != blocks)
emit_move_insn (blocks, temp);
expand_start_loop (1);
expand_exit_loop_top_cond (0, build (NE_EXPR, type,
make_tree (type, blocks),
make_tree (type, const0_rtx)));
emit_insn ((*gen_short) (dst, GEN_INT (255)));
s390_load_address (dst_addr,
gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0);
if (temp != blocks)
emit_move_insn (blocks, temp);
expand_end_loop ();
emit_insn ((*gen_short) (dst, convert_to_mode (word_mode, count, 1)));
emit_label (end_label);
}
}
/* Emit code to compare LEN bytes at OP0 with those at OP1,
and return the result in TARGET. */
void
s390_expand_cmpstr (target, op0, op1, len)
rtx target;
rtx op0;
rtx op1;
rtx len;
{
rtx (*gen_short) PARAMS ((rtx, rtx, rtx)) =
TARGET_64BIT ? gen_cmpstr_short_64 : gen_cmpstr_short_31;
rtx (*gen_long) PARAMS ((rtx, rtx, rtx, rtx)) =
TARGET_64BIT ? gen_cmpstr_long_64 : gen_cmpstr_long_31;
rtx (*gen_result) PARAMS ((rtx)) =
GET_MODE (target) == DImode ? gen_cmpint_di : gen_cmpint_si;
op0 = protect_from_queue (op0, 0);
op1 = protect_from_queue (op1, 0);
len = protect_from_queue (len, 0);
if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
{
if (INTVAL (len) > 0)
{
emit_insn ((*gen_short) (op0, op1, GEN_INT (INTVAL (len) - 1)));
emit_insn ((*gen_result) (target));
}
else
emit_move_insn (target, const0_rtx);
}
else if (TARGET_MVCLE)
{
enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode;
enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode;
rtx reg0 = gen_reg_rtx (double_mode);
rtx reg1 = gen_reg_rtx (double_mode);
emit_move_insn (gen_highpart (single_mode, reg0),
force_operand (XEXP (op0, 0), NULL_RTX));
emit_move_insn (gen_highpart (single_mode, reg1),
force_operand (XEXP (op1, 0), NULL_RTX));
convert_move (gen_lowpart (single_mode, reg0), len, 1);
convert_move (gen_lowpart (single_mode, reg1), len, 1);
emit_insn ((*gen_long) (reg0, reg1, reg0, reg1));
emit_insn ((*gen_result) (target));
}
else
{
rtx addr0, addr1, count, blocks, temp;
rtx end_label = gen_label_rtx ();
enum machine_mode mode;
tree type;
mode = GET_MODE (len);
if (mode == VOIDmode)
mode = word_mode;
type = (*lang_hooks.types.type_for_mode) (mode, 1);
if (!type)
abort ();
addr0 = gen_reg_rtx (Pmode);
addr1 = gen_reg_rtx (Pmode);
count = gen_reg_rtx (mode);
blocks = gen_reg_rtx (mode);
convert_move (count, len, 1);
emit_cmp_and_jump_insns (count, const0_rtx,
EQ, NULL_RTX, mode, 1, end_label);
emit_move_insn (addr0, force_operand (XEXP (op0, 0), NULL_RTX));
emit_move_insn (addr1, force_operand (XEXP (op1, 0), NULL_RTX));
op0 = change_address (op0, VOIDmode, addr0);
op1 = change_address (op1, VOIDmode, addr1);
temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
if (temp != count)
emit_move_insn (count, temp);
temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
if (temp != blocks)
emit_move_insn (blocks, temp);
expand_start_loop (1);
expand_exit_loop_top_cond (0, build (NE_EXPR, type,
make_tree (type, blocks),
make_tree (type, const0_rtx)));
emit_insn ((*gen_short) (op0, op1, GEN_INT (255)));
temp = gen_rtx_NE (VOIDmode, gen_rtx_REG (CCSmode, 33), const0_rtx);
temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp,
gen_rtx_LABEL_REF (VOIDmode, end_label), pc_rtx);
temp = gen_rtx_SET (VOIDmode, pc_rtx, temp);
emit_jump_insn (temp);
s390_load_address (addr0,
gen_rtx_PLUS (Pmode, addr0, GEN_INT (256)));
s390_load_address (addr1,
gen_rtx_PLUS (Pmode, addr1, GEN_INT (256)));
temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0);
if (temp != blocks)
emit_move_insn (blocks, temp);
expand_end_loop ();
emit_insn ((*gen_short) (op0, op1, convert_to_mode (word_mode, count, 1)));
emit_label (end_label);
emit_insn ((*gen_result) (target));
}
}
/* In the name of slightly smaller debug output, and to cater to
general assembler losage, recognize various UNSPEC sequences
and turn them back into a direct symbol reference. */

View File

@ -832,10 +832,13 @@
(match_operand:TI 1 "memory_operand" ""))]
"TARGET_64BIT && reload_completed
&& !s_operand (operands[1], VOIDmode)"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (mem:TI (match_dup 2)))]
"operands[2] = operand_subword (operands[0], 1, 0, TImode);
operands[3] = legitimize_la_operand (XEXP (operands[1], 0));")
[(set (match_dup 0) (match_dup 1))]
"
{
rtx addr = operand_subword (operands[0], 1, 0, TImode);
s390_load_address (addr, XEXP (operands[1], 0));
operands[1] = replace_equiv_address (operands[1], addr);
}")
;
; movdi instruction pattern(s).
@ -981,10 +984,13 @@
&& !fp_operand (operands[0], VOIDmode)
&& !fp_operand (operands[1], VOIDmode)
&& !s_operand (operands[1], VOIDmode)"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (mem:DI (match_dup 2)))]
"operands[2] = operand_subword (operands[0], 1, 0, DImode);
operands[3] = legitimize_la_operand (XEXP (operands[1], 0));")
[(set (match_dup 0) (match_dup 1))]
"
{
rtx addr = operand_subword (operands[0], 1, 0, DImode);
s390_load_address (addr, XEXP (operands[1], 0));
operands[1] = replace_equiv_address (operands[1], addr);
}")
;
; movsi instruction pattern(s).
@ -1254,10 +1260,13 @@
&& !fp_operand (operands[0], VOIDmode)
&& !fp_operand (operands[1], VOIDmode)
&& !s_operand (operands[1], VOIDmode)"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (mem:DI (match_dup 2)))]
"operands[2] = operand_subword (operands[0], 1, 0, DFmode);
operands[3] = legitimize_la_operand (XEXP (operands[1], 0));")
[(set (match_dup 0) (match_dup 1))]
"
{
rtx addr = operand_subword (operands[0], 1, 0, DFmode);
s390_load_address (addr, XEXP (operands[1], 0));
operands[1] = replace_equiv_address (operands[1], addr);
}")
;
; movsf instruction pattern(s).
@ -1503,172 +1512,31 @@
;;
;
; movstrdi instruction pattern(s).
; movstrM instruction pattern(s).
;
(define_expand "movstrdi"
[(set (match_operand:BLK 0 "general_operand" "")
(match_operand:BLK 1 "general_operand" ""))
(use (match_operand:DI 2 "general_operand" ""))
(match_operand 3 "" "")]
"TARGET_64BIT"
"
{
rtx addr0, addr1;
addr0 = force_operand (XEXP (operands[0], 0), NULL_RTX);
addr1 = force_operand (XEXP (operands[1], 0), NULL_RTX);
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) <= 256)
{
operands[0] = change_address (operands[0], VOIDmode, addr0);
operands[1] = change_address (operands[1], VOIDmode, addr1);
operands[2] = GEN_INT (INTVAL (operands[2]) - 1);
emit_insn (gen_movstrdi_short (operands[0], operands[1], operands[2]));
DONE;
}
else
{
if (TARGET_MVCLE)
{
/* implementation suggested by Richard Henderson <rth@cygnus.com> */
rtx reg0 = gen_reg_rtx (TImode);
rtx reg1 = gen_reg_rtx (TImode);
rtx len = operands[2];
if (! CONSTANT_P (len))
len = force_reg (DImode, len);
/* Load up the address+length pairs. */
emit_move_insn (gen_highpart (DImode, reg0), addr0);
emit_move_insn (gen_lowpart (DImode, reg0), len);
emit_move_insn (gen_highpart (DImode, reg1), addr1);
emit_move_insn (gen_lowpart (DImode, reg1), len);
/* MOVE */
emit_insn (gen_movstrdi_64 (reg0, reg1, reg0, reg1));
DONE;
}
else
{
rtx label1 = gen_label_rtx ();
rtx label2 = gen_label_rtx ();
rtx reg0, reg1, len, blocks;
reg0 = gen_reg_rtx (DImode);
reg1 = gen_reg_rtx (DImode);
len = gen_reg_rtx (DImode);
blocks = gen_reg_rtx (DImode);
emit_move_insn (len, operands[2]);
emit_insn (gen_cmpdi (len, const0_rtx));
emit_jump_insn (gen_beq (label1));
emit_move_insn (reg0, addr0);
emit_move_insn (reg1, addr1);
emit_insn (gen_adddi3 (len, len, constm1_rtx));
emit_insn (gen_ashrdi3 (blocks, len, GEN_INT (8)));
emit_insn (gen_cmpdi (blocks, const0_rtx));
emit_jump_insn (gen_beq (label2));
emit_insn (gen_movstrdi_long (reg0, reg1, reg0, reg1, blocks, blocks));
emit_label (label2);
operands[0] = change_address (operands[0], VOIDmode, reg0);
operands[1] = change_address (operands[1], VOIDmode, reg1);
emit_insn (gen_movstrdi_short (operands[0], operands[1], len));
emit_label (label1);
DONE;
}
}
}")
;
; movstrsi instruction pattern(s).
;
[(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand:DI 2 "general_operand" ""))
(match_operand 3 "" "")]
"TARGET_64BIT"
"s390_expand_movstr (operands[0], operands[1], operands[2]); DONE;")
(define_expand "movstrsi"
[(set (match_operand:BLK 0 "general_operand" "")
(match_operand:BLK 1 "general_operand" ""))
(use (match_operand:SI 2 "general_operand" ""))
(match_operand 3 "" "")]
"!TARGET_64BIT"
"
{
rtx addr0 = force_operand (XEXP (operands[0], 0), NULL_RTX);
rtx addr1 = force_operand (XEXP (operands[1], 0), NULL_RTX);
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) <= 256)
{
operands[0] = change_address (operands[0], VOIDmode, addr0);
operands[1] = change_address (operands[1], VOIDmode, addr1);
operands[2] = GEN_INT (INTVAL (operands[2]) - 1);
emit_insn (gen_movstrsi_short (operands[0], operands[1], operands[2]));
DONE;
}
else
{
if (TARGET_MVCLE)
{
/* implementation suggested by Richard Henderson <rth@cygnus.com> */
rtx reg0 = gen_reg_rtx (DImode);
rtx reg1 = gen_reg_rtx (DImode);
rtx len = operands[2];
if (! CONSTANT_P (len))
len = force_reg (SImode, len);
/* Load up the address+length pairs. */
emit_move_insn (gen_highpart (SImode, reg0), addr0);
emit_move_insn (gen_lowpart (SImode, reg0), len);
emit_move_insn (gen_highpart (SImode, reg1), addr1);
emit_move_insn (gen_lowpart (SImode, reg1), len);
/* MOVE */
emit_insn (gen_movstrsi_31 (reg0, reg1, reg0, reg1));
DONE;
}
else
{
rtx label1 = gen_label_rtx ();
rtx label2 = gen_label_rtx ();
rtx reg0, reg1, len, blocks;
reg0 = gen_reg_rtx (SImode);
reg1 = gen_reg_rtx (SImode);
len = gen_reg_rtx (SImode);
blocks = gen_reg_rtx (SImode);
emit_move_insn (len, operands[2]);
emit_insn (gen_cmpsi (len, const0_rtx));
emit_jump_insn (gen_beq (label1));
emit_move_insn (reg0, addr0);
emit_move_insn (reg1, addr1);
emit_insn (gen_addsi3 (len, len, constm1_rtx));
emit_insn (gen_ashrsi3 (blocks, len, GEN_INT (8)));
emit_insn (gen_cmpsi (blocks, const0_rtx));
emit_jump_insn (gen_beq (label2));
emit_insn (gen_movstrsi_long (reg0, reg1, reg0, reg1, blocks, blocks));
emit_label (label2);
operands[0] = change_address (operands[0], VOIDmode, reg0);
operands[1] = change_address (operands[1], VOIDmode, reg1);
emit_insn (gen_movstrsi_short (operands[0], operands[1], len));
emit_label (label1);
DONE;
}
}
}")
[(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand:SI 2 "general_operand" ""))
(match_operand 3 "" "")]
""
"s390_expand_movstr (operands[0], operands[1], operands[2]); DONE;")
; Move a block that is up to 256 bytes in length.
; The block length is taken as (operands[2] % 256) + 1.
(define_insn "movstrdi_short"
[(set (match_operand:BLK 0 "s_operand" "=Q,Q")
(match_operand:BLK 1 "s_operand" "Q,Q"))
(define_insn "movstr_short_64"
[(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
(match_operand:BLK 1 "memory_operand" "Q,Q"))
(use (match_operand:DI 2 "nonmemory_operand" "n,a"))
(clobber (match_scratch:DI 3 "=X,&a"))]
"TARGET_64BIT"
@ -1689,12 +1557,13 @@
}
}"
[(set_attr "op_type" "SS,NN")
(set_attr "type" "cs,cs")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
(define_insn "movstrsi_short"
[(set (match_operand:BLK 0 "s_operand" "=Q,Q")
(match_operand:BLK 1 "s_operand" "Q,Q"))
(define_insn "movstr_short_31"
[(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
(match_operand:BLK 1 "memory_operand" "Q,Q"))
(use (match_operand:SI 2 "nonmemory_operand" "n,a"))
(clobber (match_scratch:SI 3 "=X,&a"))]
"!TARGET_64BIT"
@ -1715,64 +1584,13 @@
}
}"
[(set_attr "op_type" "SS,NN")
(set_attr "type" "cs,cs")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
; Move a block that is a multiple of 256 bytes in length
; Move a block of arbitrary length.
(define_insn "movstrdi_long"
[(set (match_operand:DI 4 "register_operand" "=d")
(const_int 0))
(set (match_operand:DI 0 "register_operand" "=a")
(plus:DI (match_operand:DI 2 "register_operand" "0")
(ashift:DI (match_operand:DI 5 "register_operand" "4")
(const_int 8))))
(set (match_operand:DI 1 "register_operand" "=a")
(plus:DI (match_operand:DI 3 "register_operand" "1")
(ashift:DI (match_dup 5) (const_int 8))))
(set (mem:BLK (match_dup 2))
(mem:BLK (match_dup 3)))
(use (match_dup 5))]
"TARGET_64BIT"
"*
{
output_asm_insn (\"mvc\\t0(256,%0),0(%1)\", operands);
output_asm_insn (\"la\\t%0,256(%0)\", operands);
output_asm_insn (\"la\\t%1,256(%1)\", operands);
return \"brct\\t%4,.-14\";
}"
[(set_attr "op_type" "NN")
(set_attr "atype" "mem")
(set_attr "length" "18")])
(define_insn "movstrsi_long"
[(set (match_operand:SI 4 "register_operand" "=d")
(const_int 0))
(set (match_operand:SI 0 "register_operand" "=a")
(plus:SI (match_operand:SI 2 "register_operand" "0")
(ashift:SI (match_operand:SI 5 "register_operand" "4")
(const_int 8))))
(set (match_operand:SI 1 "register_operand" "=a")
(plus:SI (match_operand:SI 3 "register_operand" "1")
(ashift:SI (match_dup 5) (const_int 8))))
(set (mem:BLK (match_dup 2))
(mem:BLK (match_dup 3)))
(use (match_dup 5))]
"!TARGET_64BIT"
"*
{
output_asm_insn (\"mvc\\t0(256,%0),0(%1)\", operands);
output_asm_insn (\"la\\t%0,256(%0)\", operands);
output_asm_insn (\"la\\t%1,256(%1)\", operands);
return \"brct\\t%4,.-14\";
}"
[(set_attr "op_type" "NN")
(set_attr "atype" "mem")
(set_attr "length" "18")])
; Move a block that is larger than 255 bytes in length.
(define_insn "movstrdi_64"
(define_insn "movstr_long_64"
[(set (match_operand:TI 0 "register_operand" "=d")
(ashift:TI (plus:TI (match_operand:TI 2 "register_operand" "0")
(lshiftrt:TI (match_dup 2) (const_int 64)))
@ -1787,10 +1605,11 @@
"TARGET_64BIT"
"mvcle\\t%0,%1,0\;jo\\t.-4"
[(set_attr "op_type" "NN")
(set_attr "type" "vs")
(set_attr "atype" "mem")
(set_attr "length" "8")])
(define_insn "movstrsi_31"
(define_insn "movstr_long_31"
[(set (match_operand:DI 0 "register_operand" "=d")
(ashift:DI (plus:DI (match_operand:DI 2 "register_operand" "0")
(lshiftrt:DI (match_dup 2) (const_int 32)))
@ -1804,112 +1623,93 @@
(clobber (reg:CC 33))]
"!TARGET_64BIT"
"mvcle\\t%0,%1,0\;jo\\t.-4"
[(set_attr "op_type" "NN")
(set_attr "atype" "mem")
(set_attr "length" "8")])
[(set_attr "op_type" "NN")
(set_attr "type" "vs")
(set_attr "atype" "mem")
(set_attr "length" "8")])
;
; clrstrdi instruction pattern(s).
; clrstrM instruction pattern(s).
;
(define_expand "clrstrdi"
[(set (match_operand:BLK 0 "general_operand" "")
[(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand:DI 1 "general_operand" ""))
(match_operand 2 "" "")]
"TARGET_64BIT"
"
{
rtx addr = force_operand (XEXP (operands[0], 0), NULL_RTX);
operands[0] = change_address (operands[0], VOIDmode, addr);
if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 256)
{
emit_insn (gen_clrstrsico (operands[0], operands[1]));
DONE;
}
else
{
rtx reg0 = gen_reg_rtx (TImode);
rtx reg1 = gen_reg_rtx (TImode);
rtx len = operands[1];
if (! CONSTANT_P (len))
len = force_reg (DImode, len);
/* Load up the address+length pairs. */
emit_move_insn (gen_highpart (DImode, reg0), addr);
emit_move_insn (gen_lowpart (DImode, reg0), len);
emit_move_insn (gen_lowpart (DImode, reg1), const0_rtx);
/* Clear! */
emit_insn (gen_clrstrsi_64 (reg0, reg1, reg0));
DONE;
}
}")
;
; clrstrsi instruction pattern(s).
;
"s390_expand_clrstr (operands[0], operands[1]); DONE;")
(define_expand "clrstrsi"
[(set (match_operand:BLK 0 "general_operand" "")
[(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand:SI 1 "general_operand" ""))
(match_operand 2 "" "")]
"!TARGET_64BIT"
"
{
rtx addr = force_operand (XEXP (operands[0], 0), NULL_RTX);
operands[0] = change_address (operands[0], VOIDmode, addr);
if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 256)
{
emit_insn (gen_clrstrsico (operands[0], operands[1]));
DONE;
}
else
{
rtx reg0 = gen_reg_rtx (DImode);
rtx reg1 = gen_reg_rtx (DImode);
rtx len = operands[1];
if (! CONSTANT_P (len))
len = force_reg (SImode, len);
/* Load up the address+length pairs. */
emit_move_insn (gen_highpart (SImode, reg0), addr);
emit_move_insn (gen_lowpart (SImode, reg0), len);
emit_move_insn (gen_lowpart (SImode, reg1), const0_rtx);
/* CLear! */
emit_insn (gen_clrstrsi_31 (reg0, reg1, reg0));
DONE;
}
}")
; Clear memory with length less than 256 bytes
(define_insn "clrstrsico"
[(set (match_operand:BLK 0 "s_operand" "=Q")
(const_int 0))
(use (match_operand 1 "immediate_operand" "I"))
(clobber (reg:CC 33))]
""
"xc\\t%O0(%1,%R0),%0"
[(set_attr "op_type" "RS")
(set_attr "type" "cs")
(set_attr "atype" "mem")])
"s390_expand_clrstr (operands[0], operands[1]); DONE;")
; Clear memory with length greater 256 bytes or lenght not constant
; Clear a block that is up to 256 bytes in length.
; The block length is taken as (operands[2] % 256) + 1.
(define_insn "clrstrsi_64"
(define_insn "clrstr_short_64"
[(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
(const_int 0))
(use (match_operand:DI 1 "nonmemory_operand" "n,a"))
(clobber (match_scratch:DI 2 "=X,&a"))
(clobber (reg:CC 33))]
"TARGET_64BIT"
"*
{
switch (which_alternative)
{
case 0:
return \"xc\\t%O0(%b1+1,%R0),%0\";
case 1:
output_asm_insn (\"bras\\t%2,.+10\", operands);
output_asm_insn (\"xc\\t%O0(1,%R0),%0\", operands);
return \"ex\\t%1,0(%2)\";
default:
abort ();
}
}"
[(set_attr "op_type" "SS,NN")
(set_attr "type" "cs,cs")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
(define_insn "clrstr_short_31"
[(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
(const_int 0))
(use (match_operand:SI 1 "nonmemory_operand" "n,a"))
(clobber (match_scratch:SI 2 "=X,&a"))
(clobber (reg:CC 33))]
"!TARGET_64BIT"
"*
{
switch (which_alternative)
{
case 0:
return \"xc\\t%O0(%b1+1,%R0),%0\";
case 1:
output_asm_insn (\"bras\\t%2,.+10\", operands);
output_asm_insn (\"xc\\t%O0(1,%R0),%0\", operands);
return \"ex\\t%1,0(%2)\";
default:
abort ();
}
}"
[(set_attr "op_type" "SS,NN")
(set_attr "type" "cs,cs")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
; Clear a block of arbitrary length.
(define_insn "clrstr_long_64"
[(set (match_operand:TI 0 "register_operand" "=d")
(ashift:TI (plus:TI (match_operand:TI 2 "register_operand" "0")
(lshiftrt:TI (match_dup 2) (const_int 64)))
@ -1925,7 +1725,7 @@
(set_attr "type" "vs")
(set_attr "length" "8")])
(define_insn "clrstrsi_31"
(define_insn "clrstr_long_31"
[(set (match_operand:DI 0 "register_operand" "=d")
(ashift:DI (plus:DI (match_operand:DI 2 "register_operand" "0")
(lshiftrt:DI (match_dup 2) (const_int 32)))
@ -1942,157 +1742,91 @@
(set_attr "length" "8")])
;
; cmpstrdi instruction pattern(s).
; cmpstrM instruction pattern(s).
;
(define_expand "cmpstrdi"
[(set (match_operand:DI 0 "register_operand" "")
(compare:DI (match_operand:BLK 1 "general_operand" "")
(match_operand:BLK 2 "general_operand" "") ) )
(use (match_operand:DI 3 "general_operand" ""))
(use (match_operand:DI 4 "" ""))]
"TARGET_64BIT"
"
{
rtx addr0, addr1;
/* for pre/post increment */
operands[1] = protect_from_queue (operands[1], 0);
operands[2] = protect_from_queue (operands[2], 0);
operands[3] = protect_from_queue (operands[3], 0);
addr0 = force_operand (XEXP (operands[1], 0), NULL_RTX);
addr1 = force_operand (XEXP (operands[2], 0), NULL_RTX);
if (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) < 256)
{
if (INTVAL (operands[3]) == 0) {
emit_move_insn (operands[0], operands[3]);
DONE;
}
operands[1] = change_address (operands[1], VOIDmode, addr0);
operands[2] = change_address (operands[2], VOIDmode, addr1);
emit_insn (gen_cmpstr_const (operands[1], operands[2], operands[3]));
emit_insn (gen_cmpint_di (operands[0]));
DONE;
}
else
{
/* implementation suggested by Richard Henderson <rth@cygnus.com> */
rtx reg0 = gen_reg_rtx (TImode);
rtx reg1 = gen_reg_rtx (TImode);
rtx len = operands[3];
if (! CONSTANT_P (len))
len = force_reg (DImode, len);
/* Load up the address+length pairs. */
emit_move_insn (gen_highpart (DImode, reg0), addr0);
emit_move_insn (gen_lowpart (DImode, reg0), len);
emit_move_insn (gen_highpart (DImode, reg1), addr1);
emit_move_insn (gen_lowpart (DImode, reg1), len);
/* Compare! */
emit_insn (gen_cmpstr_64 (reg0, reg1, reg0, reg1));
emit_insn (gen_cmpint_di (operands[0]));
DONE;
}
}")
;
; cmpstrsi instruction pattern(s).
;
[(set (match_operand:DI 0 "register_operand" "")
(compare:DI (match_operand:BLK 1 "memory_operand" "")
(match_operand:BLK 2 "memory_operand" "") ) )
(use (match_operand:DI 3 "general_operand" ""))
(use (match_operand:DI 4 "" ""))]
"TARGET_64BIT"
"s390_expand_cmpstr (operands[0], operands[1],
operands[2], operands[3]); DONE;")
(define_expand "cmpstrsi"
[(set (match_operand:SI 0 "register_operand" "")
(compare:SI (match_operand:BLK 1 "general_operand" "")
(match_operand:BLK 2 "general_operand" "") ) )
(use (match_operand:SI 3 "general_operand" ""))
(use (match_operand:SI 4 "" ""))]
""
"
{
rtx addr0, addr1;
[(set (match_operand:SI 0 "register_operand" "")
(compare:SI (match_operand:BLK 1 "memory_operand" "")
(match_operand:BLK 2 "memory_operand" "") ) )
(use (match_operand:SI 3 "general_operand" ""))
(use (match_operand:SI 4 "" ""))]
""
"s390_expand_cmpstr (operands[0], operands[1],
operands[2], operands[3]); DONE;")
/* for pre/post increment */
operands[1] = protect_from_queue (operands[1], 0);
operands[2] = protect_from_queue (operands[2], 0);
operands[3] = protect_from_queue (operands[3], 0);
; Compare a block that is up to 256 bytes in length.
; The block length is taken as (operands[2] % 256) + 1.
addr0 = force_operand (XEXP (operands[1], 0), NULL_RTX);
addr1 = force_operand (XEXP (operands[2], 0), NULL_RTX);
if (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) < 256)
{
if (INTVAL (operands[3]) == 0) {
emit_move_insn (operands[0], operands[3]);
DONE;
}
operands[1] = change_address (operands[1], VOIDmode, addr0);
operands[2] = change_address (operands[2], VOIDmode, addr1);
emit_insn (gen_cmpstr_const (operands[1], operands[2], operands[3]));
emit_insn (gen_cmpint_si (operands[0]));
DONE;
}
else
{
/* implementation suggested by Richard Henderson <rth@cygnus.com> */
rtx reg0, reg1;
rtx len = operands[3];
if (TARGET_64BIT)
{
reg0 = gen_reg_rtx (TImode);
reg1 = gen_reg_rtx (TImode);
}
else
{
reg0 = gen_reg_rtx (DImode);
reg1 = gen_reg_rtx (DImode);
}
if (! CONSTANT_P (len))
len = force_reg (Pmode, len);
/* Load up the address+length pairs. */
emit_move_insn (gen_highpart (Pmode, reg0), addr0);
emit_move_insn (gen_lowpart (Pmode, reg0), len);
emit_move_insn (gen_highpart (Pmode, reg1), addr1);
emit_move_insn (gen_lowpart (Pmode, reg1), len);
/* Compare! */
if (TARGET_64BIT)
emit_insn (gen_cmpstr_64 (reg0, reg1, reg0, reg1));
else
emit_insn (gen_cmpstr_31 (reg0, reg1, reg0, reg1));
emit_insn (gen_cmpint_si (operands[0]));
DONE;
}
}")
; Compare a block that is less than 256 bytes in length.
(define_insn "cmpstr_const"
(define_insn "cmpstr_short_64"
[(set (reg:CCS 33)
(compare:CCS (match_operand:BLK 0 "s_operand" "Q")
(match_operand:BLK 1 "s_operand" "Q")))
(use (match_operand 2 "immediate_operand" "I"))]
"(unsigned) INTVAL (operands[2]) < 256"
"clc\\t%O0(%c2,%R0),%1"
[(set_attr "op_type" "SS")
(set_attr "atype" "mem")
(set_attr "type" "cs")])
(compare:CCS (match_operand:BLK 0 "memory_operand" "=Q,Q")
(match_operand:BLK 1 "memory_operand" "Q,Q")))
(use (match_operand:DI 2 "nonmemory_operand" "n,a"))
(clobber (match_scratch:DI 3 "=X,&a"))]
"TARGET_64BIT"
"*
{
switch (which_alternative)
{
case 0:
return \"clc\\t%O0(%b2+1,%R0),%1\";
; Compare a block that is larger than 255 bytes in length.
case 1:
output_asm_insn (\"bras\\t%3,.+10\", operands);
output_asm_insn (\"clc\\t%O0(1,%R0),%1\", operands);
return \"ex\\t%2,0(%3)\";
(define_insn "cmpstr_64"
default:
abort ();
}
}"
[(set_attr "op_type" "SS,NN")
(set_attr "type" "cs,cs")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
(define_insn "cmpstr_short_31"
[(set (reg:CCS 33)
(compare:CCS (match_operand:BLK 0 "memory_operand" "=Q,Q")
(match_operand:BLK 1 "memory_operand" "Q,Q")))
(use (match_operand:SI 2 "nonmemory_operand" "n,a"))
(clobber (match_scratch:SI 3 "=X,&a"))]
"!TARGET_64BIT"
"*
{
switch (which_alternative)
{
case 0:
return \"clc\\t%O0(%b2+1,%R0),%1\";
case 1:
output_asm_insn (\"bras\\t%3,.+10\", operands);
output_asm_insn (\"clc\\t%O0(1,%R0),%1\", operands);
return \"ex\\t%2,0(%3)\";
default:
abort ();
}
}"
[(set_attr "op_type" "SS,NN")
(set_attr "type" "cs,cs")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
; Compare a block of arbitrary length.
(define_insn "cmpstr_long_64"
[(clobber (match_operand:TI 0 "register_operand" "=d"))
(clobber (match_operand:TI 1 "register_operand" "=d"))
(set (reg:CCS 33)
@ -2106,7 +1840,7 @@
(set_attr "atype" "mem")
(set_attr "type" "vs")])
(define_insn "cmpstr_31"
(define_insn "cmpstr_long_31"
[(clobber (match_operand:DI 0 "register_operand" "=d"))
(clobber (match_operand:DI 1 "register_operand" "=d"))
(set (reg:CCS 33)
@ -3372,6 +3106,16 @@
(set_attr "atype" "mem")
(set_attr "type" "la")])
(define_insn "force_la_31"
[(set (match_operand:SI 0 "register_operand" "=d")
(match_operand:QI 1 "address_operand" "p"))
(use (const_int 0))]
"!TARGET_64BIT"
"la\\t%0,%a1"
[(set_attr "op_type" "RX")
(set_attr "atype" "mem")
(set_attr "type" "la")])
(define_expand "reload_insi"
[(parallel [(match_operand:SI 0 "register_operand" "=a")
(match_operand:SI 1 "s390_plus_operand" "")