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" } }