aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilco Dijkstra <wilco.dijkstra@arm.com>2022-05-18 16:06:57 +0100
committerWilco Dijkstra <wdijkstr@arm.com>2022-05-20 15:10:38 +0100
commit48f3f27f607d3c145ed1e3ad652baac84aacdb91 (patch)
tree634988a7a0a3ca93a1c176080f168444f85723e6
parent1be715f31605976d8e4336973d3b81c5b7cea79f (diff)
AArch64: Improve rotate patterns
Improve and generalize rotate patterns. Rotates by more than half the bitwidth of a register are canonicalized to rotate left. Many existing shift patterns don't handle this case correctly, so add rotate left to the shift iterator and convert rotate left into ror during assembly output. Add missing zero_extend patterns for shifted BIC, ORN and EON. gcc/ * config/aarch64/aarch64.md (and_<SHIFT:optab><mode>3_compare0): Support rotate left. (and_<SHIFT:optab>si3_compare0_uxtw): Likewise. (<LOGICAL:optab>_<SHIFT:optab><mode>3): Likewise. (<LOGICAL:optab>_<SHIFT:optab>si3_uxtw): Likewise. (one_cmpl_<optab><mode>2): Likewise. (<LOGICAL:optab>_one_cmpl_<SHIFT:optab><mode>3): Likewise. (<LOGICAL:optab>_one_cmpl_<SHIFT:optab>sidi_uxtw): New pattern. (eor_one_cmpl_<SHIFT:optab><mode>3_alt): Support rotate left. (eor_one_cmpl_<SHIFT:optab>sidi3_alt_ze): Likewise. (and_one_cmpl_<SHIFT:optab><mode>3_compare0): Likewise. (and_one_cmpl_<SHIFT:optab>si3_compare0_uxtw): Likewise. (and_one_cmpl_<SHIFT:optab><mode>3_compare0_no_reuse): Likewise. (and_<SHIFT:optab><mode>3nr_compare0): Likewise. (*<optab>si3_insn_uxtw): Use SHIFT_no_rotate. (rolsi3_insn_uxtw): New pattern. * config/aarch64/iterators.md (SHIFT): Add rotate left. (SHIFT_no_rotate): Add new iterator. (SHIFT:shift): Print rotate left as ror. (is_rotl): Add test for left rotate. gcc/testsuite/ * gcc.target/aarch64/ror_2.c: New test. * gcc.target/aarch64/ror_3.c: New test.
-rw-r--r--gcc/config/aarch64/aarch64.md179
-rw-r--r--gcc/config/aarch64/iterators.md11
-rw-r--r--gcc/testsuite/gcc.target/aarch64/ror_2.c205
-rw-r--r--gcc/testsuite/gcc.target/aarch64/ror_3.c131
4 files changed, 461 insertions, 65 deletions
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 2ac8d564762..acec8c11467 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -4549,7 +4549,11 @@
(set (match_operand:GPI 0 "register_operand" "=r")
(and:GPI (SHIFT:GPI (match_dup 1) (match_dup 2)) (match_dup 3)))]
""
- "ands\\t%<w>0, %<w>3, %<w>1, <SHIFT:shift> %2"
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (<sizen> - UINTVAL (operands[2]));
+ return "ands\\t%<w>0, %<w>3, %<w>1, <SHIFT:shift> %2";
+}
[(set_attr "type" "logics_shift_imm")]
)
@@ -4566,7 +4570,11 @@
(zero_extend:DI (and:SI (SHIFT:SI (match_dup 1) (match_dup 2))
(match_dup 3))))]
""
- "ands\\t%w0, %w3, %w1, <SHIFT:shift> %2"
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (32 - UINTVAL (operands[2]));
+ return "ands\\t%w0, %w3, %w1, <SHIFT:shift> %2";
+}
[(set_attr "type" "logics_shift_imm")]
)
@@ -4577,7 +4585,11 @@
(match_operand:QI 2 "aarch64_shift_imm_<mode>" "n"))
(match_operand:GPI 3 "register_operand" "r")))]
""
- "<LOGICAL:logical>\\t%<w>0, %<w>3, %<w>1, <SHIFT:shift> %2"
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (<sizen> - UINTVAL (operands[2]));
+ return "<LOGICAL:logical>\\t%<w>0, %<w>3, %<w>1, <SHIFT:shift> %2";
+}
[(set_attr "type" "logic_shift_imm")]
)
@@ -4647,17 +4659,6 @@
"operands[3] = gen_reg_rtx (<MODE>mode);"
)
-(define_insn "*<optab>_rol<mode>3"
- [(set (match_operand:GPI 0 "register_operand" "=r")
- (LOGICAL:GPI (rotate:GPI
- (match_operand:GPI 1 "register_operand" "r")
- (match_operand:QI 2 "aarch64_shift_imm_<mode>" "n"))
- (match_operand:GPI 3 "register_operand" "r")))]
- ""
- "<logical>\\t%<w>0, %<w>3, %<w>1, ror #(<sizen> - %2)"
- [(set_attr "type" "logic_shift_imm")]
-)
-
;; zero_extend versions of above
(define_insn "*<LOGICAL:optab>_<SHIFT:optab>si3_uxtw"
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -4667,19 +4668,11 @@
(match_operand:QI 2 "aarch64_shift_imm_si" "n"))
(match_operand:SI 3 "register_operand" "r"))))]
""
- "<LOGICAL:logical>\\t%w0, %w3, %w1, <SHIFT:shift> %2"
- [(set_attr "type" "logic_shift_imm")]
-)
-
-(define_insn "*<optab>_rolsi3_uxtw"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (zero_extend:DI
- (LOGICAL:SI (rotate:SI
- (match_operand:SI 1 "register_operand" "r")
- (match_operand:QI 2 "aarch64_shift_imm_si" "n"))
- (match_operand:SI 3 "register_operand" "r"))))]
- ""
- "<logical>\\t%w0, %w3, %w1, ror #(32 - %2)"
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (32 - UINTVAL (operands[2]));
+ return "<LOGICAL:logical>\\t%w0, %w3, %w1, <SHIFT:shift> %2";
+}
[(set_attr "type" "logic_shift_imm")]
)
@@ -4708,7 +4701,11 @@
(not:GPI (SHIFT:GPI (match_operand:GPI 1 "register_operand" "r")
(match_operand:QI 2 "aarch64_shift_imm_<mode>" "n"))))]
""
- "mvn\\t%<w>0, %<w>1, <shift> %2"
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (<sizen> - UINTVAL (operands[2]));
+ return "mvn\\t%<w>0, %<w>1, <shift> %2";
+}
[(set_attr "type" "logic_shift_imm")]
)
@@ -4815,7 +4812,28 @@
(match_operand:QI 2 "aarch64_shift_imm_<mode>" "n")))
(match_operand:GPI 3 "register_operand" "r")))]
""
- "<LOGICAL:nlogical>\\t%<w>0, %<w>3, %<w>1, <SHIFT:shift> %2"
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (<sizen> - UINTVAL (operands[2]));
+ return "<LOGICAL:nlogical>\\t%<w>0, %<w>3, %<w>1, <SHIFT:shift> %2";
+}
+ [(set_attr "type" "logic_shift_imm")]
+)
+
+;; Zero-extend version of the above.
+(define_insn "<LOGICAL:optab>_one_cmpl_<SHIFT:optab>sidi_uxtw"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (LOGICAL:SI (not:SI
+ (SHIFT:SI
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:QI 2 "aarch64_shift_imm_si" "n")))
+ (match_operand:SI 3 "register_operand" "r"))))]
+ ""
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (32 - UINTVAL (operands[2]));
+ return "<LOGICAL:nlogical>\\t%w0, %w3, %w1, <SHIFT:shift> %2";
+}
[(set_attr "type" "logic_shift_imm")]
)
@@ -4827,7 +4845,11 @@
(match_operand:QI 2 "aarch64_shift_imm_<mode>" "n"))
(match_operand:GPI 3 "register_operand" "r"))))]
""
- "eon\\t%<w>0, %<w>3, %<w>1, <SHIFT:shift> %2"
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (<sizen> - UINTVAL (operands[2]));
+ return "eon\\t%<w>0, %<w>3, %<w>1, <SHIFT:shift> %2";
+}
[(set_attr "type" "logic_shift_imm")]
)
@@ -4841,7 +4863,11 @@
(match_operand:QI 2 "aarch64_shift_imm_si" "n"))
(match_operand:SI 3 "register_operand" "r")))))]
""
- "eon\\t%w0, %w3, %w1, <SHIFT:shift> %2"
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (32 - UINTVAL (operands[2]));
+ return "eon\\t%w0, %w3, %w1, <SHIFT:shift> %2";
+}
[(set_attr "type" "logic_shift_imm")]
)
@@ -4859,7 +4885,11 @@
(SHIFT:GPI
(match_dup 1) (match_dup 2))) (match_dup 3)))]
""
- "bics\\t%<w>0, %<w>3, %<w>1, <SHIFT:shift> %2"
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (<sizen> - UINTVAL (operands[2]));
+ return "bics\\t%<w>0, %<w>3, %<w>1, <SHIFT:shift> %2";
+}
[(set_attr "type" "logics_shift_imm")]
)
@@ -4878,7 +4908,11 @@
(not:SI
(SHIFT:SI (match_dup 1) (match_dup 2))) (match_dup 3))))]
""
- "bics\\t%w0, %w3, %w1, <SHIFT:shift> %2"
+{
+ if (<SHIFT:is_rotl>)
+ operands[2] = GEN_INT (32 - UINTVAL (operands[2]));
+ return "bics\\t%w0, %w3, %w1, <SHIFT:shift> %2";
+}
[(set_attr "type" "logics_shift_imm")]
)
@@ -4892,7 +4926,11 @@
(match_operand:GPI 2 "register_operand" "r"))
(const_int 0)))]
""
- "bics\\t<w>zr, %<w>2, %<w>0, <SHIFT:shift> %1"
+{
+ if (<SHIFT:is_rotl>)
+ operands[1] = GEN_INT (<sizen> - UINTVAL (operands[1]));
+ return "bics\\t<w>zr, %<w>2, %<w>0, <SHIFT:shift> %1";
+}
[(set_attr "type" "logics_shift_imm")]
)
@@ -5066,7 +5104,11 @@
(match_operand:GPI 2 "register_operand" "r"))
(const_int 0)))]
""
- "tst\\t%<w>2, %<w>0, <SHIFT:shift> %1"
+{
+ if (<SHIFT:is_rotl>)
+ operands[1] = GEN_INT (<sizen> - UINTVAL (operands[1]));
+ return "tst\\t%<w>2, %<w>0, <SHIFT:shift> %1";
+}
[(set_attr "type" "logics_shift_imm")]
)
@@ -5467,10 +5509,22 @@
[(set_attr "type" "rotate_imm,shift_reg")]
)
-;; zero_extend version of above
+(define_insn "*rol<mode>3_insn"
+ [(set (match_operand:GPI 0 "register_operand" "=r")
+ (rotate:GPI (match_operand:GPI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "n")))]
+ "UINTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)"
+{
+ operands[3] = GEN_INT (<sizen> - UINTVAL (operands[2]));
+ return "ror\\t%<w>0, %<w>1, %3";
+}
+ [(set_attr "type" "rotate_imm")]
+)
+
+;; zero_extend version of shifts
(define_insn "*<optab>si3_insn_uxtw"
[(set (match_operand:DI 0 "register_operand" "=r,r")
- (zero_extend:DI (SHIFT:SI
+ (zero_extend:DI (SHIFT_no_rotate:SI
(match_operand:SI 1 "register_operand" "r,r")
(match_operand:QI 2 "aarch64_reg_or_shift_imm_si" "Uss,r"))))]
""
@@ -5480,6 +5534,31 @@
[(set_attr "type" "bfx,shift_reg")]
)
+;; zero_extend version of rotate right
+(define_insn "*rorsi3_insn_uxtw"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI
+ (rotatert:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "n"))))]
+ "UINTVAL (operands[2]) < 32"
+ "ror\\t%w0, %w1, %2"
+ [(set_attr "type" "rotate_imm")]
+)
+
+;; zero_extend version of rotate left
+(define_insn "*rolsi3_insn_uxtw"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI
+ (rotate:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "n"))))]
+ "UINTVAL (operands[2]) < 32"
+{
+ operands[2] = GEN_INT (32 - UINTVAL (operands[2]));
+ return "ror\\t%w0, %w1, %2";
+}
+ [(set_attr "type" "rotate_imm")]
+)
+
(define_insn "*<optab><mode>3_insn"
[(set (match_operand:SHORT 0 "register_operand" "=r")
(ASHIFT:SHORT (match_operand:SHORT 1 "register_operand" "r")
@@ -5562,32 +5641,6 @@
[(set_attr "type" "rotate_imm")]
)
-(define_insn "*ror<mode>3_insn"
- [(set (match_operand:GPI 0 "register_operand" "=r")
- (rotate:GPI (match_operand:GPI 1 "register_operand" "r")
- (match_operand 2 "const_int_operand" "n")))]
- "UINTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)"
-{
- operands[3] = GEN_INT (<sizen> - UINTVAL (operands[2]));
- return "ror\\t%<w>0, %<w>1, %3";
-}
- [(set_attr "type" "rotate_imm")]
-)
-
-;; zero_extend version of the above
-(define_insn "*rorsi3_insn_uxtw"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (zero_extend:DI
- (rotate:SI (match_operand:SI 1 "register_operand" "r")
- (match_operand 2 "const_int_operand" "n"))))]
- "UINTVAL (operands[2]) < 32"
-{
- operands[3] = GEN_INT (32 - UINTVAL (operands[2]));
- return "ror\\t%w0, %w1, %3";
-}
- [(set_attr "type" "rotate_imm")]
-)
-
(define_insn "*<ANY_EXTEND:optab><GPI:mode>_ashl<SHORT:mode>"
[(set (match_operand:GPI 0 "register_operand" "=r")
(ANY_EXTEND:GPI
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 1c1048368f0..1be6a915d9f 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -2119,7 +2119,10 @@
;; -------------------------------------------------------------------
;; This code iterator allows the various shifts supported on the core
-(define_code_iterator SHIFT [ashift ashiftrt lshiftrt rotatert])
+(define_code_iterator SHIFT [ashift ashiftrt lshiftrt rotatert rotate])
+
+;; This code iterator allows all shifts except for rotates.
+(define_code_iterator SHIFT_no_rotate [ashift ashiftrt lshiftrt])
;; This code iterator allows the shifts supported in arithmetic instructions
(define_code_iterator ASHIFT [ashift ashiftrt lshiftrt])
@@ -2249,6 +2252,7 @@
(ashiftrt "ashr")
(lshiftrt "lshr")
(rotatert "rotr")
+ (rotate "rotl")
(sign_extend "extend")
(zero_extend "zero_extend")
(sign_extract "extv")
@@ -2338,7 +2342,10 @@
;; Similar for the instruction mnemonics
(define_code_attr shift [(ashift "lsl") (ashiftrt "asr")
- (lshiftrt "lsr") (rotatert "ror")])
+ (lshiftrt "lsr") (rotatert "ror") (rotate "ror")])
+;; True if shift is rotate left.
+(define_code_attr is_rotl [(ashift "0") (ashiftrt "0")
+ (lshiftrt "0") (rotatert "0") (rotate "1")])
;; Op prefix for shift right and accumulate.
(define_code_attr sra_op [(ashiftrt "s") (lshiftrt "u")])
diff --git a/gcc/testsuite/gcc.target/aarch64/ror_2.c b/gcc/testsuite/gcc.target/aarch64/ror_2.c
new file mode 100644
index 00000000000..796c1222230
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ror_2.c
@@ -0,0 +1,205 @@
+/* { dg-options "-O2 --save-temps" } */
+/* { dg-do assemble } */
+
+
+#define ROR(X,Y) ((X >> Y) | (X << (32 - Y)))
+
+unsigned
+ror1 (unsigned x)
+{
+ /* { dg-final { scan-assembler "ror\tw\[0-9\]+, w\[0-9\]+, 3\n" } } */
+ return ROR (x, 3);
+}
+
+unsigned
+ror2 (unsigned x)
+{
+ /* { dg-final { scan-assembler "ror\tw\[0-9\]+, w\[0-9\]+, 17\n" } } */
+ return ROR (x, 17);
+}
+
+unsigned long
+ror3 (unsigned x)
+{
+ /* { dg-final { scan-assembler "ror\tw\[0-9\]+, w\[0-9\]+, 2\n" } } */
+ return (unsigned long) ROR (x, 2);
+}
+
+unsigned long
+ror4 (unsigned x)
+{
+ /* { dg-final { scan-assembler "ror\tw\[0-9\]+, w\[0-9\]+, 26\n" } } */
+ return (unsigned long) ROR (x, 26);
+}
+
+unsigned
+and1 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 13\n" } } */
+ return x & ROR (y, 13);
+}
+
+unsigned
+and2 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 23\n" } } */
+ return x & ROR (y, 23);
+}
+
+unsigned long
+and3 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "and\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 12\n" } } */
+ return x & (unsigned long) ROR (y, 12);
+}
+
+unsigned
+bic1 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 11\n" } } */
+ return x & ~ROR (y, 11);
+}
+
+unsigned
+bic2 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 17\n" } } */
+ return x & ~ROR (y, 17);
+}
+
+unsigned long
+bic3 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "bic\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 22\n" } } */
+ return (unsigned long) x & ~ROR (y, 22);
+}
+
+unsigned
+orr1 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "orr\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 5\n" } } */
+ return x | ROR (y, 5);
+}
+
+unsigned
+orr2 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "orr\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 25\n" } } */
+ return x | ROR (y, 25);
+}
+
+unsigned long
+orr3 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "orr\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 24\n" } } */
+ return (unsigned long)x | ROR (y, 24);
+}
+
+unsigned
+orn1 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "orn\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 3\n" } } */
+ return x | ~ROR (y, 3);
+}
+
+unsigned
+orn2 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "orn\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 30\n" } } */
+ return x | ~ROR (y, 30);
+}
+
+unsigned long
+orn3 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "orn\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 9\n" } } */
+ return x | (unsigned long) ~ROR (y, 9);
+}
+
+unsigned
+eor1 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "eor\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 9\n" } } */
+ return x ^ ROR (y, 9);
+}
+
+unsigned
+eor2 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "eor\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 31\n" } } */
+ return x ^ ROR (y, 31);
+}
+
+unsigned long
+eor3 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "eor\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 28\n" } } */
+ return (unsigned long) x ^ ROR (y, 28);
+}
+
+unsigned
+eon1 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "eon\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 1\n" } } */
+ return x ^ ~ROR (y, 1);
+}
+
+unsigned
+eon2 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "eon\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 18\n" } } */
+ return x ^ ~ROR (y, 18);
+}
+
+unsigned long
+eon3 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "eon\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, ror 19\n" } } */
+ return x ^ (unsigned long) ~ROR (y, 19);
+}
+
+int
+tst1 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+, ror 8\n" } } */
+ return (x & ROR (y, 8)) == 0;
+}
+
+int
+tst2 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+, ror 20\n" } } */
+ return (x & ROR (y, 20)) == 0;
+}
+
+int
+tst3 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "tst\tw\[0-9\]+, w\[0-9\]+, ror 20\n" } } */
+ return ((unsigned long)x & ROR (y, 20)) == 0;
+}
+
+int
+bics1 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "bics\twzr, w\[0-9\]+, w\[0-9\]+, ror 10\n" } } */
+ return (x & ~ROR (y, 10)) == 0;
+}
+
+int
+bics2 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "bics\twzr, w\[0-9\]+, w\[0-9\]+, ror 21\n" } } */
+ return (x & ~ROR (y, 21)) == 0;
+}
+
+int
+bics3 (unsigned x, unsigned y)
+{
+ /* { dg-final { scan-assembler "bics\twzr, w\[0-9\]+, w\[0-9\]+, ror 21\n" } } */
+ return (x & (unsigned long)~ROR (y, 21)) == 0;
+}
+
+/* { dg-final { scan-assembler-not "cmp" } } */
+/* { dg-final { scan-assembler-not "mvn" } } */
+/* { dg-final { scan-assembler-not "uxtw" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/ror_3.c b/gcc/testsuite/gcc.target/aarch64/ror_3.c
new file mode 100644
index 00000000000..484beecf886
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/ror_3.c
@@ -0,0 +1,131 @@
+/* { dg-options "-O2 --save-temps" } */
+/* { dg-do assemble } */
+
+
+#define ROR(X,Y) ((X >> Y) | (X << (64 - Y)))
+
+unsigned long
+ror1 (unsigned long x)
+{
+ /* { dg-final { scan-assembler "ror\tx\[0-9\]+, x\[0-9\]+, 3\n" } } */
+ return ROR (x, 3);
+}
+
+unsigned long
+ror2 (unsigned long x)
+{
+ /* { dg-final { scan-assembler "ror\tx\[0-9\]+, x\[0-9\]+, 37\n" } } */
+ return ROR (x, 37);
+}
+
+unsigned long
+and1 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 13\n" } } */
+ return x & ROR (y, 13);
+}
+
+unsigned long
+and2 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 33\n" } } */
+ return x & ROR (y, 33);
+}
+
+unsigned long
+bic1 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "bic\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 11\n" } } */
+ return x & ~ROR (y, 11);
+}
+
+unsigned long
+bic2 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "bic\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 47\n" } } */
+ return x & ~ROR (y, 47);
+}
+
+unsigned long
+orr1 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "orr\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 5\n" } } */
+ return x | ROR (y, 5);
+}
+
+unsigned long
+orr2 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "orr\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 35\n" } } */
+ return x | ROR (y, 35);
+}
+
+unsigned long
+orn1 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "orn\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 3\n" } } */
+ return x | ~ROR (y, 3);
+}
+
+unsigned long
+orn2 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "orn\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 39\n" } } */
+ return x | ~ROR (y, 39);
+}
+
+unsigned long
+eor1 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "eor\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 9\n" } } */
+ return x ^ ROR (y, 9);
+}
+
+unsigned long
+eor2 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "eor\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 41\n" } } */
+ return x ^ ROR (y, 41);
+}
+
+unsigned long
+eon1 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "eon\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 1\n" } } */
+ return x ^ ~ROR (y, 1);
+}
+
+unsigned long
+eon2 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "eon\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, ror 38\n" } } */
+ return x ^ ~ROR (y, 38);
+}
+
+unsigned long
+tst1 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "tst\tx\[0-9\]+, x\[0-9\]+, ror 8\n" } } */
+ return (x & ROR (y, 8)) == 0;
+}
+
+unsigned long
+tst2 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "tst\tx\[0-9\]+, x\[0-9\]+, ror 50\n" } } */
+ return (x & ROR (y, 50)) == 0;
+}
+
+unsigned long
+bics1 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "bics\txzr, x\[0-9\]+, x\[0-9\]+, ror 10\n" } } */
+ return (x & ~ROR (y, 10)) == 0;
+}
+
+unsigned long
+bics2 (unsigned long x, unsigned long y)
+{
+ /* { dg-final { scan-assembler "bics\txzr, x\[0-9\]+, x\[0-9\]+, ror 62\n" } } */
+ return (x & ~ROR (y, 62)) == 0;
+}