i386: Optimize blsi followed by comparison [PR98567]
authorJakub Jelinek <jakub@redhat.com>
Thu, 7 Jan 2021 16:18:58 +0000 (17:18 +0100)
committerJakub Jelinek <jakub@redhat.com>
Thu, 7 Jan 2021 16:18:58 +0000 (17:18 +0100)
The BLSI instruction sets SF and ZF based on the result and clears OF.
CF is set to something unrelated.

The following patch optimizes BLSI followed by comparison, so we don't need
to emit a TEST insn in between.

2021-01-07  Jakub Jelinek  <jakub@redhat.com>

PR target/98567
* config/i386/i386.md (*bmi_blsi_<mode>_cmp, *bmi_blsi_<mode>_ccno):
New define_insn patterns.

* gcc.target/i386/pr98567-1.c: New test.
* gcc.target/i386/pr98567-2.c: New test.

gcc/config/i386/i386.md
gcc/testsuite/gcc.target/i386/pr98567-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr98567-2.c [new file with mode: 0644]

index 6f6af8c3cbffda7a478ebc4ff64e3b6b5eed3b61..c1023123d5c008f46acb93f76c6c38517174dcae 100644 (file)
    (set_attr "btver2_decode" "double")
    (set_attr "mode" "<MODE>")])
 
+(define_insn "*bmi_blsi_<mode>_cmp"
+  [(set (reg FLAGS_REG)
+       (compare
+         (and:SWI48
+           (neg:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "rm"))
+           (match_dup 1))
+         (const_int 0)))
+   (set (match_operand:SWI48 0 "register_operand" "=r")
+       (and:SWI48 (neg:SWI48 (match_dup 1)) (match_dup 1)))]
+   "TARGET_BMI && ix86_match_ccmode (insn, CCNOmode)"
+   "blsi\t{%1, %0|%0, %1}"
+  [(set_attr "type" "bitmanip")
+   (set_attr "btver2_decode" "double")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*bmi_blsi_<mode>_ccno"
+  [(set (reg FLAGS_REG)
+       (compare
+         (and:SWI48
+           (neg:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "rm"))
+           (match_dup 1))
+         (const_int 0)))
+   (clobber (match_scratch:SWI48 0 "=r"))]
+   "TARGET_BMI && ix86_match_ccmode (insn, CCNOmode)"
+   "blsi\t{%1, %0|%0, %1}"
+  [(set_attr "type" "bitmanip")
+   (set_attr "btver2_decode" "double")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*bmi_blsmsk_<mode>"
   [(set (match_operand:SWI48 0 "register_operand" "=r")
         (xor:SWI48
diff --git a/gcc/testsuite/gcc.target/i386/pr98567-1.c b/gcc/testsuite/gcc.target/i386/pr98567-1.c
new file mode 100644 (file)
index 0000000..ef53ec7
--- /dev/null
@@ -0,0 +1,31 @@
+/* PR target/98567 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbmi -fno-stack-protector" } */
+/* { dg-final { scan-assembler-times "\tblsi" 4 } } */
+/* { dg-final { scan-assembler-times "\tsetne\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tsete\t" 2 } } */
+/* { dg-final { scan-assembler-not "\ttest\[ld]" } } */
+
+int
+foo (unsigned long x)
+{
+  return (-x & x) == 0;
+}
+
+int
+bar (unsigned int x)
+{
+  return (-x & x) == 0;
+}
+
+int
+baz (unsigned long x)
+{
+  return (x & -x) != 0;
+}
+
+int
+qux (unsigned int x)
+{
+  return 0 != (x & -x);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr98567-2.c b/gcc/testsuite/gcc.target/i386/pr98567-2.c
new file mode 100644 (file)
index 0000000..dccb24f
--- /dev/null
@@ -0,0 +1,31 @@
+/* PR target/98567 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mbmi -fno-stack-protector" } */
+/* { dg-final { scan-assembler-times "\tblsi" 4 } } */
+/* { dg-final { scan-assembler-times "\tsetle\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tsetg\t" 2 } } */
+/* { dg-final { scan-assembler-not "\ttest\[ld]" } } */
+
+int
+foo (unsigned long x)
+{
+  return 0 >= (int) (-x & x);
+}
+
+int
+bar (unsigned int x)
+{
+  return (int) (-x & x) <= 0;
+}
+
+int
+baz (unsigned long x)
+{
+  return (int) (x & -x) > 0;
+}
+
+int
+qux (unsigned int x)
+{
+  return 0 < (int) (x & -x);
+}