Hi,

the Interfaces package of the Ada library defines a pair of rotation operators

   function Rotate_Left  (Value : Unsigned_n; Amount : Natural)
      return Unsigned_n;
   function Rotate_Right (Value : Unsigned_n; Amount : Natural)
      return Unsigned_n;

on modular (aka unsigned) types of n bits.  The translation in GENERIC for the 
Rotate_Left on a 32-bit modular type is:

  Value r<< ((UNSIGNED_32) Amount & 31)

and the masking is present all the way down to the assembly at -O2:

        rlwinm 4,4,0,27,31
        rotlw 3,3,4

Now this masking is redundant since it's done by the hardware so it would be 
nice to get rid of it.  I have attached a couple of patches to that effect: 
the first one adds new instructions while the second one only adds splitters.

Tested on PowerPC64/Linux, OK (which one) for the mainline?


2020-09-29  Eric Botcazou  <ebotca...@adacore.com>

        * config/rs6000/rs6000.md (*rotl<mode>3_mask): New.
        (*rotlsi3_mask_64): Likewise.
        (*rotl<mode>3_dot): Change to use P mode iterator.
        (*rotl<mode>3_mask_dot): New.
        (*rotl<mode>3_dot2): Change to use P mode iterator.
        (*rotl<mode>3_mask_dot2): New.


2020-09-29  Eric Botcazou  <ebotca...@adacore.com>

        * gnat.dg/rotate1.adb: New test.

-- 
Eric Botcazou
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 694ff70635e..b6c185b80b7 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -4306,6 +4306,18 @@
   [(set_attr "type" "shift")
    (set_attr "maybe_var_shift" "yes")])
 
+;; Avoid useless masking of count operand
+(define_insn "*rotl<mode>3_mask"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+	(rotate:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
+		    (and:GPR (match_operand:GPR 2 "gpc_reg_operand" "r")
+			     (match_operand:GPR 3 "const_int_operand" "n"))))]
+  "(UINTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1))
+   == (unsigned HOST_WIDE_INT) (GET_MODE_BITSIZE (<MODE>mode) - 1)"
+  "rotl<wd>%I2 %0,%1,%<hH>2"
+  [(set_attr "type" "shift")
+   (set_attr "var_shift" "yes")])
+
 (define_insn "*rotlsi3_64"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
 	(zero_extend:DI
@@ -4316,20 +4328,34 @@
   [(set_attr "type" "shift")
    (set_attr "maybe_var_shift" "yes")])
 
+;; Avoid useless masking of count operand
+(define_insn "*rotlsi3_mask_64"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+	(zero_extend:DI
+	    (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+		       (and:SI (match_operand:SI 2 "gpc_reg_operand" "r")
+			       (match_operand:SI 3 "const_int_operand" "n")))))]
+  "TARGET_POWERPC64
+   && (UINTVAL (operands[3]) & (GET_MODE_BITSIZE (SImode) - 1))
+      == (unsigned HOST_WIDE_INT) (GET_MODE_BITSIZE (SImode) - 1)"
+  "rotlw%I2 %0,%1,%h2"
+  [(set_attr "type" "shift")
+   (set_attr "var_shift" "yes")])
+
 (define_insn_and_split "*rotl<mode>3_dot"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
-	(compare:CC (rotate:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
-				(match_operand:SI 2 "reg_or_cint_operand" "rn,rn"))
+	(compare:CC (rotate:P (match_operand:P 1 "gpc_reg_operand" "r,r")
+			      (match_operand:SI 2 "reg_or_cint_operand" "rn,rn"))
 		    (const_int 0)))
-   (clobber (match_scratch:GPR 0 "=r,r"))]
-  "<MODE>mode == Pmode"
+   (clobber (match_scratch:P 0 "=r,r"))]
+  ""
   "@
    rotl<wd>%I2. %0,%1,%<hH>2
    #"
-  "&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
+  "reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
   [(set (match_dup 0)
-	(rotate:GPR (match_dup 1)
-		    (match_dup 2)))
+	(rotate:P (match_dup 1)
+		  (match_dup 2)))
    (set (match_dup 3)
 	(compare:CC (match_dup 0)
 		    (const_int 0)))]
@@ -4339,22 +4365,49 @@
    (set_attr "dot" "yes")
    (set_attr "length" "4,8")])
 
+;; Avoid useless masking of count operand
+(define_insn_and_split "*rotl<mode>3_mask_dot"
+  [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+	(compare:CC (rotate:P (match_operand:P 1 "gpc_reg_operand" "r,r")
+			      (and:P (match_operand:P 2 "gpc_reg_operand" "r,r")
+				     (match_operand:P 3 "const_int_operand" "n,n")))
+		    (const_int 0)))
+   (clobber (match_scratch:P 0 "=r,r"))]
+  "(UINTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1))
+   == (unsigned HOST_WIDE_INT) (GET_MODE_BITSIZE (<MODE>mode) - 1)"
+  "@
+   rotl<wd>%I2. %0,%1,%<hH>2
+   #"
+  "&& reload_completed && cc_reg_not_cr0_operand (operands[4], CCmode)"
+  [(set (match_dup 0)
+	(rotate:P (match_dup 1)
+		  (and:P (match_dup 2)
+			 (match_dup 3))))
+   (set (match_dup 4)
+	(compare:CC (match_dup 0)
+		    (const_int 0)))]
+  ""
+  [(set_attr "type" "shift")
+   (set_attr "var_shift" "yes")
+   (set_attr "dot" "yes")
+   (set_attr "length" "4,8")])
+
 (define_insn_and_split "*rotl<mode>3_dot2"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
-	(compare:CC (rotate:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
-				(match_operand:SI 2 "reg_or_cint_operand" "rn,rn"))
+	(compare:CC (rotate:P (match_operand:P 1 "gpc_reg_operand" "r,r")
+			      (match_operand:SI 2 "reg_or_cint_operand" "rn,rn"))
 		    (const_int 0)))
-   (set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
-	(rotate:GPR (match_dup 1)
-		    (match_dup 2)))]
-  "<MODE>mode == Pmode"
+   (set (match_operand:P 0 "gpc_reg_operand" "=r,r")
+	(rotate:P (match_dup 1)
+		  (match_dup 2)))]
+  ""
   "@
    rotl<wd>%I2. %0,%1,%<hH>2
    #"
   "&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
   [(set (match_dup 0)
-	(rotate:GPR (match_dup 1)
-		    (match_dup 2)))
+	(rotate:P (match_dup 1)
+		  (match_dup 2)))
    (set (match_dup 3)
 	(compare:CC (match_dup 0)
 		    (const_int 0)))]
@@ -4364,6 +4417,36 @@
    (set_attr "dot" "yes")
    (set_attr "length" "4,8")])
 
+;; Avoid useless masking of count operand
+(define_insn_and_split "*rotl<mode>3_mask_dot2"
+  [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+	(compare:CC (rotate:P (match_operand:P 1 "gpc_reg_operand" "r,r")
+			      (and:P (match_operand:P 2 "gpc_reg_operand" "r,r")
+				     (match_operand:P 3 "const_int_operand" "n,n")))
+		    (const_int 0)))
+   (set (match_operand:P 0 "gpc_reg_operand" "=r,r")
+	(rotate:P (match_dup 1)
+		  (and:P (match_dup 2)
+			 (match_dup 3))))]
+  "(UINTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1))
+   == (unsigned HOST_WIDE_INT) (GET_MODE_BITSIZE (<MODE>mode) - 1)"
+  "@
+   rotl<wd>%I2. %0,%1,%<hH>2
+   #"
+  "&& reload_completed && cc_reg_not_cr0_operand (operands[4], CCmode)"
+  [(set (match_dup 0)
+	(rotate:P (match_dup 1)
+		  (and:P (match_dup 2)
+			 (match_dup 3))))
+   (set (match_dup 4)
+	(compare:CC (match_dup 0)
+		    (const_int 0)))]
+  ""
+  [(set_attr "type" "shift")
+   (set_attr "var_shift" "yes")
+   (set_attr "dot" "yes")
+   (set_attr "length" "4,8")])
+
 
 (define_insn "ashl<mode>3"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 694ff70635e..1689137a0de 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -4306,6 +4306,23 @@
   [(set_attr "type" "shift")
    (set_attr "maybe_var_shift" "yes")])
 
+;; Avoid useless masking of count operand
+(define_insn_and_split "*rotl<mode>3_mask"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+	(rotate:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
+		    (and:GPR (match_operand:GPR 2 "gpc_reg_operand" "r")
+			     (match_operand:GPR 3 "const_int_operand" "n"))))]
+  "(UINTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1))
+   == (unsigned HOST_WIDE_INT) (GET_MODE_BITSIZE (<MODE>mode) - 1)"
+  "#"
+  "&& 1"
+  [(set (match_dup 0)
+	(rotate:GPR (match_dup 1)
+		    (match_dup 2)))]
+  ""
+  [(set_attr "type" "shift")
+   (set_attr "var_shift" "yes")])
+
 (define_insn "*rotlsi3_64"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
 	(zero_extend:DI
@@ -4316,20 +4333,40 @@
   [(set_attr "type" "shift")
    (set_attr "maybe_var_shift" "yes")])
 
+;; Avoid useless masking of count operand
+(define_insn_and_split "*rotlsi3_mask_64"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+	(zero_extend:DI
+	    (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+		       (and:SI (match_operand:SI 2 "gpc_reg_operand" "r")
+			       (match_operand:SI 3 "const_int_operand" "n")))))]
+  "TARGET_POWERPC64
+   && (UINTVAL (operands[3]) & (GET_MODE_BITSIZE (SImode) - 1))
+      == (unsigned HOST_WIDE_INT) (GET_MODE_BITSIZE (SImode) - 1)"
+  "#"
+  "&& 1"
+  [(set (match_dup 0)
+	(zero_extend:DI
+	    (rotate:SI (match_dup 1)
+		       (match_dup 2))))]
+  ""
+  [(set_attr "type" "shift")
+   (set_attr "var_shift" "yes")])
+
 (define_insn_and_split "*rotl<mode>3_dot"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
-	(compare:CC (rotate:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
-				(match_operand:SI 2 "reg_or_cint_operand" "rn,rn"))
+	(compare:CC (rotate:P (match_operand:P 1 "gpc_reg_operand" "r,r")
+			      (match_operand:SI 2 "reg_or_cint_operand" "rn,rn"))
 		    (const_int 0)))
-   (clobber (match_scratch:GPR 0 "=r,r"))]
-  "<MODE>mode == Pmode"
+   (clobber (match_scratch:P 0 "=r,r"))]
+  ""
   "@
    rotl<wd>%I2. %0,%1,%<hH>2
    #"
-  "&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
+  "reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
   [(set (match_dup 0)
-	(rotate:GPR (match_dup 1)
-		    (match_dup 2)))
+	(rotate:P (match_dup 1)
+		  (match_dup 2)))
    (set (match_dup 3)
 	(compare:CC (match_dup 0)
 		    (const_int 0)))]
@@ -4339,22 +4376,46 @@
    (set_attr "dot" "yes")
    (set_attr "length" "4,8")])
 
+;; Avoid useless masking of count operand
+(define_insn_and_split "*rotl<mode>3_mask_dot"
+  [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+	(compare:CC (rotate:P (match_operand:P 1 "gpc_reg_operand" "r,r")
+			      (and:P (match_operand:P 2 "gpc_reg_operand" "r,r")
+				     (match_operand:P 3 "const_int_operand" "n,n")))
+		    (const_int 0)))
+   (clobber (match_scratch:P 0 "=r,r"))]
+  "(UINTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1))
+   == (unsigned HOST_WIDE_INT) (GET_MODE_BITSIZE (<MODE>mode) - 1)"
+  "@
+   rotl<wd>%I2. %0,%1,%<hH>2
+   #"
+  "&& reload_completed && cc_reg_not_cr0_operand (operands[4], CCmode)"
+  [(set (match_dup 0)
+	(rotate:P (match_dup 1)
+		  (match_dup 2)))
+   (set (match_dup 4)
+	(compare:CC (match_dup 0) (const_int 0)))]
+  ""
+  [(set_attr "type" "shift")
+   (set_attr "var_shift" "yes")
+   (set_attr "dot" "yes")
+   (set_attr "length" "4,8")])
+
 (define_insn_and_split "*rotl<mode>3_dot2"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
-	(compare:CC (rotate:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
-				(match_operand:SI 2 "reg_or_cint_operand" "rn,rn"))
+	(compare:CC (rotate:P (match_operand:P 1 "gpc_reg_operand" "r,r")
+			      (match_operand:SI 2 "reg_or_cint_operand" "rn,rn"))
 		    (const_int 0)))
-   (set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
-	(rotate:GPR (match_dup 1)
-		    (match_dup 2)))]
-  "<MODE>mode == Pmode"
+   (set (match_operand:P 0 "gpc_reg_operand" "=r,r")
+	(rotate:P (match_dup 1) (match_dup 2)))]
+  ""
   "@
    rotl<wd>%I2. %0,%1,%<hH>2
    #"
   "&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
   [(set (match_dup 0)
-	(rotate:GPR (match_dup 1)
-		    (match_dup 2)))
+	(rotate:P (match_dup 1)
+		  (match_dup 2)))
    (set (match_dup 3)
 	(compare:CC (match_dup 0)
 		    (const_int 0)))]
@@ -4364,6 +4425,35 @@
    (set_attr "dot" "yes")
    (set_attr "length" "4,8")])
 
+;; Avoid useless masking of count operand
+(define_insn_and_split "*rotl<mode>3_mask_dot2"
+  [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+	(compare:CC (rotate:P (match_operand:P 1 "gpc_reg_operand" "r,r")
+			      (and:P (match_operand:P 2 "gpc_reg_operand" "r,r")
+				     (match_operand:P 3 "const_int_operand" "n,n")))
+		    (const_int 0)))
+   (set (match_operand:P 0 "gpc_reg_operand" "=r,r")
+	(rotate:P (match_dup 1)
+		  (and:P (match_dup 2)
+			 (match_dup 3))))]
+  "(UINTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1))
+   == (unsigned HOST_WIDE_INT) (GET_MODE_BITSIZE (<MODE>mode) - 1)"
+  "@
+   rotl<wd>%I2. %0,%1,%<hH>2
+   #"
+  "&& reload_completed && cc_reg_not_cr0_operand (operands[4], CCmode)"
+  [(set (match_dup 0)
+	(rotate:P (match_dup 1)
+		  (match_dup 2)))
+   (set (match_dup 4)
+	(compare:CC (match_dup 0)
+		    (const_int 0)))]
+  ""
+  [(set_attr "type" "shift")
+   (set_attr "var_shift" "yes")
+   (set_attr "dot" "yes")
+   (set_attr "length" "4,8")])
+
 
 (define_insn "ashl<mode>3"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
-- { dg-do compile { target powerpc*-*-* } }
-- { dg-options "-O" }

with Interfaces; use Interfaces;

function Rotate1 (I : Unsigned_32; Count: Natural) return Unsigned_32 is
begin
  return Interfaces.Rotate_Left (I, Count);
end;

-- { dg-final { scan-assembler-not "rlwinm" } }

Reply via email to