This patch adds an alternative to ARC's *movsicc_insn to improve register
allocation by allowing the input operands to be swapped by reversing the
condition of the conditional move.  A example of the benefits can be
seen in the expansion of DImode shifts, where x << y currently generates

        not_s   r12,r2
        lsr_s   r3,r0
        asl_s   r1,r1,r2
        asl_s   r0,r0,r2
        lsr_s   r3,r3,r12
        btst_s  r2,5
        add_s   r1,r1,r3   ;b,b,h
        mov_s   r2,r0   ;4
        mov.eq  r2,r1
        mov_s   r1,r2   ;4
        j_s.d   [blink]
        sub.ne  r0,r0,r0

with this patch, we can now generate:

        not_s   r12,r2
        lsr_s   r3,r0
        asl_s   r1,r1,r2
        asl_s   r0,r0,r2
        lsr_s   r3,r3,r12
        btst_s  r2,5
        add_s   r1,r1,r3   ;b,b,h
        mov.ne  r1,r0
        j_s.d   [blink]
        sub.ne  r0,r0,r0

This issue is also described at
https://github.com/foss-for-synopsys-dwc-arc-processors/gcc/issues/110

Tested with a cross-compiler to arc-linux hosted on x86_64,
with no new (compile-only) regressions from make -k check.
Ok for mainline if this passes Claudiu's and/or Jeff's testing?


2024-06-22  Roger Sayle  <ro...@nextmovesoftware.com>

gcc/ChangeLog
        * config/arc/arc.md (*movsicc_insn): Add an alternative that allows
        commuting of register operands using %D to swap the condition.

gcc/testsuite/ChangeLog
        * gcc.target/arc/ashrdi-1.c: New test case.
        * gcc.target/arc/lshrdi-1.c: Likewise.
        * gcc.target/arc/shldi-1.c: Likewise.


Thanks in advance.
Roger
--

diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 9004b6085a23..a603fe213af6 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -1631,11 +1631,11 @@ archs4x, archs4xd"
   ")
 
 (define_insn "*movsicc_insn"
-  [(set (match_operand:SI 0 "dest_reg_operand" "=w,w")
+  [(set (match_operand:SI 0 "dest_reg_operand" "=w,w,w")
        (if_then_else:SI (match_operator 3 "proper_comparison_operator"
                       [(match_operand 4 "cc_register" "") (const_int 0)])
-                     (match_operand:SI 1 "nonmemory_operand" "cL,Cal")
-                     (match_operand:SI 2 "register_operand" "0,0")))]
+                       (match_operand:SI 1 "nonmemory_operand" "cL,Cal,0")
+                       (match_operand:SI 2 "register_operand" "0,0,c")))]
   ""
 {
   if (rtx_equal_p (operands[1], const0_rtx) && GET_CODE (operands[3]) == NE
@@ -1646,10 +1646,10 @@ archs4x, archs4xd"
       && rtx_equal_p (operands[1], constm1_rtx)
       && GET_CODE (operands[3]) == LTU)
     return "sbc.cs\\t%0,%0,%0";
-  return "mov.%d3\\t%0,%1";
+  return which_alternative == 2 ? "mov.%D3\\t%0,%2" : "mov.%d3\\t%0,%1";
 }
-  [(set_attr "type" "cmove,cmove")
-   (set_attr "length" "4,8")])
+  [(set_attr "type" "cmove,cmove,cmove")
+   (set_attr "length" "4,8,4")])
 
 ;; When there's a mask of a single bit, and then a compare to 0 or 1,
 ;; if the single bit is the sign bit, then GCC likes to convert this
diff --git a/gcc/testsuite/gcc.target/arc/ashrdi-1.c 
b/gcc/testsuite/gcc.target/arc/ashrdi-1.c
new file mode 100644
index 000000000000..8138752d3df8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/ashrdi-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+long long foo(long long x, int y)
+{
+  return x >> y;
+}
+
+/* { dg-final { scan-assembler-not "mov.eq" } } */
+/* { dg-final { scan-assembler-times "mov_s" 1 } } */
+/* { dg-final { scan-assembler-times "mov.ne" 2 } } */
diff --git a/gcc/testsuite/gcc.target/arc/lshrdi-1.c 
b/gcc/testsuite/gcc.target/arc/lshrdi-1.c
new file mode 100644
index 000000000000..c3106801378a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/lshrdi-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+unsigned long long foo(unsigned long long x, int y)
+{
+  return x >> y;
+}
+
+/* { dg-final { scan-assembler-not "mov_s" } } */
+/* { dg-final { scan-assembler-not "mov.eq" } } */
+/* { dg-final { scan-assembler-times "mov.ne" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arc/shldi-1.c 
b/gcc/testsuite/gcc.target/arc/shldi-1.c
new file mode 100644
index 000000000000..734e04a9ebd9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/shldi-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+long long foo(long long x, int y)
+{
+  return x << y;
+}
+
+/* { dg-final { scan-assembler-not "mov_s" } } */
+/* { dg-final { scan-assembler-not "mov.eq" } } */
+/* { dg-final { scan-assembler-times "mov.ne" 1 } } */

Reply via email to