Exclude left rotations from the masked register-count patterns that
emit ROR without negating the count.

gcc/ChangeLog:

        * config/aarch64/aarch64.md
        (*aarch64_<optab>_reg_<mode>3_mask1): Exclude left rotations.
        (*aarch64_<optab>_reg_di3_mask2): Likewise.
        * config/aarch64/aarch64.cc
        (selftest::aarch64_test_masked_rotate): New function.
        (selftest::aarch64_run_selftests): Call it.

---
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 
ef39942f8fb202b1cf8371d45cb4d35847f9c288..50a8c7b83d4fc4c6e6e8c3aa00d259b9217081e1
 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -6163,7 +6163,8 @@
          (match_operator 4 "subreg_lowpart_operator"
           [(and:GPI (match_operand:GPI 2 "register_operand" "r")
                     (match_operand 3 "const_int_operand" "n"))])))]
-  "(~INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1)) == 0"
+  "!<is_rotl>
+   && (~INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1)) == 0"
   "<shift>\t%<w>0, %<w>1, %<w>2"
   [(set_attr "type" "shift_reg")]
 )
@@ -6227,7 +6228,8 @@
          (match_operator 4 "subreg_lowpart_operator"
           [(and:SI (match_operand:SI 2 "register_operand" "r")
                    (match_operand 3 "const_int_operand" "n"))])))]
-  "((~INTVAL (operands[3]) & (GET_MODE_BITSIZE (DImode) - 1)) == 0)"
+  "!<is_rotl>
+   && ((~INTVAL (operands[3]) & (GET_MODE_BITSIZE (DImode) - 1)) == 0)"
 {
   rtx xop[3];
   xop[0] = operands[0];
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 
730a1fee835982df6627c870bc6849776e82642d..b4dae29cf4b427a6435417155ff4c2cb79ad3714
 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -34417,6 +34417,35 @@
 
 extern void aarch64_json_tunings_tests ();
 
+/* Masked register counts must not turn a left rotate into a right rotate.  */
+
+static void
+aarch64_test_masked_rotate ()
+{
+  for (auto mode : { SImode, DImode })
+    for (auto count_mode : { SImode, DImode })
+      {
+       if (mode == SImode && count_mode == DImode)
+         continue;
+       rtx dest = gen_rtx_REG (mode, LAST_VIRTUAL_REGISTER + 1);
+       rtx value = gen_rtx_REG (mode, LAST_VIRTUAL_REGISTER + 2);
+       rtx count = gen_rtx_REG (count_mode, LAST_VIRTUAL_REGISTER + 3);
+       count = gen_rtx_AND (count_mode, count,
+                            GEN_INT (GET_MODE_BITSIZE (mode) - 1));
+       count = gen_rtx_SUBREG (QImode, count,
+                               subreg_lowpart_offset (QImode, count_mode));
+       for (auto code : { ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, ROTATE })
+         {
+           rtx op = gen_rtx_fmt_ee (code, mode, value, count);
+           int icode = recog (gen_rtx_SET (dest, op), nullptr, nullptr);
+           if (code == ROTATE)
+             ASSERT_EQ (icode, -1);
+           else
+             ASSERT_TRUE (icode >= 0);
+         }
+      }
+}
+
 /* Run all target-specific selftests.  */
 
 static void
@@ -34427,6 +34456,7 @@
   aarch64_test_sysreg_encoding_clashes ();
   aarch64_test_sve_folding ();
   aarch64_json_tunings_tests ();
+  aarch64_test_masked_rotate ();
 }
 
 } // namespace selftest

Reply via email to