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

Reply via email to