Message ID | 20220621210231.57904-1-hjl.tools@gmail.com |
---|---|
State | New |
Headers |
Return-Path: <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 39DC93857034 for <patchwork@sourceware.org>; Tue, 21 Jun 2022 21:03:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 39DC93857034 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1655845385; bh=gOAMsQMploinbaedAAgsdn1G4xDY7rW/L2RhC6vgYbU=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=O2AQPArBZLnXegVEU8aj7FlHY3VlMp8sdypbVFf9J/M6KHfemx+rUPOuqR0Tj2fNK Tbh1TTP6ofF5Y/y/7F1dtljLAPqkXm2qONLeZ5/Ij1N+zHiAoyEmNaZqmsjHFoA04i mqz57IuvhYAvcP7gHNx8ThOcUnXgBLFfIyMP91sw= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x435.google.com (mail-pf1-x435.google.com [IPv6:2607:f8b0:4864:20::435]) by sourceware.org (Postfix) with ESMTPS id 0E1C93857B83 for <gcc-patches@gcc.gnu.org>; Tue, 21 Jun 2022 21:02:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0E1C93857B83 Received: by mail-pf1-x435.google.com with SMTP id a15so7000308pfv.13 for <gcc-patches@gcc.gnu.org>; Tue, 21 Jun 2022 14:02:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=gOAMsQMploinbaedAAgsdn1G4xDY7rW/L2RhC6vgYbU=; b=EPTNkFmlxnVeI5jorShTTJS/m3kmMmcenq1L0/0XZovlVkpIKLrMAph9cjNpQPUrzk EdQcrFR2FLR+XB5EssyvYZMyNEiKi1WIYSJLTRYo5eXrT+P34dRmxSTDGAdWs0S3a+lG 5Gi1YWFitIHw2MavnefmgghlNOdcO6UDJGENtZWJ7wTM5tt2yRZmxmUfMeSR2Du5AX0/ o78EADX+KlnaIx70CDYY/HjoAbp46jMrOkbX4eeYL6IL28n/LZ0fVL+EgYXbhyfxi9Sn lqq1reoreT3Qeu5ixEaASHO1nM/O0a7kRIVwrSfZ2KZ/p3G45kuqjuslzfrkCpChPtzY DdvA== X-Gm-Message-State: AJIora+yx5jx52Eh6UBi8hFFq8P8rDbD51EUXgInYQpwzFpE7OMhKh9R Sk3to1ql3xyQg7uXyA+ch6KqfjQ0I8M= X-Google-Smtp-Source: AGRyM1sh1ombPC1nslewXg92N5Pn0h7NMsjICkoAuQy0871yOtMJHkeH40V/JUuolNo0H9iWlAYq9g== X-Received: by 2002:a63:5b42:0:b0:408:8710:13b0 with SMTP id l2-20020a635b42000000b00408871013b0mr28210418pgm.584.1655845353459; Tue, 21 Jun 2022 14:02:33 -0700 (PDT) Received: from gnu-tgl-3.localdomain ([172.58.37.230]) by smtp.gmail.com with ESMTPSA id q8-20020a170902a3c800b00163ffbc4f74sm11229042plb.49.2022.06.21.14.02.33 for <gcc-patches@gcc.gnu.org> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Jun 2022 14:02:33 -0700 (PDT) Received: from gnu-tgl-3.. (localhost [IPv6:::1]) by gnu-tgl-3.localdomain (Postfix) with ESMTP id 0CB72C00A7 for <gcc-patches@gcc.gnu.org>; Tue, 21 Jun 2022 14:02:32 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH] Inline memchr with a small constant string Date: Tue, 21 Jun 2022 14:02:31 -0700 Message-Id: <20220621210231.57904-1-hjl.tools@gmail.com> X-Mailer: git-send-email 2.36.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3027.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list <gcc-patches.gcc.gnu.org> List-Unsubscribe: <https://gcc.gnu.org/mailman/options/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe> List-Archive: <https://gcc.gnu.org/pipermail/gcc-patches/> List-Post: <mailto:gcc-patches@gcc.gnu.org> List-Help: <mailto:gcc-patches-request@gcc.gnu.org?subject=help> List-Subscribe: <https://gcc.gnu.org/mailman/listinfo/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe> From: "H.J. Lu via Gcc-patches" <gcc-patches@gcc.gnu.org> Reply-To: "H.J. Lu" <hjl.tools@gmail.com> Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> |
Series |
Inline memchr with a small constant string
|
|
Commit Message
H.J. Lu
June 21, 2022, 9:02 p.m. UTC
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
Comments
On Tue, Jun 21, 2022 at 11:03 PM H.J. Lu via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > 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. Please do this in strlenopt or so, with match.pd you will end up moving the memchr loads across possible aliasing stores to the point of the comparison. Richard. > 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 >
On Wed, Jun 22, 2022 at 4:39 AM Richard Biener <richard.guenther@gmail.com> wrote: > > On Tue, Jun 21, 2022 at 11:03 PM H.J. Lu via Gcc-patches > <gcc-patches@gcc.gnu.org> wrote: > > > > 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. > > Please do this in strlenopt or so, with match.pd you will end up moving > the memchr loads across possible aliasing stores to the point of the > comparison. strlenopt is run after many other passes. The code won't be well optimized. Since we are only optimizing __builtin_memchr ("eE", a, 2) != 0; I don't see any aliasing store issues here. > Richard. > > > 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 > >
On Wed, Jun 22, 2022 at 7:13 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Wed, Jun 22, 2022 at 4:39 AM Richard Biener > <richard.guenther@gmail.com> wrote: > > > > On Tue, Jun 21, 2022 at 11:03 PM H.J. Lu via Gcc-patches > > <gcc-patches@gcc.gnu.org> wrote: > > > > > > 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. > > > > Please do this in strlenopt or so, with match.pd you will end up moving > > the memchr loads across possible aliasing stores to the point of the > > comparison. > > strlenopt is run after many other passes. The code won't be well optimized. What followup optimizations do you expect? That is, other builtins are only expanded inline at RTL expansion time? > Since we are only optimizing > > __builtin_memchr ("eE", a, 2) != 0; > > I don't see any aliasing store issues here. Ah, I failed to see the STRING_CST restriction. Note that when optimizing for size this doesn't look very good. I would expect a target might produce some vector code for memchr ("aAbBcCdDeE...", c, 9) != 0 by splatting 'c', doing a v16qimode compare, masking off excess elements beyond length and then comparing against zero or for == 0 against all-ones. The repetitive pattern result also suggests an implementation elsewhere, if you think strlenopt is too late there would be forwprop as well. Richard. > > Richard. > > > > > 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 > > > > > > > -- > H.J.
On Wed, Jun 22, 2022 at 11:03 PM Richard Biener <richard.guenther@gmail.com> wrote: > > On Wed, Jun 22, 2022 at 7:13 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > On Wed, Jun 22, 2022 at 4:39 AM Richard Biener > > <richard.guenther@gmail.com> wrote: > > > > > > On Tue, Jun 21, 2022 at 11:03 PM H.J. Lu via Gcc-patches > > > <gcc-patches@gcc.gnu.org> wrote: > > > > > > > > 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. > > > > > > Please do this in strlenopt or so, with match.pd you will end up moving > > > the memchr loads across possible aliasing stores to the point of the > > > comparison. > > > > strlenopt is run after many other passes. The code won't be well optimized. > > What followup optimizations do you expect? That is, other builtins are only reassociation and dce turn _5 = a_2(D) == 101; _6 = a_2(D) == 69; _1 = _5 | _6; _4 = (int) _1; into _7 = a_2(D) & -33; _8 = _7 == 69; _1 = _8; _4 = (int) _1; > expanded inline at RTL expansion time? Some high level optimizations will be missed and TARGET_GIMPLE_FOLD_BUILTIN improves builtins codegen. > > Since we are only optimizing > > > > __builtin_memchr ("eE", a, 2) != 0; > > > > I don't see any aliasing store issues here. > > Ah, I failed to see the STRING_CST restriction. Note that when optimizing for > size this doesn't look very good. True. > I would expect a target might produce some vector code for > memchr ("aAbBcCdDeE...", c, 9) != 0 by splatting 'c', doing > a v16qimode compare, masking off excess elements beyond length > and then comparing against zero or for == 0 against all-ones. > > The repetitive pattern result also suggests an implementation elsewhere, > if you think strlenopt is too late there would be forwprop as well. forwprop seems a good place. Thanks. > Richard. > > > > > > Richard. > > > > > > > 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 > > > > > > > > > > > > -- > > H.J.
On Thu, Jun 23, 2022 at 9:26 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Wed, Jun 22, 2022 at 11:03 PM Richard Biener > <richard.guenther@gmail.com> wrote: > > > > On Wed, Jun 22, 2022 at 7:13 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > > > On Wed, Jun 22, 2022 at 4:39 AM Richard Biener > > > <richard.guenther@gmail.com> wrote: > > > > > > > > On Tue, Jun 21, 2022 at 11:03 PM H.J. Lu via Gcc-patches > > > > <gcc-patches@gcc.gnu.org> wrote: > > > > > > > > > > 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. > > > > > > > > Please do this in strlenopt or so, with match.pd you will end up moving > > > > the memchr loads across possible aliasing stores to the point of the > > > > comparison. > > > > > > strlenopt is run after many other passes. The code won't be well optimized. > > > > What followup optimizations do you expect? That is, other builtins are only > > reassociation and dce turn > > _5 = a_2(D) == 101; > _6 = a_2(D) == 69; > _1 = _5 | _6; > _4 = (int) _1; > > into > > _7 = a_2(D) & -33; > _8 = _7 == 69; > _1 = _8; > _4 = (int) _1; > > > expanded inline at RTL expansion time? > > Some high level optimizations will be missed and > TARGET_GIMPLE_FOLD_BUILTIN improves builtins > codegen. > > > > Since we are only optimizing > > > > > > __builtin_memchr ("eE", a, 2) != 0; > > > > > > I don't see any aliasing store issues here. > > > > Ah, I failed to see the STRING_CST restriction. Note that when optimizing for > > size this doesn't look very good. > > True. > > > I would expect a target might produce some vector code for > > memchr ("aAbBcCdDeE...", c, 9) != 0 by splatting 'c', doing > > a v16qimode compare, masking off excess elements beyond length > > and then comparing against zero or for == 0 against all-ones. > > > > The repetitive pattern result also suggests an implementation elsewhere, > > if you think strlenopt is too late there would be forwprop as well. > > forwprop seems a good place. The v2 patch is at https://gcc.gnu.org/pipermail/gcc-patches/2022-July/598022.html Thanks.
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" } } */