S/390: Rework string insns
Ulrich Weigand
Ulrich.Weigand@de.ibm.com
Mon Sep 16 07:21:00 GMT 2002
Hello,
now that the doloop pattern are implemented, it is possible to make the
hard-coded loops used for movstr explicit to the compiler; this allows
e.g. loop unrolling where appropriate. This patch does so, and adds the
same feature for the clrstr and cmpstr patterns.
Incidentally, this fixes a bug where the compiler would ICE when cmpstrsi
was called with a DImode length on 64-bit; this works now as well.
Bootstrapped/regtested on s390-ibm-linux and s390x-ibm-linux.
ChangeLog:
* 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".
Index: gcc/config/s390/s390-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390-protos.h,v
retrieving revision 1.12
diff -c -p -r1.12 s390-protos.h
*** gcc/config/s390/s390-protos.h 26 Aug 2002 18:18:19 -0000 1.12
--- gcc/config/s390/s390-protos.h 16 Sep 2002 13:52:10 -0000
*************** extern enum machine_mode s390_tm_ccmode
*** 49,55 ****
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));
--- 49,54 ----
*************** extern enum reg_class s390_secondary_inp
*** 61,66 ****
--- 60,69 ----
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));
Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.51
diff -c -p -r1.51 s390.c
*** gcc/config/s390/s390.c 12 Sep 2002 12:37:17 -0000 1.51
--- gcc/config/s390/s390.c 16 Sep 2002 13:52:14 -0000
*************** Boston, MA 02111-1307, USA. */
*** 46,51 ****
--- 46,52 ----
#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));
*************** s390_expand_plus_operand (target, src, s
*** 1458,1465 ****
/* 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));
}
--- 1459,1465 ----
/* 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. */
! s390_load_address (target, src);
}
*************** s390_decompose_address (addr, out)
*** 1548,1553 ****
--- 1548,1556 ----
|| ((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;
*************** s390_decompose_address (addr, out)
*** 1573,1578 ****
--- 1576,1584 ----
|| ((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;
*************** legitimate_la_operand_p (op)
*** 1737,1766 ****
return FALSE;
}
! /* Return a modified variant of OP that is guaranteed to
! be accepted by legitimate_la_operand_p. */
! rtx
! legitimize_la_operand (op)
! register rtx op;
{
! 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;
}
/* Return a legitimate reference for ORIG (an address) using the
--- 1743,1761 ----
return FALSE;
}
! /* 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. */
! void
! s390_load_address (dst, src)
! rtx dst;
! rtx src;
{
! 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
*************** legitimize_address (x, oldx, mode)
*** 2146,2151 ****
--- 2141,2452 ----
x = gen_rtx_PLUS (Pmode, x, constant_term);
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
Index: gcc/config/s390/s390.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.md,v
retrieving revision 1.31
diff -c -p -r1.31 s390.md
*** gcc/config/s390/s390.md 13 Sep 2002 09:46:57 -0000 1.31
--- gcc/config/s390/s390.md 16 Sep 2002 13:52:19 -0000
***************
*** 832,841 ****
(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));")
;
; movdi instruction pattern(s).
--- 832,844 ----
(match_operand:TI 1 "memory_operand" ""))]
"TARGET_64BIT && reload_completed
&& !s_operand (operands[1], VOIDmode)"
! [(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,990 ****
&& !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));")
;
; movsi instruction pattern(s).
--- 984,996 ----
&& !fp_operand (operands[0], VOIDmode)
&& !fp_operand (operands[1], VOIDmode)
&& !s_operand (operands[1], VOIDmode)"
! [(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,1263 ****
&& !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));")
;
; movsf instruction pattern(s).
--- 1260,1272 ----
&& !fp_operand (operands[0], VOIDmode)
&& !fp_operand (operands[1], VOIDmode)
&& !s_operand (operands[1], VOIDmode)"
! [(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,1674 ****
;;
;
! ; movstrdi 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).
! ;
(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;
! }
! }
! }")
; 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"))
(use (match_operand:DI 2 "nonmemory_operand" "n,a"))
(clobber (match_scratch:DI 3 "=X,&a"))]
"TARGET_64BIT"
--- 1512,1542 ----
;;
;
! ; movstrM instruction pattern(s).
;
(define_expand "movstrdi"
! [(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 "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 "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,1700 ****
}
}"
[(set_attr "op_type" "SS,NN")
(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"))
(use (match_operand:SI 2 "nonmemory_operand" "n,a"))
(clobber (match_scratch:SI 3 "=X,&a"))]
"!TARGET_64BIT"
--- 1557,1569 ----
}
}"
[(set_attr "op_type" "SS,NN")
+ (set_attr "type" "cs,cs")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
! (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,1778 ****
}
}"
[(set_attr "op_type" "SS,NN")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
! ; Move a block that is a multiple of 256 bytes in 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"
[(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)))
--- 1584,1596 ----
}
}"
[(set_attr "op_type" "SS,NN")
+ (set_attr "type" "cs,cs")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
! ; Move a block of arbitrary length.
! (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,1796 ****
"TARGET_64BIT"
"mvcle\\t%0,%1,0\;jo\\t.-4"
[(set_attr "op_type" "NN")
(set_attr "atype" "mem")
(set_attr "length" "8")])
! (define_insn "movstrsi_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)))
--- 1605,1615 ----
"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 "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,1915 ****
(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")])
;
! ; clrstrdi instruction pattern(s).
;
(define_expand "clrstrdi"
! [(set (match_operand:BLK 0 "general_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).
! ;
(define_expand "clrstrsi"
! [(set (match_operand:BLK 0 "general_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")])
! ; Clear memory with length greater 256 bytes or lenght not constant
! (define_insn "clrstrsi_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)))
--- 1623,1715 ----
(clobber (reg:CC 33))]
"!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")])
;
! ; clrstrM instruction pattern(s).
;
(define_expand "clrstrdi"
! [(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand:DI 1 "general_operand" ""))
(match_operand 2 "" "")]
"TARGET_64BIT"
! "s390_expand_clrstr (operands[0], operands[1]); DONE;")
(define_expand "clrstrsi"
! [(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand:SI 1 "general_operand" ""))
(match_operand 2 "" "")]
! ""
! "s390_expand_clrstr (operands[0], operands[1]); DONE;")
! ; Clear a block that is up to 256 bytes in length.
! ; The block length is taken as (operands[2] % 256) + 1.
! (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,1931 ****
(set_attr "type" "vs")
(set_attr "length" "8")])
! (define_insn "clrstrsi_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)))
--- 1725,1731 ----
(set_attr "type" "vs")
(set_attr "length" "8")])
! (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,2098 ****
(set_attr "length" "8")])
;
! ; cmpstrdi 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).
! ;
(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;
!
! /* 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_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"
[(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 a block that is larger than 255 bytes in length.
! (define_insn "cmpstr_64"
[(clobber (match_operand:TI 0 "register_operand" "=d"))
(clobber (match_operand:TI 1 "register_operand" "=d"))
(set (reg:CCS 33)
--- 1742,1832 ----
(set_attr "length" "8")])
;
! ; cmpstrM instruction pattern(s).
;
(define_expand "cmpstrdi"
! [(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 "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;")
! ; Compare a block that is up to 256 bytes in length.
! ; The block length is taken as (operands[2] % 256) + 1.
! (define_insn "cmpstr_short_64"
! [(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: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\";
! 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")])
! (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,2112 ****
(set_attr "atype" "mem")
(set_attr "type" "vs")])
! (define_insn "cmpstr_31"
[(clobber (match_operand:DI 0 "register_operand" "=d"))
(clobber (match_operand:DI 1 "register_operand" "=d"))
(set (reg:CCS 33)
--- 1840,1846 ----
(set_attr "atype" "mem")
(set_attr "type" "vs")])
! (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)
***************
*** 3367,3372 ****
--- 3101,3116 ----
[(set (match_operand:SI 0 "register_operand" "=d")
(match_operand:QI 1 "address_operand" "p"))]
"legitimate_la_operand_p (operands[1])"
+ "la\\t%0,%a1"
+ [(set_attr "op_type" "RX")
+ (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")
Mit freundlichen Gruessen / Best Regards
Ulrich Weigand
--
Dr. Ulrich Weigand
Linux for S/390 Design & Development
IBM Deutschland Entwicklung GmbH, Schoenaicher Str. 220, 71032 Boeblingen
Phone: +49-7031/16-3727 --- Email: Ulrich.Weigand@de.ibm.com
More information about the Gcc-patches
mailing list