[5/7] s390: Implement extzv for z10

Submitted by Richard Henderson on Aug. 10, 2012, 2:31 a.m.

Details

Message ID 1344565921-27852-6-git-send-email-rth@redhat.com
State New
Headers show

Commit Message

Richard Henderson Aug. 10, 2012, 2:31 a.m.
---
 gcc/config/s390/predicates.md |    4 +++
 gcc/config/s390/s390-protos.h |    1 +
 gcc/config/s390/s390.c        |   16 ++++++++++++
 gcc/config/s390/s390.md       |   55 +++++++++++++++++++++++++++++++++++------
 4 files changed, 68 insertions(+), 8 deletions(-)

Comments

Andreas Krebbel Dec. 14, 2012, 1:52 p.m.
I've changed the s390_extzv_shift_ok function and have added extzv
patterns for zEC12. I also tried to implement an extzvsi expander but
ran into some issues which need to be fixed first.

Tested on s390 and s390x with z196 and zEC12.

Please apply to mainline. Thanks!

Bye,

-Andreas-

 gcc/config/s390/predicates.md |    4 +
 gcc/config/s390/s390-protos.h |    1 
 gcc/config/s390/s390.c        |   18 ++++++++
 gcc/config/s390/s390.md       |   94 +++++++++++++++++++++++++!!!!!!!!!!!!!!!!!
 4 files changed, 81 insertions(+), 36 modifications(!)

Index: gcc/config/s390/predicates.md
===================================================================
*** gcc/config/s390/predicates.md.orig
--- gcc/config/s390/predicates.md
***************
*** 101,106 ****
--- 101,110 ----
    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: gcc/config/s390/s390-protos.h
===================================================================
*** gcc/config/s390/s390-protos.h.orig
--- gcc/config/s390/s390-protos.h
*************** extern bool s390_legitimate_address_with
*** 109,113 ****
--- 109,114 ----
  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: gcc/config/s390/s390.c
===================================================================
*** gcc/config/s390/s390.c.orig
--- gcc/config/s390/s390.c
*************** s390_contiguous_bitmask_p (unsigned HOST
*** 1347,1352 ****
--- 1347,1370 ----
    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: gcc/config/s390/s390.md
===================================================================
*** gcc/config/s390/s390.md.orig
--- gcc/config/s390/s390.md
***************
*** 3307,3321 ****
    [(set_attr "op_type" "RS,RSY")
     (set_attr "z10prop" "z10_super_E1,z10_super_E1")])
  
  
! (define_insn_and_split "*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")
  		          (const_int 0)))
     (clobber (reg:CC CC_REGNUM))]
!   "INTVAL (operands[2]) > 0
!    && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)"
    "#"
    "&& reload_completed"
    [(parallel
--- 3307,3370 ----
    [(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 "*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 "nonzero_shift_count_operand" "")
  		          (const_int 0)))
     (clobber (reg:CC CC_REGNUM))]
!   "!TARGET_Z10"
    "#"
    "&& reload_completed"
    [(parallel
***************
*** 3333,3346 ****
    operands[3] = GEN_INT (mask);
  })
  
! (define_insn_and_split "*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")
  		          (const_int 0)))
     (clobber (reg:CC CC_REGNUM))]
!   "INTVAL (operands[2]) > 0
!    && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)"
    "#"
    "&& reload_completed"
    [(parallel
--- 3382,3394 ----
    operands[3] = GEN_INT (mask);
  })
  
! (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 "nonzero_shift_count_operand" "")
  		          (const_int 0)))
     (clobber (reg:CC CC_REGNUM))]
!   ""
    "#"
    "&& reload_completed"
    [(parallel
***************
*** 6067,6072 ****
--- 6115,6150 ----
       (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).

Patch hide | download patch | download mbox

diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md
index 333457d..e4632b9 100644
--- a/gcc/config/s390/predicates.md
+++ b/gcc/config/s390/predicates.md
@@ -101,6 +101,10 @@ 
   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"
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 79673d6..97c378f 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -110,5 +110,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 */
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 4e22100..52138d7 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -1308,6 +1308,22 @@  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.  */
+
+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 <= pos || rotl >= pos + len + (64 - bitsize));
+}
+
 /* 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.  */
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index b6e1535..ae004ac 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -3298,15 +3298,25 @@ 
   [(set_attr "op_type" "RS,RSY")
    (set_attr "z10prop" "z10_super_E1,z10_super_E1")])
 
+(define_insn "extzv"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+	(zero_extract:DI
+	  (match_operand:DI 1 "register_operand" "d")
+	  (match_operand 2 "const_int_operand" "")
+	  (match_operand 3 "const_int_operand" "")))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_Z10"
+  "risbg\t%0,%1,63-%3-%2,128+63,63-%3-%2"
+  [(set_attr "op_type" "RIE")
+   (set_attr "z10prop" "z10_super_E1")])
 
-(define_insn_and_split "*extzv<mode>"
+(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
@@ -3324,14 +3334,13 @@ 
   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)"
+  "!TARGET_Z10"
   "#"
   "&& reload_completed"
   [(parallel
@@ -6034,6 +6043,36 @@ 
      (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:DSI 0 "register_operand" "=d")
+	(and:DSI (lshiftrt:DSI
+		   (match_operand:DSI 1 "register_operand" "d")
+		   (match_operand:DSI 2 "nonzero_shift_count_operand" ""))
+		(match_operand:DSI 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>, 64 - 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:DSI 0 "register_operand" "=d")
+	(and:DSI (ashift:DSI
+		  (match_operand:DSI 1 "register_operand" "d")
+		  (match_operand:DSI 2 "nonzero_shift_count_operand" ""))
+		(match_operand:DSI 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).