[RS6000 2/7] Tidy rotates

Alan Modra amodra@gmail.com
Wed Jun 24 00:52:00 GMT 2015


Besides various tidies this fixes the wrong mode used for a number of
rotate pattern shift counts.  Since every other shift and rotate
pattern uses SImode for the shift count, these combine patterns won't
match anything.  The testcase exercises one of these rotate patterns.
It requires rtx_cost const_int mode fix to pass, since without that
the combine pattern is not seen as profitable.

See notes interspersed with changelog.

gcc/
	* config/rs6000/predicates.md (logical_const_operand): Correct
	comment.
	(mask_operand): Note failure to exclude masks only valid in 64-bit
	insns when used in 'T' constraint.
	* config/rs6000/rs6000.md (and<mode>3_imm_dot): Comment.
	(and<mode>3_imm_dot2): Comment.
	(and<mode>3_mask): Use 'n' constraint rather than 'T'.
May as well use 'n' as all we need is something to mop up the leftover
cases that match the operand predicate but don't match 'S'.  'T' is
ineffective as a constraint anyway.  You can't put 'T' before 'S' as
per the comment added to mask_operand.
	(and<mode>3_mask_dot): Likewise.  Remove redundant insn predicate test.
	(and<mode>3_mask_dot2): Likewise.
	(andsi3_internal0_nomc): Delete.
Covered by and<mode>3_mask and bool<mode>3, so redundant.
	(rotldi3_internal4): Use SImode for shift count.
	(rotldi3_internal5, +split): Likewise.
	(rotldi3_internal6, +split): Likewise.
	(ashldi3_internal7): Don't repeat operand predicate test covered
	by insn predicate.
includes_rldicr_lshift_p constrains the operand to a subset of
mask64_operand.
	(ashldi3_internal8, +split): Likewise.
	(ashldi3_internal9, +split): Likewise.
	* config/rs6000/rs6000.c (includes_rldic_lshift_p): Remove redundant
	CONST_INT test.  Don't reject all 1's.
All 1's is supported by the machine instructions and doesn't cause a
problem in print_operand.
	(includes_rldicr_lshift_p): Likewise.
gcc/testsuite/
    	* gcc.target/powerpc/rotmask.c: New.

diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index fd293ab..c408b0f 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -726,7 +726,7 @@
 		    && !satisfies_constraint_L (op)")))
 
 ;; Return 1 if the operand is a constant that can be used as the operand
-;; of an OR or XOR.
+;; of an AND, OR or XOR.
 (define_predicate "logical_const_operand"
   (match_code "const_int")
 {
@@ -764,7 +764,11 @@
 
   if (TARGET_POWERPC64)
     {
-      /* Fail if the mask is not 32-bit.  */
+      /* Fail if the mask is not 32-bit.  Note: If constraints are
+	 implemented using mask_operand then they will never fail this
+	 test.  const_ints are VOIDmode, which is what is seen here
+	 when called from a constraint.  When called as a predicate,
+	 the match_operand mode is seen.  */
       if (mode == DImode && (c & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0)
 	return 0;
 
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index c7c24db..5f42192 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -16444,36 +16444,30 @@ includes_rshift_p (rtx shiftop, rtx andop)
 int
 includes_rldic_lshift_p (rtx shiftop, rtx andop)
 {
-  if (GET_CODE (andop) == CONST_INT)
-    {
-      unsigned HOST_WIDE_INT c, lsb, shift_mask;
+  unsigned HOST_WIDE_INT c, lsb, shift_mask;
 
-      c = INTVAL (andop);
-      if (c == 0 || c == HOST_WIDE_INT_M1U)
-	return 0;
+  c = INTVAL (andop);
+  if (c == 0)
+    return 0;
 
-      shift_mask = HOST_WIDE_INT_M1U;
-      shift_mask <<= INTVAL (shiftop);
+  shift_mask = HOST_WIDE_INT_M1U << INTVAL (shiftop);
 
-      /* Find the least significant one bit.  */
-      lsb = c & -c;
+  /* Find the least significant one bit.  */
+  lsb = c & -c;
 
-      /* It must coincide with the LSB of the shift mask.  */
-      if (-lsb != shift_mask)
-	return 0;
+  /* It must coincide with the LSB of the shift mask.  */
+  if (-lsb != shift_mask)
+    return 0;
 
-      /* Invert to look for the next transition (if any).  */
-      c = ~c;
+  /* Invert to look for the next transition (if any).  */
+  c = ~c;
 
-      /* Remove the low group of ones (originally low group of zeros).  */
-      c &= -lsb;
+  /* Remove the low group of ones (originally low group of zeros).  */
+  c &= -lsb;
 
-      /* Again find the lsb, and check we have all 1's above.  */
-      lsb = c & -c;
-      return c == -lsb;
-    }
-  else
-    return 0;
+  /* Again find the lsb, and check we have all 1's above.  */
+  lsb = c & -c;
+  return c == -lsb;
 }
 
 /* Return 1 if ANDOP is a mask suitable for use with an rldicr insn
@@ -16483,27 +16477,21 @@ includes_rldic_lshift_p (rtx shiftop, rtx andop)
 int
 includes_rldicr_lshift_p (rtx shiftop, rtx andop)
 {
-  if (GET_CODE (andop) == CONST_INT)
-    {
-      unsigned HOST_WIDE_INT c, lsb, shift_mask;
+  unsigned HOST_WIDE_INT c, lsb, shift_mask;
 
-      shift_mask = HOST_WIDE_INT_M1U;
-      shift_mask <<= INTVAL (shiftop);
-      c = INTVAL (andop);
+  shift_mask = HOST_WIDE_INT_M1U << INTVAL (shiftop);
+  c = INTVAL (andop);
 
-      /* Find the least significant one bit.  */
-      lsb = c & -c;
-
-      /* It must be covered by the shift mask.
-	 This test also rejects c == 0.  */
-      if ((lsb & shift_mask) == 0)
-	return 0;
+  /* Find the least significant one bit.  */
+  lsb = c & -c;
 
-      /* Check we have all 1's above the transition, and reject all 1's.  */
-      return c == -lsb && lsb != 1;
-    }
-  else
+  /* It must be covered by the shift mask.
+     This test also rejects c == 0.  */
+  if ((lsb & shift_mask) == 0)
     return 0;
+
+  /* Check we have all 1's above the transition.  */
+  return c == -lsb;
 }
 
 /* Return 1 if operands will generate a valid arguments to rlwimi
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 243a151..f28d48e 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -2921,6 +2921,9 @@
   [(set_attr "type" "logical")
    (set_attr "dot" "yes")])
 
+;; Differs from and<mode>3_imm_mask_dot in that if cr0 is not allocated
+;; the splitter will need to trash cr0.  So choose and<mode>3_imm_mask_dot
+;; if possible.
 (define_insn_and_split "*and<mode>3_imm_dot"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,??y")
 	(compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r")
@@ -2947,6 +2950,9 @@
    (set_attr "dot" "yes")
    (set_attr "length" "4,8")])
 
+;; Differs from and<mode>3_imm_mask_dot2 in that if cr0 is not allocated
+;; the splitter will need to trash cr0.  So choose and<mode>3_imm_mask_dot2
+;; if possible.
 (define_insn_and_split "*and<mode>3_imm_dot2"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,??y")
 	(compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r")
@@ -3029,7 +3035,7 @@
 (define_insn "*and<mode>3_mask"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
 	(and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r")
-		 (match_operand:GPR 2 "any_mask_operand" "S,T")))]
+		 (match_operand:GPR 2 "any_mask_operand" "S,n")))]
   ""
   "@
    rldic%B2 %0,%1,0,%S2
@@ -3039,12 +3045,11 @@
 (define_insn_and_split "*and<mode>3_mask_dot"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y")
 	(compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r,r,r")
-			     (match_operand:GPR 2 "any_mask_operand" "S,T,S,T"))
+			     (match_operand:GPR 2 "any_mask_operand" "S,n,S,n"))
 		    (const_int 0)))
    (clobber (match_scratch:GPR 0 "=r,r,r,r"))]
   "(<MODE>mode == Pmode || UINTVAL (operands[2]) <= 0x7fffffff)
-   && rs6000_gen_cell_microcode
-   && !logical_const_operand (operands[2], <MODE>mode)"
+   && rs6000_gen_cell_microcode"
   "@
    rldic%B2. %0,%1,0,%S2
    rlwinm. %0,%1,0,%m2,%M2
@@ -3065,14 +3070,13 @@
 (define_insn_and_split "*and<mode>3_mask_dot2"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y")
 	(compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r,r,r")
-			     (match_operand:GPR 2 "any_mask_operand" "S,T,S,T"))
+			     (match_operand:GPR 2 "any_mask_operand" "S,n,S,n"))
 		    (const_int 0)))
    (set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,r,r")
 	(and:GPR (match_dup 1)
 		 (match_dup 2)))]
   "(<MODE>mode == Pmode || UINTVAL (operands[2]) <= 0x7fffffff)
-   && rs6000_gen_cell_microcode
-   && !logical_const_operand (operands[2], <MODE>mode)"
+   && rs6000_gen_cell_microcode"
   "@
    rldic%B2. %0,%1,0,%S2
    rlwinm. %0,%1,0,%m2,%M2
@@ -3091,18 +3095,6 @@
    (set_attr "length" "4,4,8,8")])
 
 
-
-(define_insn "andsi3_internal0_nomc"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
-        (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r")
-                (match_operand:SI 2 "and_operand" "?r,T")))]
-  "!rs6000_gen_cell_microcode"
-  "@
-   and %0,%1,%2
-   rlwinm %0,%1,0,%m2,%M2"
-  [(set_attr "type" "logical,shift")])
-
-
 ;; Handle the PowerPC64 rlwinm corner case
 
 (define_insn_and_split "*andsi3_internal6"
@@ -5786,7 +5778,7 @@
 (define_insn "*rotldi3_internal4"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
 	(and:DI (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
-			   (match_operand:DI 2 "reg_or_cint_operand" "rn"))
+			   (match_operand:SI 2 "reg_or_cint_operand" "rn"))
 		(match_operand:DI 3 "mask64_operand" "n")))]
   "TARGET_POWERPC64"
   "rld%I2c%B3 %0,%1,%H2,%S3"
@@ -5797,7 +5789,7 @@
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
 	(compare:CC (and:DI
 		     (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
-				(match_operand:DI 2 "reg_or_cint_operand" "rn,rn"))
+				(match_operand:SI 2 "reg_or_cint_operand" "rn,rn"))
 		     (match_operand:DI 3 "mask64_operand" "n,n"))
 		    (const_int 0)))
    (clobber (match_scratch:DI 4 "=r,r"))]
@@ -5814,7 +5806,7 @@
   [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
 	(compare:CC (and:DI
 		     (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
-				(match_operand:DI 2 "reg_or_cint_operand" ""))
+				(match_operand:SI 2 "reg_or_cint_operand" ""))
 		     (match_operand:DI 3 "mask64_operand" ""))
 		    (const_int 0)))
    (clobber (match_scratch:DI 4 ""))]
@@ -5832,7 +5824,7 @@
   [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
 	(compare:CC (and:DI
 		     (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
-				(match_operand:DI 2 "reg_or_cint_operand" "rn,rn"))
+				(match_operand:SI 2 "reg_or_cint_operand" "rn,rn"))
 		     (match_operand:DI 3 "mask64_operand" "n,n"))
 		    (const_int 0)))
    (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
@@ -5850,7 +5842,7 @@
   [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "")
 	(compare:CC (and:DI
 		     (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
-				(match_operand:DI 2 "reg_or_cint_operand" ""))
+				(match_operand:SI 2 "reg_or_cint_operand" ""))
 		     (match_operand:DI 3 "mask64_operand" ""))
 		    (const_int 0)))
    (set (match_operand:DI 0 "gpc_reg_operand" "")
@@ -5947,7 +5939,7 @@
   [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
 	(and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r")
 			   (match_operand:SI 2 "const_int_operand" "i"))
-		(match_operand:DI 3 "mask64_operand" "n")))]
+		(match_operand:DI 3 "const_int_operand" "n")))]
   "TARGET_POWERPC64 && includes_rldicr_lshift_p (operands[2], operands[3])"
   "rldicr %0,%1,%H2,%S3"
   [(set_attr "type" "shift")])
@@ -5957,7 +5949,7 @@
 	(compare:CC
 	 (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
 			    (match_operand:SI 2 "const_int_operand" "i,i"))
-		 (match_operand:DI 3 "mask64_operand" "n,n"))
+		 (match_operand:DI 3 "const_int_operand" "n,n"))
 	 (const_int 0)))
    (clobber (match_scratch:DI 4 "=r,r"))]
   "TARGET_64BIT && includes_rldicr_lshift_p (operands[2], operands[3])"
@@ -5973,7 +5965,7 @@
 	(compare:CC
 	 (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
 			    (match_operand:SI 2 "const_int_operand" ""))
-		 (match_operand:DI 3 "mask64_operand" ""))
+		 (match_operand:DI 3 "const_int_operand" ""))
 	 (const_int 0)))
    (clobber (match_scratch:DI 4 ""))]
   "TARGET_POWERPC64 && reload_completed
@@ -5991,7 +5983,7 @@
 	(compare:CC
 	 (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
 			    (match_operand:SI 2 "const_int_operand" "i,i"))
-		    (match_operand:DI 3 "mask64_operand" "n,n"))
+		    (match_operand:DI 3 "const_int_operand" "n,n"))
 	 (const_int 0)))
    (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
 	(and:DI (ashift:DI (match_dup 1) (match_dup 2)) (match_dup 3)))]
@@ -6008,7 +6000,7 @@
 	(compare:CC
 	 (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
 			    (match_operand:SI 2 "const_int_operand" ""))
-		 (match_operand:DI 3 "mask64_operand" ""))
+		 (match_operand:DI 3 "const_int_operand" ""))
 	 (const_int 0)))
    (set (match_operand:DI 0 "gpc_reg_operand" "")
 	(and:DI (ashift:DI (match_dup 1) (match_dup 2)) (match_dup 3)))]
diff --git a/gcc/testsuite/gcc.target/powerpc/rotmask.c b/gcc/testsuite/gcc.target/powerpc/rotmask.c
new file mode 100644
index 0000000..4d1b917
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rotmask.c
@@ -0,0 +1,8 @@
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "rotldi" } } */
+
+unsigned long f (unsigned long x)
+{
+  return ((x << 1) | (x >> 63)) & 0xffffffff;
+}

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Gcc-patches mailing list