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