s390.c: (legitimize_la_operand): Remove, replace by ...
authorUlrich Weigand <uweigand@de.ibm.com>
Mon, 16 Sep 2002 14:13:12 +0000 (14:13 +0000)
committerUlrich Weigand <uweigand@gcc.gnu.org>
Mon, 16 Sep 2002 14:13:12 +0000 (14:13 +0000)
* 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

gcc/ChangeLog
gcc/config/s390/s390-protos.h
gcc/config/s390/s390.c
gcc/config/s390/s390.md

index ad15fdf933b0deea07e7867f5841cf4c9daab725..b9611076c32e0267e03c10a3bb2e949c21c0967c 100644 (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.
index c44ffb33234d20d23efb1a4a6ed94625fcbf1584..c66207ad0727b46e5507842ab3b9621631334705 100644 (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));
index 26c4dd2fe3d5430711741ab64ca3b36ee82abc39..549f3171e4e7dc0efab9871ce7283fab912b042f 100644 (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.  */
index 418165c84ea950f53509caa964e86dae6f212ab0..100758408db82084954c23534b2a1e96def0f4c3 100644 (file)
         (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).
    && !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).
    && !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).
 ;;
 
 ;
-; 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"
     }
 }"
   [(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"
     }
 }"
   [(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)))
   "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)))
    (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);
+  ""
+  "s390_expand_clrstr (operands[0], operands[1]); DONE;")
 
-      /* Load up the address+length pairs.  */
+; Clear a block that is up to 256 bytes in length.
+; The block length is taken as (operands[2] % 256) + 1.
 
-      emit_move_insn (gen_highpart (SImode, reg0), addr);
-      emit_move_insn (gen_lowpart (SImode, reg0), len);
+(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\";
 
-      emit_move_insn (gen_lowpart (SImode, reg1), const0_rtx);
-      /* CLear! */
-      emit_insn (gen_clrstrsi_31 (reg0, reg1, reg0));
-      DONE;    
-     }
-}")
+      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)\";
 
-; Clear memory with length less than 256 bytes 
+      default:
+        abort ();
+    }
+}"
+  [(set_attr "op_type" "SS,NN")
+   (set_attr "type"    "cs,cs")
+   (set_attr "atype"   "mem,mem")
+   (set_attr "length"  "*,14")])
 
-(define_insn "clrstrsico"
-  [(set (match_operand:BLK 0 "s_operand" "=Q")
+(define_insn "clrstr_short_31"
+  [(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
         (const_int 0))
-   (use (match_operand 1 "immediate_operand" "I"))
+   (use (match_operand:SI 1 "nonmemory_operand" "n,a"))
+   (clobber (match_scratch:SI 2 "=X,&a"))
    (clobber (reg:CC 33))]
-  ""
-  "xc\\t%O0(%1,%R0),%0"        
-  [(set_attr "op_type" "RS")
-   (set_attr "type"    "cs")
-   (set_attr "atype"   "mem")])
+  "!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 memory with length greater 256 bytes or lenght not constant
+; Clear a block of arbitrary length.
 
-(define_insn "clrstrsi_64"
+(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)))
    (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)))
    (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;
+  [(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;")
 
-  /* 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);
+(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;")
 
-  addr0 = force_operand (XEXP (operands[1], 0), NULL_RTX);
-  addr1 = force_operand (XEXP (operands[2], 0), NULL_RTX);
+; Compare a block that is up to 256 bytes in length.
+; The block length is taken as (operands[2] % 256) + 1.
 
-  if (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) < 256) 
+(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)
     {
-      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);
+      case 0:
+       return \"clc\\t%O0(%b2+1,%R0),%1\";
 
-      emit_move_insn (gen_highpart (DImode, reg1), addr1);
-      emit_move_insn (gen_lowpart (DImode, reg1), len);
+      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)\";
 
-      /* Compare! */
-      emit_insn (gen_cmpstr_64 (reg0, reg1, reg0, reg1));
-      emit_insn (gen_cmpint_di (operands[0]));
-      DONE;
+      default:
+        abort ();
     }
-}")
-
-;
-; cmpstrsi instruction pattern(s).
-;
+}"
+  [(set_attr "op_type" "SS,NN")
+   (set_attr "type"    "cs,cs")
+   (set_attr "atype"   "mem,mem")
+   (set_attr "length"  "*,14")])
 
-(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  "" ""))]
-   ""
-   "
+(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"
+  "*
 {
-  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) 
+  switch (which_alternative)
     {
-      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);
+      case 0:
+       return \"clc\\t%O0(%b2+1,%R0),%1\";
 
-      /* Compare! */
-      if (TARGET_64BIT) 
-          emit_insn (gen_cmpstr_64 (reg0, reg1, reg0, reg1));
-      else
-          emit_insn (gen_cmpstr_31 (reg0, reg1, reg0, reg1));
+      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)\";
 
-      emit_insn (gen_cmpint_si (operands[0]));
-      DONE;
+      default:
+        abort ();
     }
-}")
-
-; 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")])
+}"
+  [(set_attr "op_type" "SS,NN")
+   (set_attr "type"    "cs,cs")
+   (set_attr "atype"   "mem,mem")
+   (set_attr "length"  "*,14")])
 
-; Compare a block that is larger than 255 bytes in length.
+; Compare a block of arbitrary length.
 
-(define_insn "cmpstr_64"
+(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)
    (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)
    (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" "")