Hi!

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.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

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

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

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

--- gcc/config/i386/i386.md.jj  2021-01-04 10:25:45.072163178 +0100
+++ gcc/config/i386/i386.md     2021-01-06 17:49:13.251966127 +0100
@@ -14568,6 +14568,21 @@ (define_insn "*bmi_blsi_<mode>"
    (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_blsmsk_<mode>"
   [(set (match_operand:SWI48 0 "register_operand" "=r")
         (xor:SWI48
--- gcc/testsuite/gcc.target/i386/pr98567-1.c.jj        2021-01-07 
09:44:54.109343371 +0100
+++ gcc/testsuite/gcc.target/i386/pr98567-1.c   2021-01-07 09:44:54.109343371 
+0100
@@ -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);
+}
--- gcc/testsuite/gcc.target/i386/pr98567-2.c.jj        2021-01-07 
09:45:23.037015732 +0100
+++ gcc/testsuite/gcc.target/i386/pr98567-2.c   2021-01-07 09:51:58.348539820 
+0100
@@ -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);
+}

        Jakub

Reply via email to