From patchwork Tue Jun 21 21:02:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 55243 Return-Path: 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 ; 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 ; 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 ; 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 (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 ; 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 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "H.J. Lu via Gcc-patches" From: "H.J. Lu" Reply-To: "H.J. Lu" Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" 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 + +__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" } } */