When memchr is applied on a constant string of no more than the bytes of
a word, inline memchr by checking each byte in the constant string.
int f (int a)
{
return __builtin_memchr ("eE", a, 2) != 0;
}
is simplified to
int f (int a)
{
return (char) a == 'e' || (char) a == 'E';
}
gcc/
PR tree-optimization/103798
* match.pd (__builtin_memchr (const_str, a, N)): Inline memchr
with constant strings of no more than the bytes of a word.
gcc/testsuite/
PR tree-optimization/103798
* c-c++-common/pr103798-1.c: New test.
* c-c++-common/pr103798-2.c: Likewise.
* c-c++-common/pr103798-3.c: Likewise.
* c-c++-common/pr103798-4.c: Likewise.
* c-c++-common/pr103798-5.c: Likewise.
* c-c++-common/pr103798-6.c: Likewise.
* c-c++-common/pr103798-7.c: Likewise.
* c-c++-common/pr103798-8.c: Likewise.
---
gcc/match.pd | 136 ++++++++++++++++++++++++
gcc/testsuite/c-c++-common/pr103798-1.c | 28 +++++
gcc/testsuite/c-c++-common/pr103798-2.c | 30 ++++++
gcc/testsuite/c-c++-common/pr103798-3.c | 28 +++++
gcc/testsuite/c-c++-common/pr103798-4.c | 28 +++++
gcc/testsuite/c-c++-common/pr103798-5.c | 26 +++++
gcc/testsuite/c-c++-common/pr103798-6.c | 27 +++++
gcc/testsuite/c-c++-common/pr103798-7.c | 27 +++++
gcc/testsuite/c-c++-common/pr103798-8.c | 27 +++++
9 files changed, 357 insertions(+)
create mode 100644 gcc/testsuite/c-c++-common/pr103798-1.c
create mode 100644 gcc/testsuite/c-c++-common/pr103798-2.c
create mode 100644 gcc/testsuite/c-c++-common/pr103798-3.c
create mode 100644 gcc/testsuite/c-c++-common/pr103798-4.c
create mode 100644 gcc/testsuite/c-c++-common/pr103798-5.c
create mode 100644 gcc/testsuite/c-c++-common/pr103798-6.c
create mode 100644 gcc/testsuite/c-c++-common/pr103798-7.c
create mode 100644 gcc/testsuite/c-c++-common/pr103798-8.c
diff --git a/gcc/match.pd b/gcc/match.pd
index a63b649841b..aa4766749af 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7976,3 +7976,139 @@ and,
(match (bitwise_induction_p @0 @2 @3)
(bit_not
(nop_convert1? (bit_xor@0 (convert2? (lshift integer_onep@1 @2)) @3))))
+
+#if GIMPLE
+/* __builtin_memchr (const_str, a, N) != 0 ->
+ a == const_str[0] .. || a == const_str[N-1]
+ __builtin_memchr (const_str, a, N) == 0 ->
+ a != const_str[0] .. && a != const_str[N-1]
+ where N is less than the string size. */
+(for cmp (eq ne)
+ icmp (ne eq)
+ bit_op (bit_and bit_ior)
+ (simplify (cmp:c @0 (BUILT_IN_MEMCHR ADDR_EXPR@1 @2 INTEGER_CST@3))
+ (if (UNITS_PER_WORD <= 8
+ && CHAR_TYPE_SIZE == 8
+ && BITS_PER_UNIT == 8
+ && CHAR_BIT == 8
+ && integer_zerop (@0)
+ && !integer_zerop (@3)
+ && TREE_CODE (TREE_OPERAND (@1, 0)) == STRING_CST
+ && TREE_STRING_LENGTH (TREE_OPERAND (@1, 0)) >= 2
+ && wi::leu_p (wi::to_wide (@3), UNITS_PER_WORD)
+ && wi::ltu_p (wi::to_wide (@3),
+ TREE_STRING_LENGTH (TREE_OPERAND (@1, 0))))
+ (with
+ {
+ const char *p = TREE_STRING_POINTER (TREE_OPERAND (@1, 0));
+ unsigned HOST_WIDE_INT size = TREE_INT_CST_LOW (@3);
+ }
+ (switch
+ (if (size == 1)
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[0]); }))
+ (if (size == 2)
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[0]); })
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[1]); })))
+ (if (size == 3)
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[0]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[1]); })
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[2]); }))))
+ (if (size == 4)
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[0]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[1]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[2]); })
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[3]); })))))
+ (if (size == 5)
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[0]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[1]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[2]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[3]); })
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[4]); }))))))
+ (if (size == 6)
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[0]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[1]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[2]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[3]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[4]); })
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[5]); })))))))
+ (if (size == 7)
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[0]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[1]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[2]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[3]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[4]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[5]); })
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[6]); }))))))))
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[0]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[1]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[2]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[3]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[4]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[5]); })
+ (bit_op
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[6]); })
+ (icmp (convert:char_type_node @2)
+ { build_int_cst (char_type_node, p[7]); })))))))))))))
+#endif
diff --git a/gcc/testsuite/c-c++-common/pr103798-1.c
b/gcc/testsuite/c-c++-common/pr103798-1.c
new file mode 100644
index 00000000000..cd3edf569fc
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-1.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int
+f (char a)
+{
+ return __builtin_memchr ("a", a, 1) == 0;
+}
+
+__attribute__ ((weak))
+int
+g (char a)
+{
+ return a != 'a';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-2.c
b/gcc/testsuite/c-c++-common/pr103798-2.c
new file mode 100644
index 00000000000..e7e99c3679e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-2.c
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+#include <string.h>
+
+__attribute__ ((weak))
+int
+f (int a)
+{
+ return memchr ("aE", a, 2) != NULL;
+}
+
+__attribute__ ((weak))
+int
+g (char a)
+{
+ return a == 'a' || a == 'E';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i + 256) != g (i + 256))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-3.c
b/gcc/testsuite/c-c++-common/pr103798-3.c
new file mode 100644
index 00000000000..ddcedc7e238
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-3.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int
+f (char a)
+{
+ return __builtin_memchr ("aEgZ", a, 3) == 0;
+}
+
+__attribute__ ((weak))
+int
+g (char a)
+{
+ return a != 'a' && a != 'E' && a != 'g';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-4.c
b/gcc/testsuite/c-c++-common/pr103798-4.c
new file mode 100644
index 00000000000..00e8302a833
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-4.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int
+f (char a)
+{
+ return __builtin_memchr ("aEgi", a, 4) != 0;
+}
+
+__attribute__ ((weak))
+int
+g (char a)
+{
+ return a == 'a' || a == 'E' || a == 'g' || a == 'i';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-5.c
b/gcc/testsuite/c-c++-common/pr103798-5.c
new file mode 100644
index 00000000000..0d6487a13df
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-5.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int f(char a)
+{
+ return __builtin_memchr ("aEgiH", a, 5) == 0;
+}
+
+__attribute__ ((weak))
+int g(char a)
+{
+ return a != 'a' && a != 'E' && a != 'g' && a != 'i' && a != 'H';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-6.c
b/gcc/testsuite/c-c++-common/pr103798-6.c
new file mode 100644
index 00000000000..5ccb5ee66e0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-6.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int f(char a)
+{
+ return __builtin_memchr ("aEgiHx", a, 6) != 0;
+}
+
+__attribute__ ((weak))
+int g(char a)
+{
+ return (a == 'a' || a == 'E' || a == 'g' || a == 'i' || a == 'H'
+ || a == 'x');
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-7.c
b/gcc/testsuite/c-c++-common/pr103798-7.c
new file mode 100644
index 00000000000..40fd38257d1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-7.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int f(char a)
+{
+ return __builtin_memchr ("aEgiHjZ", a, 7) == 0;
+}
+
+__attribute__ ((weak))
+int g(char a)
+{
+ return (a != 'a' && a != 'E' && a != 'g' && a != 'i' && a != 'H'
+ && a != 'j' && a != 'Z');
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-8.c
b/gcc/testsuite/c-c++-common/pr103798-8.c
new file mode 100644
index 00000000000..0841b18cea4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-8.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int f(int a)
+{
+ return __builtin_memchr ("aEgiHx19ABC", a, 8) != 0;
+}
+
+__attribute__ ((weak))
+int g(char a)
+{
+ return (a == 'a' || a == 'E' || a == 'g' || a == 'i' || a == 'H'
+ || a == 'x' || a == '1' || a == '9');
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i + 256) != g (i + 256))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
--
2.36.1