Patchwork [5/7] s390: Implement extzv for z10

login
register
mail settings
Submitter Richard Henderson
Date Aug. 10, 2012, 2:31 a.m.
Message ID <1344565921-27852-6-git-send-email-rth@redhat.com>
Download mbox | patch
Permalink /patch/176334/
State New
Headers show

Comments

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(-)
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

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).