s390: Implement extzv for z10
authorRichard Henderson <rth@redhat.com>
Thu, 20 Dec 2012 18:05:11 +0000 (10:05 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Thu, 20 Dec 2012 18:05:11 +0000 (10:05 -0800)
        * config/s390/predicates.md (nonzero_shift_count_operand): New.
        * config/s390/s390-protos.h (s390_extzv_shift_ok): Declare.
        * config/s390/s390.c (s390_extzv_shift_ok): New function.
        * config/s390/s390.md (extzv): New expander.
        (*extzv<GPR>_zEC12, *extzv<GPR>_z10): New insns.
        (*pre_z10_extzv<GPR>): Rename from *extzv<GPR>; simplify with
        nonzero_shift_count_operand.
        (*extzv_<mode>_srl, *extzv_<mode>_sll): New insns.

Co-Authored-By: Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
From-SVN: r194644

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

index 3efc06806556df6ad4edde664048aac449aa006c..d2b9342472292ebbaf46dac3b13c169cf9f5b914 100644 (file)
        (extend<HQI><DSI>2, zero_extend<HQI>si2): Likewise.
        (zero_extend<HQI>di2, fixuns_trunc<BFP><GPR>2): Likewise.
 
+       * config/s390/predicates.md (nonzero_shift_count_operand): New.
+       * config/s390/s390-protos.h (s390_extzv_shift_ok): Declare.
+       * config/s390/s390.c (s390_extzv_shift_ok): New function.
+       * config/s390/s390.md (extzv): New expander.
+       (*extzv<GPR>_zEC12, *extzv<GPR>_z10): New insns.
+       (*pre_z10_extzv<GPR>): Rename from *extzv<GPR>; simplify with
+       nonzero_shift_count_operand.
+       (*extzv_<mode>_srl, *extzv_<mode>_sll): New insns.
+
 2012-12-20  Thomas Schwinge  <thomas@codesourcery.com>
 
        PR bootstrap/55202
index b9524ecc664545a989c25372c86394e72e11c6b3..d5e185d5ac7d8208dbb78bd3f0a7567af82dd565 100644 (file)
   return true;
 })
 
+(define_predicate "nonzero_shift_count_operand"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 1, GET_MODE_BITSIZE (mode) - 1)")))
+
 ;;  Return true if OP a valid operand for the LARL instruction.
 
 (define_predicate "larl_operand"
index 9b87914e4710b525364932031caf9cd2d1802d53..a494ba22893760f6fe66fa139140f3d0fce04c3f 100644 (file)
@@ -109,5 +109,6 @@ extern bool s390_legitimate_address_without_index_p (rtx);
 extern bool s390_decompose_shift_count (rtx, rtx *, HOST_WIDE_INT *);
 extern int s390_branch_condition_mask (rtx);
 extern int s390_compare_and_branch_condition_mask (rtx);
+extern bool s390_extzv_shift_ok (int, int, unsigned HOST_WIDE_INT);
 
 #endif /* RTX_CODE */
index d38ba7f79fb804b96e4f30b823e2c7170ca2d11b..2edc8ab78f2e848a2cbbf3a9829049c27925bc46 100644 (file)
@@ -1347,6 +1347,24 @@ s390_contiguous_bitmask_p (unsigned HOST_WIDE_INT in, int size,
   return true;
 }
 
+/* Check whether a rotate of ROTL followed by an AND of CONTIG is
+   equivalent to a shift followed by the AND.  In particular, CONTIG
+   should not overlap the (rotated) bit 0/bit 63 gap.  Negative values
+   for ROTL indicate a rotate to the right.  */
+
+bool
+s390_extzv_shift_ok (int bitsize, int rotl, unsigned HOST_WIDE_INT contig)
+{
+  int pos, len;
+  bool ok;
+
+  ok = s390_contiguous_bitmask_p (contig, bitsize, &pos, &len);
+  gcc_assert (ok);
+
+  return ((rotl >= 0 && rotl <= pos)
+         || (rotl < 0 && -rotl <= bitsize - len - pos));
+}
+
 /* Check whether we can (and want to) split a double-word
    move in mode MODE from SRC to DST into two single-word
    moves, moving the subword FIRST_SUBWORD first.  */
index d7adde5e724ca2dbbbbbea4a025439883029dbe4..f32004c328c4ae457990e7a051c3d277e5126bc5 100644 (file)
   [(set_attr "op_type" "RS,RSY")
    (set_attr "z10prop" "z10_super_E1,z10_super_E1")])
 
+;
+; extv instruction patterns
+;
+
+; FIXME: This expander needs to be converted from DI to GPR as well
+; after resolving some issues with it.
+
+(define_expand "extzv"
+  [(parallel
+    [(set (match_operand:DI 0 "register_operand" "=d")
+        (zero_extract:DI
+         (match_operand:DI 1 "register_operand" "d")
+         (match_operand 2 "const_int_operand" "")   ; size
+         (match_operand 3 "const_int_operand" ""))) ; start
+     (clobber (reg:CC CC_REGNUM))])]
+  "TARGET_Z10"
+{
+  /* Starting with zEC12 there is risbgn not clobbering CC.  */
+  if (TARGET_ZEC12)
+    {
+      emit_move_insn (operands[0],
+                    gen_rtx_ZERO_EXTRACT (DImode,
+                                          operands[1],
+                                          operands[2],
+                                          operands[3]));
+      DONE;
+    }
+})
 
-(define_insn_and_split "*extzv<mode>"
+(define_insn "*extzv<mode>_zEC12"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+      (zero_extract:GPR
+        (match_operand:GPR 1 "register_operand" "d")
+        (match_operand 2 "const_int_operand" "")   ; size
+        (match_operand 3 "const_int_operand" "")))] ; start]
+  "TARGET_ZEC12"
+  "risbgn\t%0,%1,64-%2,128+63,<bitsize>+%3+%2" ; dst, src, start, end, shift
+  [(set_attr "op_type" "RIE")])
+
+(define_insn "*extzv<mode>_z10"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+      (zero_extract:GPR
+       (match_operand:GPR 1 "register_operand" "d")
+       (match_operand 2 "const_int_operand" "")   ; size
+       (match_operand 3 "const_int_operand" ""))) ; start
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_Z10"
+  "risbg\t%0,%1,64-%2,128+63,<bitsize>+%3+%2" ; dst, src, start, end, shift
+  [(set_attr "op_type" "RIE")
+   (set_attr "z10prop" "z10_super_E1")])
+
+(define_insn_and_split "*pre_z10_extzv<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=d")
        (zero_extract:GPR (match_operand:QI 1 "s_operand" "QS")
-                         (match_operand 2 "const_int_operand" "n")
+                         (match_operand 2 "nonzero_shift_count_operand" "")
                          (const_int 0)))
    (clobber (reg:CC CC_REGNUM))]
-  "INTVAL (operands[2]) > 0
-   && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)"
+  "!TARGET_Z10"
   "#"
   "&& reload_completed"
   [(parallel
   operands[3] = GEN_INT (mask);
 })
 
-(define_insn_and_split "*extv<mode>"
+(define_insn_and_split "*pre_z10_extv<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=d")
        (sign_extract:GPR (match_operand:QI 1 "s_operand" "QS")
-                         (match_operand 2 "const_int_operand" "n")
+                         (match_operand 2 "nonzero_shift_count_operand" "")
                          (const_int 0)))
    (clobber (reg:CC CC_REGNUM))]
-  "INTVAL (operands[2]) > 0
-   && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)"
+  ""
   "#"
   "&& reload_completed"
   [(parallel
      (clobber (reg:CC CC_REGNUM))])]
   "s390_narrow_logical_operator (AND, &operands[0], &operands[1]);")
 
+;; These two are what combine generates for (ashift (zero_extract)).
+(define_insn "*extzv_<mode>_srl"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+       (and:GPR (lshiftrt:GPR
+                  (match_operand:GPR 1 "register_operand" "d")
+                  (match_operand:GPR 2 "nonzero_shift_count_operand" ""))
+               (match_operand:GPR 3 "contiguous_bitmask_operand" "")))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_Z10
+   /* Note that even for the SImode pattern, the rotate is always DImode.  */
+   && s390_extzv_shift_ok (<bitsize>, -INTVAL (operands[2]),
+                          INTVAL (operands[3]))"
+  "risbg\t%0,%1,%<bfstart>3,128+%<bfend>3,64-%2"
+  [(set_attr "op_type" "RIE")
+   (set_attr "z10prop" "z10_super_E1")])
+
+(define_insn "*extzv_<mode>_sll"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+       (and:GPR (ashift:GPR
+                 (match_operand:GPR 1 "register_operand" "d")
+                 (match_operand:GPR 2 "nonzero_shift_count_operand" ""))
+               (match_operand:GPR 3 "contiguous_bitmask_operand" "")))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_Z10
+   && s390_extzv_shift_ok (<bitsize>, INTVAL (operands[2]),
+                          INTVAL (operands[3]))"
+  "risbg\t%0,%1,%<bfstart>3,128+%<bfend>3,%2"
+  [(set_attr "op_type" "RIE")
+   (set_attr "z10prop" "z10_super_E1")])
+
 
 ;
 ; andsi3 instruction pattern(s).