]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ARC: Convert (signed<<31)>>31 to -(signed&1) without barrel shifter.
authorRoger Sayle <roger@nextmovesoftware.com>
Mon, 30 Oct 2023 16:21:28 +0000 (16:21 +0000)
committerRoger Sayle <roger@nextmovesoftware.com>
Mon, 30 Oct 2023 16:21:28 +0000 (16:21 +0000)
This patch optimizes PR middle-end/101955 for the ARC backend.  On ARC
CPUs with a barrel shifter, using two shifts is optimal as:

        asl_s   r0,r0,31
        asr_s   r0,r0,31

but without a barrel shifter, GCC -O2 -mcpu=em currently generates:

        and     r2,r0,1
        ror     r2,r2
        add.f   0,r2,r2
        sbc     r0,r0,r0

with this patch, we now generate the smaller, faster and non-flags
clobbering:

        bmsk_s  r0,r0,0
        neg_s   r0,r0

2023-10-30  Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog
PR middle-end/101955
* config/arc/arc.md (*extvsi_1_0): New define_insn_and_split
to convert sign extract of the least significant bit into an
AND $1 then a NEG when !TARGET_BARREL_SHIFTER.

gcc/testsuite/ChangeLog
PR middle-end/101955
* gcc.target/arc/pr101955.c: New test case.

gcc/config/arc/arc.md
gcc/testsuite/gcc.target/arc/pr101955.c [new file with mode: 0644]

index 11cd22cf1b3471ec40f7c32d4a75bdb332f22735..96ff62d56d8e8f1cfcc252c0fc79a9af2b0a5596 100644 (file)
@@ -5905,6 +5905,20 @@ archs4x, archs4xd"
                   (zero_extract:SI (match_dup 1) (match_dup 5) (match_dup 7)))])
    (match_dup 1)])
 
+;; Split sign-extension of single least significant bit as and x,$1;neg x
+(define_insn_and_split "*extvsi_1_0"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (sign_extract:SI (match_operand:SI 1 "register_operand" "0")
+                        (const_int 1)
+                        (const_int 0)))]
+  "!TARGET_BARREL_SHIFTER"
+  "#"
+  "&& 1"
+  [(set (match_dup 0) (and:SI (match_dup 1) (const_int 1)))
+   (set (match_dup 0) (neg:SI (match_dup 0)))]
+  ""
+  [(set_attr "length" "8")])
+
 (define_insn_and_split "rotlsi3_cnt1"
   [(set (match_operand:SI 0 "dest_reg_operand"            "=r")
        (rotate:SI (match_operand:SI 1 "register_operand" "r")
diff --git a/gcc/testsuite/gcc.target/arc/pr101955.c b/gcc/testsuite/gcc.target/arc/pr101955.c
new file mode 100644 (file)
index 0000000..3c66885
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcpu=em" } */
+
+int f(int a)
+{
+    return (a << 31) >> 31;
+}
+
+/* { dg-final { scan-assembler "bmsk_s\\s+r0,r0,0" } } */
+/* { dg-final { scan-assembler "neg_s\\s+r0,r0" } } */