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 } } */