Commit 8b0b334a by Qing Zhao Committed by Qing Zhao

2nd Patch for PR78009

Patch for PR83026

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78809
Inline strcmp with small constant strings

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83026
missing strlen optimization for strcmp of unequal strings

The design doc for PR78809 is at:
https://www.mail-archive.com/gcc@gcc.gnu.org/msg83822.html

this patch is for the second part of change of PR78809 and PR83026:

B. for strncmp (s1, s2, n) (!)= 0 or strcmp (s1, s2) (!)= 0

   B.1. (PR83026) When the lengths of both arguments are constant and
        it's a strcmp:
      * if the lengths are NOT equal, we can safely fold the call
        to a non-zero value.
      * otherwise, do nothing now.

   B.2. (PR78809) When the length of one argument is constant, try to replace
   the call with a __builtin_str(n)cmp_eq call where possible, i.e:

   strncmp (s, STR, C) (!)= 0 in which, s is a pointer to a string, STR is a
   string with constant length, C is a constant.
     if (C <= strlen(STR) && sizeof_array(s) > C)
       {
         replace this call with
         __builtin_strncmp_eq (s, STR, C) (!)= 0
       }
     if (C > strlen(STR)
       {
         it can be safely treated as a call to strcmp (s, STR) (!)= 0
         can handled by the following strcmp.
       }

   strcmp (s, STR) (!)= 0 in which, s is a pointer to a string, STR is a
   string with constant length.
     if  (sizeof_array(s) > strlen(STR))
       {
         replace this call with
         __builtin_strcmp_eq (s, STR, strlen(STR)+1) (!)= 0
       }

   later when expanding the new __builtin_str(n)cmp_eq calls, first expand them
   as __builtin_memcmp_eq, if the expansion does not succeed, change them back
   to call to __builtin_str(n)cmp.

adding test case strcmpopt_2.c and strcmpopt_4.c into gcc.dg for part B of
PR78809 adding test case strcmpopt_3.c into gcc.dg for PR83026

From-SVN: r261039
parent 28c84b62
2018-05-31 Qing Zhao <qing.zhao@oracle.com>
PR middle-end/78809
PR middle-end/83026
* builtins.c (expand_builtin): Add the handling of BUILT_IN_STRCMP_EQ
and BUILT_IN_STRNCMP_EQ.
* builtins.def: Add new builtins BUILT_IN_STRCMP_EQ and
BUILT_IN_STRNCMP_EQ.
* gimple-fold.c (gimple_fold_builtin_string_compare): Add the
handling of BUILTIN_IN_STRCMP_EQ and BUILT_IN_STRNCMP_EQ.
(gimple_fold_builtin): Likewise.
* tree-ssa-strlen.c (compute_string_length): New function.
(determine_min_obsize): New function.
(handle_builtin_string_cmp): New function to handle calls to
string compare functions.
(strlen_optimize_stmt): Add handling to builtin string compare
calls.
* tree-ssa-structalias.c (find_func_aliases_for_builtin_call):
Add the handling of BUILT_IN_STRCMP_EQ and BUILT_IN_STRNCMP_EQ.
* tree.c (build_common_builtin_nodes): Add new defines of
BUILT_IN_STRNCMP_EQ and BUILT_IN_STRCMP_EQ.
2018-05-31 Jakub Jelinek <jakub@redhat.com>
PR target/85984
......
......@@ -7139,12 +7139,45 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
return target;
break;
/* Expand it as BUILT_IN_MEMCMP_EQ first. If not successful, change it
back to a BUILT_IN_STRCMP. Remember to delete the 3rd paramater
when changing it to a strcmp call. */
case BUILT_IN_STRCMP_EQ:
target = expand_builtin_memcmp (exp, target, true);
if (target)
return target;
/* Change this call back to a BUILT_IN_STRCMP. */
TREE_OPERAND (exp, 1)
= build_fold_addr_expr (builtin_decl_explicit (BUILT_IN_STRCMP));
/* Delete the last parameter. */
unsigned int i;
vec<tree, va_gc> *arg_vec;
vec_alloc (arg_vec, 2);
for (i = 0; i < 2; i++)
arg_vec->quick_push (CALL_EXPR_ARG (exp, i));
exp = build_call_vec (TREE_TYPE (exp), CALL_EXPR_FN (exp), arg_vec);
/* FALLTHROUGH */
case BUILT_IN_STRCMP:
target = expand_builtin_strcmp (exp, target);
if (target)
return target;
break;
/* Expand it as BUILT_IN_MEMCMP_EQ first. If not successful, change it
back to a BUILT_IN_STRNCMP. */
case BUILT_IN_STRNCMP_EQ:
target = expand_builtin_memcmp (exp, target, true);
if (target)
return target;
/* Change it back to a BUILT_IN_STRNCMP. */
TREE_OPERAND (exp, 1)
= build_fold_addr_expr (builtin_decl_explicit (BUILT_IN_STRNCMP));
/* FALLTHROUGH */
case BUILT_IN_STRNCMP:
target = expand_builtin_strncmp (exp, target, mode);
if (target)
......
......@@ -971,6 +971,11 @@ DEF_BUILTIN_STUB (BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX, "__builtin_alloca_with_ali
equality with zero. */
DEF_BUILTIN_STUB (BUILT_IN_MEMCMP_EQ, "__builtin_memcmp_eq")
/* An internal version of strcmp/strncmp, used when the result is only
tested for equality with zero. */
DEF_BUILTIN_STUB (BUILT_IN_STRCMP_EQ, "__builtin_strcmp_eq")
DEF_BUILTIN_STUB (BUILT_IN_STRNCMP_EQ, "__builtin_strncmp_eq")
/* Object size checking builtins. */
DEF_GCC_BUILTIN (BUILT_IN_OBJECT_SIZE, "object_size", BT_FN_SIZE_CONST_PTR_INT, ATTR_PURE_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN_CHKP (BUILT_IN_MEMCPY_CHK, "__memcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
......
......@@ -2215,12 +2215,14 @@ gimple_fold_builtin_string_compare (gimple_stmt_iterator *gsi)
switch (fcode)
{
case BUILT_IN_STRCMP:
case BUILT_IN_STRCMP_EQ:
{
r = strcmp (p1, p2);
known_result = true;
break;
}
case BUILT_IN_STRNCMP:
case BUILT_IN_STRNCMP_EQ:
{
if (length == -1)
break;
......@@ -2254,6 +2256,7 @@ gimple_fold_builtin_string_compare (gimple_stmt_iterator *gsi)
bool nonzero_length = length >= 1
|| fcode == BUILT_IN_STRCMP
|| fcode == BUILT_IN_STRCMP_EQ
|| fcode == BUILT_IN_STRCASECMP;
location_t loc = gimple_location (stmt);
......@@ -3687,8 +3690,10 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
case BUILT_IN_STRSTR:
return gimple_fold_builtin_strstr (gsi);
case BUILT_IN_STRCMP:
case BUILT_IN_STRCMP_EQ:
case BUILT_IN_STRCASECMP:
case BUILT_IN_STRNCMP:
case BUILT_IN_STRNCMP_EQ:
case BUILT_IN_STRNCASECMP:
return gimple_fold_builtin_string_compare (gsi);
case BUILT_IN_MEMCHR:
......
2018-05-31 Qing Zhao <qing.zhao@oracle.com>
PR middle-end/78809
* gcc.dg/strcmpopt_2.c: New test.
* gcc.dg/strcmpopt_3.c: New test.
PR middle-end/83026
* gcc.dg/strcmpopt_3.c: New test.
2018-05-31 Jakub Jelinek <jakub@redhat.com>
PR target/85984
......
/* { dg-do run } */
/* { dg-options "-O2 -fdump-tree-strlen" } */
char s[100] = {'a','b','c','d'};
typedef struct { char s[8]; int x; } S;
__attribute__ ((noinline)) int
f1 (S *s)
{
return __builtin_strcmp (s->s, "abc") != 0;
}
__attribute__ ((noinline)) int
f2 (void)
{
return __builtin_strcmp (s, "abc") != 0;
}
__attribute__ ((noinline)) int
f3 (S *s)
{
return __builtin_strcmp ("abc", s->s) != 0;
}
__attribute__ ((noinline)) int
f4 (void)
{
return __builtin_strcmp ("abc", s) != 0;
}
__attribute__ ((noinline)) int
f5 (S *s)
{
return __builtin_strncmp (s->s, "abc", 3) != 0;
}
__attribute__ ((noinline)) int
f6 (void)
{
return __builtin_strncmp (s, "abc", 2) != 0;
}
__attribute__ ((noinline)) int
f7 (S *s)
{
return __builtin_strncmp ("abc", s->s, 3) != 0;
}
__attribute__ ((noinline)) int
f8 (void)
{
return __builtin_strncmp ("abc", s, 2) != 0;
}
int main (void)
{
S ss = {{'a','b','c'}, 2};
if (f1 (&ss) != 0 || f2 () != 1 || f3 (&ss) != 0 ||
f4 () != 1 || f5 (&ss) != 0 || f6 () != 0 ||
f7 (&ss) != 0 || f8 () != 0)
__builtin_abort ();
return 0;
}
/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 8 "strlen" } } */
/* { dg-do run } */
/* { dg-options "-O2 -fdump-tree-strlen" } */
__attribute__ ((noinline)) int
f1 (void)
{
char *s0= "abcd";
char s[8];
__builtin_strcpy (s, s0);
return __builtin_strcmp(s, "abc") != 0;
}
__attribute__ ((noinline)) int
f2 (void)
{
char *s0 = "ab";
char s[8];
__builtin_strcpy (s, s0);
return __builtin_strcmp("abc", s) != 0;
}
int main (void)
{
if (f1 () != 1
|| f2 () != 1)
__builtin_abort ();
return 0;
}
/* { dg-final { scan-tree-dump-times "strcmp" 0 "strlen" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-strlen" } */
typedef struct { char s[8]; int x; } S;
extern int max_i;
int
f1 (S * s)
{
int result, i;
for (i = 0; i < max_i; i++)
result += __builtin_strcmp (s->s, "abc") != 0 ? 2 : 1;
return result;
}
/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 1 "strlen" } } */
......@@ -4498,7 +4498,9 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
that use the memory pointed to by their arguments (but not
transitively). */
case BUILT_IN_STRCMP:
case BUILT_IN_STRCMP_EQ:
case BUILT_IN_STRNCMP:
case BUILT_IN_STRNCMP_EQ:
case BUILT_IN_STRCASECMP:
case BUILT_IN_STRNCASECMP:
case BUILT_IN_MEMCMP:
......
......@@ -10277,6 +10277,14 @@ build_common_builtin_nodes (void)
"__builtin_memcmp_eq",
ECF_PURE | ECF_NOTHROW | ECF_LEAF);
local_define_builtin ("__builtin_strncmp_eq", ftype, BUILT_IN_STRNCMP_EQ,
"__builtin_strncmp_eq",
ECF_PURE | ECF_NOTHROW | ECF_LEAF);
local_define_builtin ("__builtin_strcmp_eq", ftype, BUILT_IN_STRCMP_EQ,
"__builtin_strcmp_eq",
ECF_PURE | ECF_NOTHROW | ECF_LEAF);
/* If there's a possibility that we might use the ARM EABI, build the
alternate __cxa_end_cleanup node used to resume from C++. */
if (targetm.arm_eabi_unwinder)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment