Try RISBG last, after other mechanisms have failed; don't require
operands in registers for it but force them there instead.  Try a
limited form of ICM.
---
 gcc/config/s390/s390.c |  129 ++++++++++++++++++++++++++++++-----------------
 1 files changed, 82 insertions(+), 47 deletions(-)

diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index f72f49f..240fb7e 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -4538,48 +4538,70 @@ s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src)
 {
   int bitsize = INTVAL (op1);
   int bitpos = INTVAL (op2);
+  enum machine_mode mode = GET_MODE (dest);
+  enum machine_mode smode = smallest_mode_for_size (bitsize, MODE_INT);
+  rtx op, clobber;
 
-  /* On z10 we can use the risbg instruction to implement insv.  */
-  if (TARGET_Z10
-      && ((GET_MODE (dest) == DImode && GET_MODE (src) == DImode)
-         || (GET_MODE (dest) == SImode && GET_MODE (src) == SImode)))
+  /* Generate INSERT IMMEDIATE (IILL et al).  */
+  /* (set (ze (reg)) (const_int)).  */
+  if (TARGET_ZARCH
+      && register_operand (dest, word_mode)
+      && (bitpos % 16) == 0
+      && (bitsize % 16) == 0
+      && const_int_operand (src, VOIDmode))
     {
-      rtx op;
-      rtx clobber;
+      HOST_WIDE_INT val = INTVAL (src);
+      int regpos = bitpos + bitsize;
 
-      op = gen_rtx_SET (GET_MODE(src),
-                       gen_rtx_ZERO_EXTRACT (GET_MODE (dest), dest, op1, op2),
-                       src);
-      clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
-      emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clobber)));
+      while (regpos > bitpos)
+       {
+         enum machine_mode putmode;
+         int putsize;
+
+         if (TARGET_EXTIMM && (regpos % 32 == 0) && (regpos >= bitpos + 32))
+           putmode = SImode;
+         else
+           putmode = HImode;
 
+         putsize = GET_MODE_BITSIZE (putmode);
+         regpos -= putsize;
+         emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest,
+                                               GEN_INT (putsize),
+                                               GEN_INT (regpos)),
+                         gen_int_mode (val, putmode));
+         val >>= putsize;
+       }
+      gcc_assert (regpos == bitpos);
       return true;
     }
 
-  /* We need byte alignment.  */
-  if (bitsize % BITS_PER_UNIT)
-    return false;
-
+  /* Generate STORE CHARACTERS UNDER MASK (STCM et al).  */
   if (bitpos == 0
-      && memory_operand (dest, VOIDmode)
+      && (bitsize % BITS_PER_UNIT) == 0
+      && MEM_P (dest)
       && (register_operand (src, word_mode)
          || const_int_operand (src, VOIDmode)))
     {
       /* Emit standard pattern if possible.  */
-      enum machine_mode mode = smallest_mode_for_size (bitsize, MODE_INT);
-      if (GET_MODE_BITSIZE (mode) == bitsize)
-       emit_move_insn (adjust_address (dest, mode, 0), gen_lowpart (mode, 
src));
+      if (GET_MODE_BITSIZE (smode) == bitsize)
+       {
+         emit_move_insn (adjust_address (dest, smode, 0),
+                         gen_lowpart (smode, src));
+         return true;
+       }
 
       /* (set (ze (mem)) (const_int)).  */
       else if (const_int_operand (src, VOIDmode))
        {
          int size = bitsize / BITS_PER_UNIT;
-         rtx src_mem = adjust_address (force_const_mem (word_mode, src), 
BLKmode,
+         rtx src_mem = adjust_address (force_const_mem (word_mode, src),
+                                       BLKmode,
                                        GET_MODE_SIZE (word_mode) - size);
 
          dest = adjust_address (dest, BLKmode, 0);
          set_mem_size (dest, size);
          s390_expand_movmem (dest, src_mem, GEN_INT (size));
+         return true;
        }
 
       /* (set (ze (mem)) (reg)).  */
@@ -4602,42 +4624,55 @@ s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src)
                              gen_rtx_LSHIFTRT (word_mode, src, GEN_INT
                                                (GET_MODE_BITSIZE (SImode))));
            }
+         return true;
        }
-      else
-       return false;
+    }
 
-      return true;
+  /* Generate INSERT CHARACTERS UNDER MASK (IC, ICM et al).  */
+  if ((bitpos % BITS_PER_UNIT) == 0
+      && (bitsize % BITS_PER_UNIT) == 0
+      && (bitpos & 32) == ((bitpos + bitsize - 1) & 32)
+      && MEM_P (src)
+      && (mode == DImode || mode == SImode)
+      && register_operand (dest, mode))
+    {
+      /* Emit a strict_low_part pattern if possible.  */
+      if (bitpos == 0 && GET_MODE_BITSIZE (smode) == bitsize)
+       {
+         op = gen_rtx_STRICT_LOW_PART (VOIDmode, gen_lowpart (smode, dest));
+         op = gen_rtx_SET (VOIDmode, op, gen_lowpart (smode, src));
+         clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
+         emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clobber)));
+         return true;
+       }
+
+      /* ??? There are more powerful versions of ICM that are not
+        completely represented in the md file.  */
     }
 
-  /* (set (ze (reg)) (const_int)).  */
-  if (TARGET_ZARCH
-      && register_operand (dest, word_mode)
-      && (bitpos % 16) == 0
-      && (bitsize % 16) == 0
-      && const_int_operand (src, VOIDmode))
+  /* For z10, generate ROTATE THEN INSERT SELECTED BITS (RISBG et al).  */
+  if (TARGET_Z10 && (mode == DImode || mode == SImode))
     {
-      HOST_WIDE_INT val = INTVAL (src);
-      int regpos = bitpos + bitsize;
+      enum machine_mode mode_s = GET_MODE (src);
 
-      while (regpos > bitpos)
+      if (mode_s == VOIDmode)
        {
-         enum machine_mode putmode;
-         int putsize;
+         /* Assume const_int etc already in the proper mode.  */
+         src = force_reg (mode, src);
+       }
+      else if (mode_s != mode)
+       {
+         gcc_assert (GET_MODE_BITSIZE (mode_s) >= bitsize);
+         src = force_reg (mode_s, src);
+         src = gen_lowpart (mode, src);
+       }
 
-         if (TARGET_EXTIMM && (regpos % 32 == 0) && (regpos >= bitpos + 32))
-           putmode = SImode;
-         else
-           putmode = HImode;
+      op = gen_rtx_SET (mode,
+                       gen_rtx_ZERO_EXTRACT (mode, dest, op1, op2),
+                       src);
+      clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
+      emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clobber)));
 
-         putsize = GET_MODE_BITSIZE (putmode);
-         regpos -= putsize;
-         emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest,
-                                               GEN_INT (putsize),
-                                               GEN_INT (regpos)),
-                         gen_int_mode (val, putmode));
-         val >>= putsize;
-       }
-      gcc_assert (regpos == bitpos);
       return true;
     }
 
-- 
1.7.7.6

Reply via email to