aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2021-01-07 17:18:58 +0100
committerJakub Jelinek <jakub@redhat.com>2021-01-07 17:18:58 +0100
commit6bca2ebf10654b8beb5c5737c8652e8262901294 (patch)
treea85478c609d106005d7b0910b3d5fd49213a1331 /gcc
parent0f9d2c1a318ed30a66b75bd6b7fa3dc3630e362e (diff)
downloadgcc-6bca2ebf10654b8beb5c5737c8652e8262901294.zip
gcc-6bca2ebf10654b8beb5c5737c8652e8262901294.tar.gz
gcc-6bca2ebf10654b8beb5c5737c8652e8262901294.tar.bz2
i386: Optimize blsi followed by comparison [PR98567]
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/i386/i386.md29
-rw-r--r--gcc/testsuite/gcc.target/i386/pr98567-1.c31
-rw-r--r--gcc/testsuite/gcc.target/i386/pr98567-2.c31
3 files changed, 91 insertions, 0 deletions
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 6f6af8c..c102312 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -14563,6 +14563,35 @@
(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
index 0000000..ef53ec7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr98567-1.c
@@ -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
index 0000000..dccb24f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr98567-2.c
@@ -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);
+}