common.opt: Add -foptimize-strlen option.
* common.opt: Add -foptimize-strlen option. * Makefile.in (OBJS): Add tree-ssa-strlen.o. (tree-sssa-strlen.o): Add dependencies. * opts.c (default_options_table): Enable -foptimize-strlen by default at -O2 if not -Os. * passes.c (init_optimization_passes): Add pass_strlen after pass_object_sizes. * timevar.def (TV_TREE_STRLEN): New timevar. * params.def (PARAM_MAX_TRACKED_STRLENS): New parameter. * tree-pass.h (pass_strlen): Declare. * tree-ssa-strlen.c: New file. * c-decl.c (merge_decls): If compatible stpcpy prototype is seen, set implicit_built_in_decls[BUILT_IN_STPCPY]. cp/ * decl.c (duplicate_decls): If compatible stpcpy prototype is seen, set implicit_built_in_decls[BUILT_IN_STPCPY]. testsuite/ * gcc.dg/strlenopt-1.c: New test. * gcc.dg/strlenopt-1f.c: New test. * gcc.dg/strlenopt-2.c: New test. * gcc.dg/strlenopt-2f.c: New test. * gcc.dg/strlenopt-3.c: New test. * gcc.dg/strlenopt-4.c: New test. * gcc.dg/strlenopt-4g.c: New test. * gcc.dg/strlenopt-4gf.c: New test. * gcc.dg/strlenopt-5.c: New test. * gcc.dg/strlenopt-6.c: New test. * gcc.dg/strlenopt-7.c: New test. * gcc.dg/strlenopt-8.c: New test. * gcc.dg/strlenopt-9.c: New test. * gcc.dg/strlenopt-10.c: New test. * gcc.dg/strlenopt-11.c: New test. * gcc.dg/strlenopt-12.c: New test. * gcc.dg/strlenopt-12g.c: New test. * gcc.dg/strlenopt-13.c: New test. * gcc.dg/strlenopt-14g.c: New test. * gcc.dg/strlenopt-14gf.c: New test. * gcc.dg/strlenopt-15.c: New test. * gcc.dg/strlenopt-16g.c: New test. * gcc.dg/strlenopt-17g.c: New test. * gcc.dg/strlenopt-18g.c: New test. * gcc.dg/strlenopt.h: New file. From-SVN: r179277
This commit is contained in:
parent
baaa40aeca
commit
8b57bfebe0
@ -1,3 +1,19 @@
|
||||
2011-09-27 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* common.opt: Add -foptimize-strlen option.
|
||||
* Makefile.in (OBJS): Add tree-ssa-strlen.o.
|
||||
(tree-sssa-strlen.o): Add dependencies.
|
||||
* opts.c (default_options_table): Enable -foptimize-strlen
|
||||
by default at -O2 if not -Os.
|
||||
* passes.c (init_optimization_passes): Add pass_strlen
|
||||
after pass_object_sizes.
|
||||
* timevar.def (TV_TREE_STRLEN): New timevar.
|
||||
* params.def (PARAM_MAX_TRACKED_STRLENS): New parameter.
|
||||
* tree-pass.h (pass_strlen): Declare.
|
||||
* tree-ssa-strlen.c: New file.
|
||||
* c-decl.c (merge_decls): If compatible stpcpy prototype
|
||||
is seen, set implicit_built_in_decls[BUILT_IN_STPCPY].
|
||||
|
||||
2011-09-27 Tom de Vries <tom@codesourcery.com>
|
||||
|
||||
PR middle-end/43864
|
||||
|
@ -1475,6 +1475,7 @@ OBJS = \
|
||||
tree-ssa-reassoc.o \
|
||||
tree-ssa-sccvn.o \
|
||||
tree-ssa-sink.o \
|
||||
tree-ssa-strlen.o \
|
||||
tree-ssa-structalias.o \
|
||||
tree-ssa-tail-merge.o \
|
||||
tree-ssa-ter.o \
|
||||
@ -3168,6 +3169,9 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_FLOW_H) $(CONFIG_H) \
|
||||
$(TREE_DUMP_H) $(BASIC_BLOCK_H) $(TREE_PASS_H) langhooks.h $(PARAMS_H) \
|
||||
tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) $(DIAGNOSTIC_CORE_H) \
|
||||
$(DBGCNT_H) tree-pretty-print.h gimple-pretty-print.h gimple-fold.h
|
||||
tree-ssa-strlen.o : tree-ssa-strlen.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
||||
$(TREE_FLOW_H) $(TREE_PASS_H) domwalk.h alloc-pool.h tree-ssa-propagate.h \
|
||||
gimple-pretty-print.h $(PARAMS_H)
|
||||
tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) coretypes.h alloc-pool.h \
|
||||
$(TM_H) $(TREE_H) $(GIMPLE_H) $(CGRAPH_H) $(TREE_FLOW_H) \
|
||||
$(IPA_PROP_H) $(DIAGNOSTIC_H) statistics.h $(TREE_DUMP_H) $(TIMEVAR_H) \
|
||||
|
16
gcc/c-decl.c
16
gcc/c-decl.c
@ -2369,7 +2369,21 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
|
||||
DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
|
||||
C_DECL_DECLARED_BUILTIN (newdecl) = 1;
|
||||
if (new_is_prototype)
|
||||
C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0;
|
||||
{
|
||||
C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0;
|
||||
if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
|
||||
switch (DECL_FUNCTION_CODE (newdecl))
|
||||
{
|
||||
/* If a compatible prototype of these builtin functions
|
||||
is seen, assume the runtime implements it with the
|
||||
expected semantics. */
|
||||
case BUILT_IN_STPCPY:
|
||||
implicit_built_in_decls[DECL_FUNCTION_CODE (newdecl)]
|
||||
= built_in_decls[DECL_FUNCTION_CODE (newdecl)];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
C_DECL_BUILTIN_PROTOTYPE (newdecl)
|
||||
= C_DECL_BUILTIN_PROTOTYPE (olddecl);
|
||||
|
@ -1961,6 +1961,10 @@ ftree-fre
|
||||
Common Report Var(flag_tree_fre) Optimization
|
||||
Enable Full Redundancy Elimination (FRE) on trees
|
||||
|
||||
foptimize-strlen
|
||||
Common Report Var(flag_optimize_strlen) Optimization
|
||||
Enable string length optimizations on trees
|
||||
|
||||
ftree-loop-distribution
|
||||
Common Report Var(flag_tree_loop_distribution) Optimization
|
||||
Enable loop distribution on trees
|
||||
|
@ -1,3 +1,8 @@
|
||||
2011-09-27 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* decl.c (duplicate_decls): If compatible stpcpy prototype
|
||||
is seen, set implicit_built_in_decls[BUILT_IN_STPCPY].
|
||||
|
||||
2011-09-26 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/45012
|
||||
|
@ -2135,6 +2135,18 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|
||||
/* If we're keeping the built-in definition, keep the rtl,
|
||||
regardless of declaration matches. */
|
||||
COPY_DECL_RTL (olddecl, newdecl);
|
||||
if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
|
||||
switch (DECL_FUNCTION_CODE (newdecl))
|
||||
{
|
||||
/* If a compatible prototype of these builtin functions
|
||||
is seen, assume the runtime implements it with the
|
||||
expected semantics. */
|
||||
case BUILT_IN_STPCPY:
|
||||
implicit_built_in_decls[DECL_FUNCTION_CODE (newdecl)]
|
||||
= built_in_decls[DECL_FUNCTION_CODE (newdecl)];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* Top level of GCC compilers (cc1, cc1plus, etc.)
|
||||
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
||||
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
Free Software Foundation, Inc.
|
||||
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
2011 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
@ -1321,6 +1321,7 @@ init_optimization_passes (void)
|
||||
NEXT_PASS (pass_forwprop);
|
||||
NEXT_PASS (pass_phiopt);
|
||||
NEXT_PASS (pass_object_sizes);
|
||||
NEXT_PASS (pass_strlen);
|
||||
NEXT_PASS (pass_ccp);
|
||||
NEXT_PASS (pass_copy_prop);
|
||||
NEXT_PASS (pass_cse_sincos);
|
||||
|
@ -1,3 +1,31 @@
|
||||
2011-09-27 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* gcc.dg/strlenopt-1.c: New test.
|
||||
* gcc.dg/strlenopt-1f.c: New test.
|
||||
* gcc.dg/strlenopt-2.c: New test.
|
||||
* gcc.dg/strlenopt-2f.c: New test.
|
||||
* gcc.dg/strlenopt-3.c: New test.
|
||||
* gcc.dg/strlenopt-4.c: New test.
|
||||
* gcc.dg/strlenopt-4g.c: New test.
|
||||
* gcc.dg/strlenopt-4gf.c: New test.
|
||||
* gcc.dg/strlenopt-5.c: New test.
|
||||
* gcc.dg/strlenopt-6.c: New test.
|
||||
* gcc.dg/strlenopt-7.c: New test.
|
||||
* gcc.dg/strlenopt-8.c: New test.
|
||||
* gcc.dg/strlenopt-9.c: New test.
|
||||
* gcc.dg/strlenopt-10.c: New test.
|
||||
* gcc.dg/strlenopt-11.c: New test.
|
||||
* gcc.dg/strlenopt-12.c: New test.
|
||||
* gcc.dg/strlenopt-12g.c: New test.
|
||||
* gcc.dg/strlenopt-13.c: New test.
|
||||
* gcc.dg/strlenopt-14g.c: New test.
|
||||
* gcc.dg/strlenopt-14gf.c: New test.
|
||||
* gcc.dg/strlenopt-15.c: New test.
|
||||
* gcc.dg/strlenopt-16g.c: New test.
|
||||
* gcc.dg/strlenopt-17g.c: New test.
|
||||
* gcc.dg/strlenopt-18g.c: New test.
|
||||
* gcc.dg/strlenopt.h: New file.
|
||||
|
||||
2011-09-27 Tom de Vries <tom@codesourcery.com>
|
||||
|
||||
PR middle-end/43864
|
||||
|
47
gcc/testsuite/gcc.dg/strlenopt-1.c
Normal file
47
gcc/testsuite/gcc.dg/strlenopt-1.c
Normal file
@ -0,0 +1,47 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
foo (char *p, char *r)
|
||||
{
|
||||
char *q = malloc (strlen (p) + strlen (r) + 64);
|
||||
if (q == NULL) return NULL;
|
||||
/* This strcpy can be optimized into memcpy, using the remembered
|
||||
strlen (p). */
|
||||
strcpy (q, p);
|
||||
/* These two strcat can be optimized into memcpy. The first one
|
||||
could be even optimized into a *ptr = '/'; store as the '\0'
|
||||
is immediately overwritten. */
|
||||
strcat (q, "/");
|
||||
strcat (q, "abcde");
|
||||
/* Due to inefficient PTA (PR50262) the above calls invalidate
|
||||
string length of r, so it is optimized just into strcpy instead
|
||||
of memcpy. */
|
||||
strcat (q, r);
|
||||
return q;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char *volatile p = "string1";
|
||||
char *volatile r = "string2";
|
||||
char *q = foo (p, r);
|
||||
if (q != NULL)
|
||||
{
|
||||
if (strcmp (q, "string1/abcdestring2"))
|
||||
abort ();
|
||||
free (q);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
80
gcc/testsuite/gcc.dg/strlenopt-10.c
Normal file
80
gcc/testsuite/gcc.dg/strlenopt-10.c
Normal file
@ -0,0 +1,80 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn1 (char *p)
|
||||
{
|
||||
char *q;
|
||||
/* This can be optimized into memcpy and the size can be decreased to one,
|
||||
as it is immediately overwritten. */
|
||||
strcpy (p, "z");
|
||||
q = strchr (p, '\0');
|
||||
*q = 32;
|
||||
/* This strlen can't be optimized away, string length is unknown here. */
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
fn2 (char *p, const char *z, size_t *lp)
|
||||
{
|
||||
char *q, *r;
|
||||
char buf[64];
|
||||
size_t l[10];
|
||||
/* The first strlen stays, all the strcpy calls can be optimized
|
||||
into memcpy and all other strlen calls and all strchr calls
|
||||
optimized away. */
|
||||
l[0] = strlen (z);
|
||||
strcpy (buf, z);
|
||||
strcpy (p, "abcde");
|
||||
q = strchr (p, '\0');
|
||||
strcpy (q, "efghi");
|
||||
r = strchr (q, '\0');
|
||||
strcpy (r, "jkl");
|
||||
l[1] = strlen (p);
|
||||
l[2] = strlen (q);
|
||||
l[3] = strlen (r);
|
||||
strcpy (r, buf);
|
||||
l[4] = strlen (p);
|
||||
l[5] = strlen (q);
|
||||
l[6] = strlen (r);
|
||||
strcpy (r, "mnopqr");
|
||||
l[7] = strlen (p);
|
||||
l[8] = strlen (q);
|
||||
l[9] = strlen (r);
|
||||
memcpy (lp, l, sizeof l);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char buf[64];
|
||||
size_t l[10];
|
||||
const char *volatile z = "ABCDEFG";
|
||||
memset (buf, '\0', sizeof buf);
|
||||
if (fn1 (buf) != 2 || buf[0] != 'z' || buf[1] != 32 || buf[2] != '\0')
|
||||
abort ();
|
||||
fn2 (buf, z, l);
|
||||
if (memcmp (buf, "abcdeefghimnopqr", 17) != 0)
|
||||
abort ();
|
||||
if (l[0] != 7)
|
||||
abort ();
|
||||
if (l[1] != 13 || l[2] != 8 || l[3] != 3)
|
||||
abort ();
|
||||
if (l[4] != 17 || l[5] != 12 || l[6] != 7)
|
||||
abort ();
|
||||
if (l[7] != 16 || l[8] != 11 || l[9] != 6)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 8 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "\\*q_\[0-9\]* = 32;" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(\[^\n\r\]*, 1\\)" 1 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
70
gcc/testsuite/gcc.dg/strlenopt-11.c
Normal file
70
gcc/testsuite/gcc.dg/strlenopt-11.c
Normal file
@ -0,0 +1,70 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
fn1 (char *p, const char *z, size_t *lp)
|
||||
{
|
||||
char *q, *r, *s;
|
||||
char buf[64];
|
||||
size_t l[11];
|
||||
/* The first strlen stays, all the strcpy calls can be optimized
|
||||
into memcpy and most other strlen calls and all strchr calls
|
||||
optimized away. l[6] = strlen (r); and l[9] = strlen (r); need
|
||||
to stay, because we need to invalidate the knowledge about
|
||||
r strlen after strcpy (q, "jklmnopqrst"). */
|
||||
l[0] = strlen (z);
|
||||
strcpy (buf, z);
|
||||
strcpy (p, "abcde");
|
||||
q = strchr (p, '\0');
|
||||
strcpy (q, "efghi");
|
||||
r = strchr (q, '\0');
|
||||
strcpy (r, buf);
|
||||
l[1] = strlen (p);
|
||||
l[2] = strlen (q);
|
||||
l[3] = strlen (r);
|
||||
strcpy (q, "jklmnopqrst");
|
||||
l[4] = strlen (p);
|
||||
l[5] = strlen (q);
|
||||
l[6] = strlen (r);
|
||||
s = strchr (q, '\0');
|
||||
strcpy (s, buf);
|
||||
l[7] = strlen (p);
|
||||
l[8] = strlen (q);
|
||||
l[9] = strlen (r);
|
||||
l[10] = strlen (s);
|
||||
memcpy (lp, l, sizeof l);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char buf[64];
|
||||
size_t l[11];
|
||||
const char *volatile z = "ABCDEFG";
|
||||
memset (buf, '\0', sizeof buf);
|
||||
fn1 (buf, z, l);
|
||||
if (memcmp (buf, "abcdejklmnopqrstABCDEFG", 24) != 0)
|
||||
abort ();
|
||||
if (l[0] != 7)
|
||||
abort ();
|
||||
if (l[1] != 17 || l[2] != 12 || l[3] != 7)
|
||||
abort ();
|
||||
if (l[4] != 16 || l[5] != 11 || l[6] != 6)
|
||||
abort ();
|
||||
if (l[7] != 23 || l[8] != 18 || l[9] != 13 || l[10] != 7)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.0. = " 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.6. = " 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.9. = " 1 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
90
gcc/testsuite/gcc.dg/strlenopt-12.c
Normal file
90
gcc/testsuite/gcc.dg/strlenopt-12.c
Normal file
@ -0,0 +1,90 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn1 (char *p, size_t *l)
|
||||
{
|
||||
char *q = strcat (p, "abcde");
|
||||
*l = strlen (p);
|
||||
return q;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn2 (char *p, const char *q, size_t *l1, size_t *l2)
|
||||
{
|
||||
size_t l = strlen (q);
|
||||
char *r = strcat (p, q);
|
||||
*l1 = l;
|
||||
*l2 = strlen (p);
|
||||
return r;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn3 (char *p, const char *q, size_t *l)
|
||||
{
|
||||
char *r = strcpy (p, q);
|
||||
*l = strlen (p);
|
||||
return r;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn4 (char *p, const char *q, size_t *l)
|
||||
{
|
||||
char *r = strcat (p, q);
|
||||
*l = strlen (p);
|
||||
return r;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn5 (char *p, const char *q, size_t *l1, size_t *l2, size_t *l3)
|
||||
{
|
||||
size_t l = strlen (q);
|
||||
size_t ll = strlen (p);
|
||||
char *r = strcat (p, q);
|
||||
*l1 = l;
|
||||
*l2 = strlen (p);
|
||||
*l3 = ll;
|
||||
return r;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn6 (char *p, const char *q, size_t *l1, size_t *l2)
|
||||
{
|
||||
size_t l = strlen (p);
|
||||
char *r = strcat (p, q);
|
||||
*l1 = strlen (p);
|
||||
*l2 = l;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char buf[64];
|
||||
const char *volatile q = "fgh";
|
||||
size_t l, l1, l2, l3;
|
||||
memset (buf, '\0', sizeof buf);
|
||||
memset (buf, 'a', 3);
|
||||
if (fn1 (buf, &l) != buf || l != 8 || memcmp (buf, "aaaabcde", 9) != 0)
|
||||
abort ();
|
||||
if (fn2 (buf, q, &l1, &l2) != buf || l1 != 3 || l2 != 11
|
||||
|| memcmp (buf, "aaaabcdefgh", 12) != 0)
|
||||
abort ();
|
||||
if (fn3 (buf, q, &l) != buf || l != 3
|
||||
|| memcmp (buf, "fgh\0bcdefgh", 12) != 0)
|
||||
abort ();
|
||||
if (fn4 (buf, q, &l) != buf || l != 6
|
||||
|| memcmp (buf, "fghfgh\0efgh", 12) != 0)
|
||||
abort ();
|
||||
l1 = 0;
|
||||
l2 = 0;
|
||||
if (fn5 (buf, q, &l1, &l2, &l3) != buf || l1 != 3 || l2 != 9 || l3 != 6
|
||||
|| memcmp (buf, "fghfghfgh\0h", 12) != 0)
|
||||
abort ();
|
||||
if (fn6 (buf, q, &l1, &l2) != buf || l1 != 12 || l2 != 9
|
||||
|| memcmp (buf, "fghfghfghfgh", 13) != 0)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
6
gcc/testsuite/gcc.dg/strlenopt-12g.c
Normal file
6
gcc/testsuite/gcc.dg/strlenopt-12g.c
Normal file
@ -0,0 +1,6 @@
|
||||
/* This test needs runtime that provides stpcpy function. */
|
||||
/* { dg-do run { target *-*-linux* } } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
#define USE_GNU
|
||||
#include "strlenopt-12.c"
|
68
gcc/testsuite/gcc.dg/strlenopt-13.c
Normal file
68
gcc/testsuite/gcc.dg/strlenopt-13.c
Normal file
@ -0,0 +1,68 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
fn1 (char *p, const char *y, const char *z, size_t *lp)
|
||||
{
|
||||
char *q, *r, *s;
|
||||
char buf1[64], buf2[64];
|
||||
size_t l[8];
|
||||
/* These two strlen calls stay, all strcpy calls are optimized into
|
||||
memcpy, all strchr calls optimized away, and most other strlen
|
||||
calls too. */
|
||||
l[0] = strlen (y);
|
||||
l[1] = strlen (z);
|
||||
strcpy (buf1, y);
|
||||
strcpy (buf2, z);
|
||||
strcpy (p, "abcde");
|
||||
q = strchr (p, '\0');
|
||||
strcpy (q, "efghi");
|
||||
r = strchr (q, '\0');
|
||||
strcpy (r, buf1);
|
||||
l[2] = strlen (p);
|
||||
l[3] = strlen (q);
|
||||
l[4] = strlen (r);
|
||||
strcpy (r, buf2);
|
||||
/* Except for these two calls, strlen (r) before and after the above
|
||||
is non-constant, so adding l[4] - l[1] to all previous strlens
|
||||
might make the expressions already too complex. */
|
||||
l[5] = strlen (p);
|
||||
l[6] = strlen (q);
|
||||
/* This one is of course optimized, it is l[1]. */
|
||||
l[7] = strlen (r);
|
||||
memcpy (lp, l, sizeof l);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char buf[64];
|
||||
size_t l[8];
|
||||
const char *volatile y = "ABCDEFG";
|
||||
const char *volatile z = "HIJK";
|
||||
memset (buf, '\0', sizeof buf);
|
||||
fn1 (buf, y, z, l);
|
||||
if (memcmp (buf, "abcdeefghiHIJK", 15) != 0)
|
||||
abort ();
|
||||
if (l[0] != 7 || l[1] != 4)
|
||||
abort ();
|
||||
if (l[2] != 17 || l[3] != 12 || l[4] != 7)
|
||||
abort ();
|
||||
if (l[5] != 14 || l[6] != 9 || l[7] != 4)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.0. = " 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.1. = " 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.5. = " 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times " D\.\[0-9_\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.6. = " 1 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
115
gcc/testsuite/gcc.dg/strlenopt-14g.c
Normal file
115
gcc/testsuite/gcc.dg/strlenopt-14g.c
Normal file
@ -0,0 +1,115 @@
|
||||
/* This test needs runtime that provides stpcpy and mempcpy functions. */
|
||||
/* { dg-do run { target *-*-linux* } } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#define USE_GNU
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn1 (char *p, size_t *l1, size_t *l2)
|
||||
{
|
||||
char *a = mempcpy (p, "abcde", 6);
|
||||
/* This strlen needs to stay. */
|
||||
size_t la = strlen (a);
|
||||
/* This strlen can be optimized into 5. */
|
||||
size_t lp = strlen (p);
|
||||
*l1 = la;
|
||||
*l2 = lp;
|
||||
return a;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn2 (char *p, const char *q, size_t *l1, size_t *l2, size_t *l3)
|
||||
{
|
||||
/* This strlen needs to stay. */
|
||||
size_t lq = strlen (q);
|
||||
char *a = mempcpy (p, q, lq + 1);
|
||||
/* This strlen needs to stay. */
|
||||
size_t la = strlen (a);
|
||||
/* This strlen can be optimized into lq. */
|
||||
size_t lp = strlen (p);
|
||||
*l1 = lq;
|
||||
*l2 = la;
|
||||
*l3 = lp;
|
||||
return a;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn3 (char *p, size_t *l1, size_t *l2)
|
||||
{
|
||||
char *a = stpcpy (p, "abcde");
|
||||
/* This strlen can be optimized into 0. */
|
||||
size_t la = strlen (a);
|
||||
/* This strlen can be optimized into 5. */
|
||||
size_t lp = strlen (p);
|
||||
*l1 = la;
|
||||
*l2 = lp;
|
||||
return a;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn4 (char *p, const char *q, size_t *l1, size_t *l2, size_t *l3)
|
||||
{
|
||||
/* This strlen needs to stay. */
|
||||
size_t lq = strlen (q);
|
||||
char *a = stpcpy (p, q);
|
||||
/* This strlen can be optimized into 0. */
|
||||
size_t la = strlen (a);
|
||||
/* This strlen can be optimized into lq. */
|
||||
size_t lp = strlen (p);
|
||||
*l1 = lq;
|
||||
*l2 = la;
|
||||
*l3 = lp;
|
||||
return a;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn5 (char *p, const char *q, size_t *l1, size_t *l2)
|
||||
{
|
||||
char *a = stpcpy (p, q);
|
||||
/* This strlen can be optimized into 0. */
|
||||
size_t la = strlen (a);
|
||||
/* This strlen can be optimized into a - p. */
|
||||
size_t lp = strlen (p);
|
||||
*l1 = la;
|
||||
*l2 = lp;
|
||||
return a;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char buf[64];
|
||||
const char *volatile q = "ABCDEFGH";
|
||||
size_t l1, l2, l3;
|
||||
memset (buf, '\0', sizeof buf);
|
||||
memset (buf + 6, 'z', 7);
|
||||
if (fn1 (buf, &l1, &l2) != buf + 6 || l1 != 7 || l2 != 5
|
||||
|| memcmp (buf, "abcde\0zzzzzzz", 14) != 0)
|
||||
abort ();
|
||||
if (fn2 (buf, q, &l1, &l2, &l3) != buf + 9 || l1 != 8 || l2 != 4 || l3 != 8
|
||||
|| memcmp (buf, "ABCDEFGH\0zzzz", 14) != 0)
|
||||
abort ();
|
||||
if (fn3 (buf, &l1, &l2) != buf + 5 || l1 != 0 || l2 != 5
|
||||
|| memcmp (buf, "abcde\0GH\0zzzz", 14) != 0)
|
||||
abort ();
|
||||
l3 = 0;
|
||||
memset (buf, 'n', 9);
|
||||
if (fn4 (buf, q, &l1, &l2, &l3) != buf + 8 || l1 != 8 || l2 != 0 || l3 != 8
|
||||
|| memcmp (buf, "ABCDEFGH\0zzzz", 14) != 0)
|
||||
abort ();
|
||||
memset (buf, 'm', 9);
|
||||
if (fn5 (buf, q, &l1, &l2) != buf + 8 || l1 != 0 || l2 != 8
|
||||
|| memcmp (buf, "ABCDEFGH\0zzzz", 14) != 0)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
24
gcc/testsuite/gcc.dg/strlenopt-14gf.c
Normal file
24
gcc/testsuite/gcc.dg/strlenopt-14gf.c
Normal file
@ -0,0 +1,24 @@
|
||||
/* This test needs runtime that provides stpcpy, mempcpy and __*_chk
|
||||
functions. */
|
||||
/* { dg-do run { target *-*-linux* } } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#define FORTIFY_SOURCE 2
|
||||
#include "strlenopt-14g.c"
|
||||
|
||||
/* Compared to strlenopt-14gf.c, strcpy_chk with string literal as
|
||||
second argument isn't being optimized by builtins.c into
|
||||
memcpy. */
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__mempcpy_chk \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 3 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
60
gcc/testsuite/gcc.dg/strlenopt-15.c
Normal file
60
gcc/testsuite/gcc.dg/strlenopt-15.c
Normal file
@ -0,0 +1,60 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn1 (char *p, size_t l)
|
||||
{
|
||||
memcpy (p, "abcdef", l);
|
||||
/* This strlen can't be optimized, as l is unknown. */
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn2 (char *p, const char *q, size_t *lp)
|
||||
{
|
||||
size_t l = strlen (q), l2;
|
||||
memcpy (p, q, 7);
|
||||
/* This strlen can't be optimized, as l might be bigger than 7. */
|
||||
l2 = strlen (p);
|
||||
*lp = l;
|
||||
return l2;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn3 (char *p)
|
||||
{
|
||||
*p = 0;
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char buf[64];
|
||||
const char *volatile q = "ABCDEFGH";
|
||||
const char *volatile q2 = "IJ\0KLMNOPQRS";
|
||||
size_t l;
|
||||
memset (buf, '\0', sizeof buf);
|
||||
memset (buf + 2, 'a', 7);
|
||||
if (fn1 (buf, 3) != 9 || memcmp (buf, "abcaaaaaa", 10) != 0)
|
||||
abort ();
|
||||
if (fn1 (buf, 7) != 6 || memcmp (buf, "abcdef\0aa", 10) != 0)
|
||||
abort ();
|
||||
if (fn2 (buf, q, &l) != 9 || l != 8 || memcmp (buf, "ABCDEFGaa", 10) != 0)
|
||||
abort ();
|
||||
if (fn2 (buf, q2, &l) != 2 || l != 2 || memcmp (buf, "IJ\0KLMNaa", 10) != 0)
|
||||
abort ();
|
||||
if (fn3 (buf) != buf + 1 || memcmp (buf, "\0J\0KLMNaa", 10) != 0)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
34
gcc/testsuite/gcc.dg/strlenopt-16g.c
Normal file
34
gcc/testsuite/gcc.dg/strlenopt-16g.c
Normal file
@ -0,0 +1,34 @@
|
||||
/* This test needs runtime that provides stpcpy function. */
|
||||
/* { dg-do run { target *-*-linux* } } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#define USE_GNU
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn1 (char *p, const char *q)
|
||||
{
|
||||
/* This strcpy can be optimized into stpcpy. */
|
||||
strcpy (p, q);
|
||||
/* And this strchr into the return value from it. */
|
||||
return strchr (p, '\0');
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char buf[64];
|
||||
const char *volatile q = "ABCDEFGH";
|
||||
if (fn1 (buf, q) != buf + 8 || memcmp (buf, "ABCDEFGH", 9) != 0)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
57
gcc/testsuite/gcc.dg/strlenopt-17g.c
Normal file
57
gcc/testsuite/gcc.dg/strlenopt-17g.c
Normal file
@ -0,0 +1,57 @@
|
||||
/* This test needs runtime that provides stpcpy function. */
|
||||
/* { dg-do run { target *-*-linux* } } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#define USE_GNU
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) int
|
||||
foo (const char *p)
|
||||
{
|
||||
static int c;
|
||||
const char *q[] = { "123498765abcde", "123498765..", "129abcde", "129abcde" };
|
||||
if (strcmp (p, q[c]) != 0)
|
||||
abort ();
|
||||
return c++;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
bar (const char *p, const char *q)
|
||||
{
|
||||
size_t l;
|
||||
/* This strlen stays. */
|
||||
char *a = __builtin_alloca (strlen (p) + 50);
|
||||
/* strcpy can be optimized into memcpy. */
|
||||
strcpy (a, p);
|
||||
/* strcat into stpcpy. */
|
||||
strcat (a, q);
|
||||
/* This strlen can be optimized away. */
|
||||
l = strlen (a);
|
||||
/* This becomes memcpy. */
|
||||
strcat (a, "abcde");
|
||||
if (!foo (a))
|
||||
/* And this one too. */
|
||||
strcpy (a + l, "..");
|
||||
foo (a);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
const char *volatile s1 = "1234";
|
||||
const char *volatile s2 = "98765";
|
||||
const char *volatile s3 = "12";
|
||||
const char *volatile s4 = "9";
|
||||
bar (s1, s2);
|
||||
bar (s3, s4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
82
gcc/testsuite/gcc.dg/strlenopt-18g.c
Normal file
82
gcc/testsuite/gcc.dg/strlenopt-18g.c
Normal file
@ -0,0 +1,82 @@
|
||||
/* This test needs runtime that provides stpcpy function. */
|
||||
/* { dg-do run { target *-*-linux* } } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#define USE_GNU
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn1 (int x, int y, int z)
|
||||
{
|
||||
static char buf[40];
|
||||
const char *p;
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
p = "abcd";
|
||||
break;
|
||||
case 1:
|
||||
p = "efgh";
|
||||
break;
|
||||
case 2:
|
||||
p = "ijkl";
|
||||
break;
|
||||
default:
|
||||
p = "mnopq";
|
||||
break;
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
strcpy (buf, p);
|
||||
if (z)
|
||||
strcat (buf, "ABCDEFG");
|
||||
else
|
||||
strcat (buf, "HIJKLMN");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (buf, p + 1);
|
||||
if (z)
|
||||
strcat (buf, "OPQ");
|
||||
else
|
||||
strcat (buf, "RST");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
const char *p = "abcdefghijklmnopq" + (i < 3 ? i : 3) * 4;
|
||||
const char *q;
|
||||
int j = i >= 3;
|
||||
fn1 (i ? 0 : 1, 1, 1);
|
||||
q = fn1 (i, 0, 0);
|
||||
if (memcmp (q, p + 1, 3 + j) != 0 || memcmp (q + 3 + j, "RST", 4) != 0)
|
||||
abort ();
|
||||
fn1 (i ? 0 : 1, 0, 1);
|
||||
q = fn1 (i, 1, 0);
|
||||
if (memcmp (q, p, 4 + j) != 0 || memcmp (q + 4 + j, "HIJKLMN", 8) != 0)
|
||||
abort ();
|
||||
fn1 (i ? 0 : 1, 1, 0);
|
||||
q = fn1 (i, 0, 1);
|
||||
if (memcmp (q, p + 1, 3 + j) != 0 || memcmp (q + 3 + j, "OPQ", 4) != 0)
|
||||
abort ();
|
||||
fn1 (i ? 0 : 1, 0, 0);
|
||||
q = fn1 (i, 1, 1);
|
||||
if (memcmp (q, p, 4 + j) != 0 || memcmp (q + 4 + j, "ABCDEFG", 8) != 0)
|
||||
abort ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
81
gcc/testsuite/gcc.dg/strlenopt-19.c
Normal file
81
gcc/testsuite/gcc.dg/strlenopt-19.c
Normal file
@ -0,0 +1,81 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn1 (int x, int y, int z)
|
||||
{
|
||||
static char buf[40];
|
||||
const char *p;
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
p = "abcd";
|
||||
/* Prevent cswitch optimization. */
|
||||
asm volatile ("" : : : "memory");
|
||||
break;
|
||||
case 1:
|
||||
p = "efgh";
|
||||
break;
|
||||
case 2:
|
||||
p = "ijkl";
|
||||
break;
|
||||
default:
|
||||
p = "mnop";
|
||||
break;
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
strcpy (buf, p);
|
||||
if (z)
|
||||
strcat (buf, "ABCDEFG");
|
||||
else
|
||||
strcat (buf, "HIJKLMN");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (buf, p + 1);
|
||||
if (z)
|
||||
strcat (buf, "OPQ");
|
||||
else
|
||||
strcat (buf, "RST");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
const char *p = "abcdefghijklmnop" + (i < 3 ? i : 3) * 4;
|
||||
const char *q;
|
||||
fn1 (i ? 0 : 1, 1, 1);
|
||||
q = fn1 (i, 0, 0);
|
||||
if (memcmp (q, p + 1, 3) != 0 || memcmp (q + 3, "RST", 4) != 0)
|
||||
abort ();
|
||||
fn1 (i ? 0 : 1, 0, 1);
|
||||
q = fn1 (i, 1, 0);
|
||||
if (memcmp (q, p, 4) != 0 || memcmp (q + 4, "HIJKLMN", 8) != 0)
|
||||
abort ();
|
||||
fn1 (i ? 0 : 1, 1, 0);
|
||||
q = fn1 (i, 0, 1);
|
||||
if (memcmp (q, p + 1, 3) != 0 || memcmp (q + 3, "OPQ", 4) != 0)
|
||||
abort ();
|
||||
fn1 (i ? 0 : 1, 0, 0);
|
||||
q = fn1 (i, 1, 1);
|
||||
if (memcmp (q, p, 4) != 0 || memcmp (q + 4, "ABCDEFG", 8) != 0)
|
||||
abort ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
18
gcc/testsuite/gcc.dg/strlenopt-1f.c
Normal file
18
gcc/testsuite/gcc.dg/strlenopt-1f.c
Normal file
@ -0,0 +1,18 @@
|
||||
/* This test needs runtime that provides __*_chk functions. */
|
||||
/* { dg-do run { target *-*-linux* } } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#define FORTIFY_SOURCE 2
|
||||
#include "strlenopt-1.c"
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 3 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
49
gcc/testsuite/gcc.dg/strlenopt-2.c
Normal file
49
gcc/testsuite/gcc.dg/strlenopt-2.c
Normal file
@ -0,0 +1,49 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
foo (char *p, char *r)
|
||||
{
|
||||
char buf[26];
|
||||
if (strlen (p) + strlen (r) + 9 > 26)
|
||||
return NULL;
|
||||
/* This strcpy can be optimized into memcpy, using the remembered
|
||||
strlen (p). */
|
||||
strcpy (buf, p);
|
||||
/* These two strcat can be optimized into memcpy. The first one
|
||||
could be even optimized into a *ptr = '/'; store as the '\0'
|
||||
is immediately overwritten. */
|
||||
strcat (buf, "/");
|
||||
strcat (buf, "abcde");
|
||||
/* This strcpy can be optimized into memcpy, using the remembered
|
||||
strlen (r). */
|
||||
strcat (buf, r);
|
||||
/* And this can be optimized into memcpy too. */
|
||||
strcat (buf, "fg");
|
||||
return strdup (buf);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char *volatile p = "string1";
|
||||
char *volatile r = "string2";
|
||||
char *q = foo (p, r);
|
||||
if (q != NULL)
|
||||
{
|
||||
if (strcmp (q, "string1/abcdestring2fg"))
|
||||
abort ();
|
||||
free (q);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 5 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
95
gcc/testsuite/gcc.dg/strlenopt-20.c
Normal file
95
gcc/testsuite/gcc.dg/strlenopt-20.c
Normal file
@ -0,0 +1,95 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) const char *
|
||||
fn1 (int x, int y)
|
||||
{
|
||||
const char *p;
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
p = "abcd";
|
||||
/* Prevent cswitch optimization. */
|
||||
asm volatile ("" : : : "memory");
|
||||
break;
|
||||
case 1:
|
||||
p = "efgh";
|
||||
break;
|
||||
case 2:
|
||||
p = "ijkl";
|
||||
break;
|
||||
default:
|
||||
p = "mnop";
|
||||
break;
|
||||
}
|
||||
if (y)
|
||||
/* strchr should be optimized into p + 4 here. */
|
||||
return strchr (p, '\0');
|
||||
else
|
||||
/* and strlen into 3. */
|
||||
return p + strlen (p + 1);
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn2 (char *p, char *q)
|
||||
{
|
||||
size_t l;
|
||||
/* Both strcpy calls can be optimized into memcpy, strlen needs to stay. */
|
||||
strcpy (p, "abc");
|
||||
p[3] = 'd';
|
||||
l = strlen (p);
|
||||
strcpy (q, p);
|
||||
return l;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn3 (char *p)
|
||||
{
|
||||
char *c;
|
||||
/* The strcpy call can be optimized into memcpy, strchr needs to stay,
|
||||
strcat is optimized into memcpy. */
|
||||
strcpy (p, "abc");
|
||||
p[3] = 'd';
|
||||
c = strchr (p, '\0');
|
||||
strcat (p, "efgh");
|
||||
return c;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
int i;
|
||||
char buf[64], buf2[64];
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
const char *p = "abcdefghijklmnop" + (i < 3 ? i : 3) * 4;
|
||||
const char *q;
|
||||
q = fn1 (i, 1);
|
||||
if (memcmp (q - 4, p, 4) != 0 || q[0] != '\0')
|
||||
abort ();
|
||||
q = fn1 (i, 0);
|
||||
if (memcmp (q - 3, p, 4) != 0 || q[1] != '\0')
|
||||
abort ();
|
||||
}
|
||||
memset (buf, '\0', sizeof buf);
|
||||
memset (buf + 4, 'z', 2);
|
||||
if (fn2 (buf, buf2) != 6
|
||||
|| memcmp (buf, "abcdzz", 7) != 0
|
||||
|| memcmp (buf2, "abcdzz", 7) != 0)
|
||||
abort ();
|
||||
memset (buf, '\0', sizeof buf);
|
||||
memset (buf + 4, 'z', 2);
|
||||
if (fn3 (buf) != buf + 6 || memcmp (buf, "abcdzzefgh", 11) != 0)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
18
gcc/testsuite/gcc.dg/strlenopt-2f.c
Normal file
18
gcc/testsuite/gcc.dg/strlenopt-2f.c
Normal file
@ -0,0 +1,18 @@
|
||||
/* This test needs runtime that provides __*_chk functions. */
|
||||
/* { dg-do run { target *-*-linux* } } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#define FORTIFY_SOURCE 2
|
||||
#include "strlenopt-2.c"
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 5 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
66
gcc/testsuite/gcc.dg/strlenopt-3.c
Normal file
66
gcc/testsuite/gcc.dg/strlenopt-3.c
Normal file
@ -0,0 +1,66 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen -fdump-tree-optimized" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn1 (char *p, char *q)
|
||||
{
|
||||
size_t s = strlen (q);
|
||||
strcpy (p, q);
|
||||
return s - strlen (p);
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn2 (char *p, char *q)
|
||||
{
|
||||
size_t s = strlen (q);
|
||||
memcpy (p, q, s + 1);
|
||||
return s - strlen (p);
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn3 (char *p)
|
||||
{
|
||||
memcpy (p, "abcd", 5);
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn4 (char *p)
|
||||
{
|
||||
memcpy (p, "efg\0hij", 6);
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char buf[64];
|
||||
char *volatile p = buf;
|
||||
char *volatile q = "ABCDEF";
|
||||
buf[7] = 'G';
|
||||
if (fn1 (p, q) != 0 || memcmp (buf, "ABCDEF\0G", 8))
|
||||
abort ();
|
||||
q = "HIJ";
|
||||
if (fn2 (p + 1, q) != 0 || memcmp (buf, "AHIJ\0F\0G", 8))
|
||||
abort ();
|
||||
buf[6] = 'K';
|
||||
if (fn3 (p + 1) != 4 || memcmp (buf, "Aabcd\0KG", 8))
|
||||
abort ();
|
||||
if (fn4 (p) != 3 || memcmp (buf, "efg\0hiKG", 8))
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "return 0" 3 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "return 4" 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "return 3" 1 "optimized" } } */
|
||||
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
75
gcc/testsuite/gcc.dg/strlenopt-4.c
Normal file
75
gcc/testsuite/gcc.dg/strlenopt-4.c
Normal file
@ -0,0 +1,75 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
/* If stpcpy can't be used, this is optimized into
|
||||
strcpy (p, q); strcat (p, r); memcpy (p + strlen (p), "abcd", 5);
|
||||
If stpcpy can be used (see strlenopt-4g.c test),
|
||||
this is optimized into
|
||||
memcpy (stpcpy (stpcpy (p, q), r), "abcd", 5); */
|
||||
__attribute__((noinline, noclone)) void
|
||||
foo (char *p, const char *q, const char *r)
|
||||
{
|
||||
strcpy (p, q);
|
||||
strcat (p, r);
|
||||
strcat (p, "abcd");
|
||||
}
|
||||
|
||||
/* If stpcpy can't be used, this is optimized into
|
||||
memcpy (p, "abcd", 4); strcpy (p + 4, q); strcat (p, r);
|
||||
If stpcpy can be used, this is optimized into
|
||||
memcpy (p, "abcd", 4); strcpy (stpcpy (p + 4, q), r); */
|
||||
__attribute__((noinline, noclone)) void
|
||||
bar (char *p, const char *q, const char *r)
|
||||
{
|
||||
strcpy (p, "abcd");
|
||||
strcat (p, q);
|
||||
strcat (p, r);
|
||||
}
|
||||
|
||||
/* If stpcpy can't be used, this is optimized into
|
||||
strcat (p, q); memcpy (t1 = p + strlen (p), "abcd", 4);
|
||||
strcpy (t1 + 4, r); memcpy (p + strlen (p), "efgh", 5);
|
||||
If stpcpy can be used, this is optimized into
|
||||
t1 = stpcpy (p + strlen (p), q); memcpy (t1, "abcd", 4);
|
||||
memcpy (stpcpy (t1 + 4, r), "efgh", 5); */
|
||||
__attribute__((noinline, noclone)) void
|
||||
baz (char *p, const char *q, const char *r)
|
||||
{
|
||||
strcat (p, q);
|
||||
strcat (p, "abcd");
|
||||
strcat (p, r);
|
||||
strcat (p, "efgh");
|
||||
}
|
||||
|
||||
char buf[64];
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char *volatile p = buf;
|
||||
const char *volatile q = "ij";
|
||||
const char *volatile r = "klmno";
|
||||
foo (p, q, r);
|
||||
if (memcmp (buf, "ijklmnoabcd\0\0\0\0\0\0\0\0", 20) != 0)
|
||||
abort ();
|
||||
memset (buf, '\0', sizeof buf);
|
||||
bar (p, q, r);
|
||||
if (memcmp (buf, "abcdijklmno\0\0\0\0\0\0\0\0", 20) != 0)
|
||||
abort ();
|
||||
memset (buf, 'v', 3);
|
||||
memset (buf + 3, '\0', -3 + sizeof buf);
|
||||
baz (p, q, r);
|
||||
if (memcmp (buf, "vvvijabcdklmnoefgh\0", 20) != 0)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 3 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 3 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
14
gcc/testsuite/gcc.dg/strlenopt-4g.c
Normal file
14
gcc/testsuite/gcc.dg/strlenopt-4g.c
Normal file
@ -0,0 +1,14 @@
|
||||
/* This test needs runtime that provides stpcpy function. */
|
||||
/* { dg-do run { target *-*-linux* } } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#define USE_GNU
|
||||
#include "strlenopt-4.c"
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 5 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
19
gcc/testsuite/gcc.dg/strlenopt-4gf.c
Normal file
19
gcc/testsuite/gcc.dg/strlenopt-4gf.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* This test needs runtime that provides stpcpy and __*_chk functions. */
|
||||
/* { dg-do run { target *-*-linux* } } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#define USE_GNU
|
||||
#define FORTIFY_SOURCE 2
|
||||
#include "strlenopt-4.c"
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 5 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
57
gcc/testsuite/gcc.dg/strlenopt-5.c
Normal file
57
gcc/testsuite/gcc.dg/strlenopt-5.c
Normal file
@ -0,0 +1,57 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
foo (char *p, const char *q)
|
||||
{
|
||||
char *e = strchr (p, '\0');
|
||||
strcat (p, q);
|
||||
return e;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
bar (char *p)
|
||||
{
|
||||
memcpy (p, "abcd", 5);
|
||||
return strchr (p, '\0');
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
baz (char *p)
|
||||
{
|
||||
char *e = strchr (p, '\0');
|
||||
strcat (e, "abcd");
|
||||
}
|
||||
|
||||
char buf[64];
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char *volatile p = buf;
|
||||
const char *volatile q = "ij";
|
||||
memset (buf, 'v', 3);
|
||||
if (foo (p, q) != buf + 3
|
||||
|| memcmp (buf, "vvvij\0\0\0\0", 10) != 0)
|
||||
abort ();
|
||||
memset (buf, '\0', sizeof buf);
|
||||
if (bar (p) != buf + 4
|
||||
|| memcmp (buf, "abcd\0\0\0\0\0", 10) != 0)
|
||||
abort ();
|
||||
memset (buf, 'v', 2);
|
||||
memset (buf + 2, '\0', -2 + sizeof buf);
|
||||
baz (p);
|
||||
if (memcmp (buf, "vvabcd\0\0\0", 10) != 0)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
86
gcc/testsuite/gcc.dg/strlenopt-6.c
Normal file
86
gcc/testsuite/gcc.dg/strlenopt-6.c
Normal file
@ -0,0 +1,86 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
foo (char *x)
|
||||
{
|
||||
#ifdef PR50262_FIXED
|
||||
/* Once PTA is fixed, we'll need just one strlen here,
|
||||
without the memcpy. */
|
||||
char *p = x;
|
||||
char *q = malloc (strlen (p) + 64);
|
||||
#else
|
||||
/* This is here just because PTA can't figure that
|
||||
*q = '\0' store below can't change p's length.
|
||||
In this case we have one strlen and one memcpy here. */
|
||||
char b[64];
|
||||
char *q = malloc (strlen (x) + 64);
|
||||
char *p = strcpy (b, x);
|
||||
#endif
|
||||
char *r;
|
||||
if (q == NULL) return NULL;
|
||||
/* This store can be optimized away once strcat is
|
||||
replaced with memcpy. */
|
||||
*q = '\0';
|
||||
/* These two strcat calls can be optimized into memcpy calls. */
|
||||
strcat (q, p);
|
||||
strcat (q, "/");
|
||||
/* The strchr can be optimized away, as we know the current
|
||||
string length as well as end pointer. */
|
||||
r = strchr (q, '\0');
|
||||
/* This store can go, as it is overwriting '\0' with the same
|
||||
character. */
|
||||
*r = '\0';
|
||||
/* And this strcat can be again optimized into memcpy call. */
|
||||
strcat (q, "abcde");
|
||||
return q;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
bar (char *p)
|
||||
{
|
||||
char buf[26];
|
||||
char *r;
|
||||
if (strlen (p) + 9 > 26)
|
||||
return NULL;
|
||||
*buf = '\0';
|
||||
strcat (buf, p);
|
||||
strcat (buf, "/");
|
||||
r = strchr (buf, '\0');
|
||||
*r = '\0';
|
||||
strcat (buf, "abcde");
|
||||
return strdup (buf);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char *volatile p = "string1";
|
||||
char *volatile r = "string2";
|
||||
char *q = foo (p);
|
||||
if (q != NULL)
|
||||
{
|
||||
if (strcmp (q, "string1/abcde"))
|
||||
abort ();
|
||||
memset (q, '\0', 14);
|
||||
free (q);
|
||||
}
|
||||
q = bar (p);
|
||||
if (q != NULL)
|
||||
{
|
||||
if (strcmp (q, "string1/abcde"))
|
||||
abort ();
|
||||
free (q);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
53
gcc/testsuite/gcc.dg/strlenopt-7.c
Normal file
53
gcc/testsuite/gcc.dg/strlenopt-7.c
Normal file
@ -0,0 +1,53 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen -fdump-tree-optimized" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
char buf[64];
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
foo (void)
|
||||
{
|
||||
char *p = memcpy (buf, "abcdefgh", 9);
|
||||
/* This store can be optimized away as... */
|
||||
*p = '\0';
|
||||
/* ... the following strcat can be optimized into memcpy,
|
||||
which overwrites that '\0'. */
|
||||
strcat (p, "ijk");
|
||||
/* This should be optimized into return 3. */
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
bar (char *p)
|
||||
{
|
||||
char *r = strchr (p, '\0');
|
||||
/* This store shouldn't be optimized away, because we
|
||||
want to crash if p is e.g. a string literal. */
|
||||
*r = '\0';
|
||||
/* This strlen can be optimized into 0. */
|
||||
return strlen (r);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char *volatile p = buf;
|
||||
if (foo () != 3 || memcmp (buf, "ijk\0efgh\0", 10) != 0)
|
||||
abort ();
|
||||
if (bar (p) != 0 || memcmp (buf, "ijk\0efgh\0", 10) != 0)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "\\*r_\[0-9\]* = 0;" 1 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "return 3;" 1 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "return 0;" 2 "optimized" } } */
|
||||
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
52
gcc/testsuite/gcc.dg/strlenopt-8.c
Normal file
52
gcc/testsuite/gcc.dg/strlenopt-8.c
Normal file
@ -0,0 +1,52 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
/* Yes, there are people who write code like this. */
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
foo (int r)
|
||||
{
|
||||
char buf[10] = "";
|
||||
strcat (buf, r ? "r" : "w");
|
||||
strcat (buf, "b");
|
||||
return strdup (buf);
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
bar (int r)
|
||||
{
|
||||
char buf[10] = {};
|
||||
strcat (buf, r ? "r" : "w");
|
||||
strcat (buf, "b");
|
||||
return strdup (buf);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char *q = foo (1);
|
||||
if (q != NULL)
|
||||
{
|
||||
if (strcmp (q, "rb"))
|
||||
abort ();
|
||||
free (q);
|
||||
}
|
||||
q = bar (0);
|
||||
if (q != NULL)
|
||||
{
|
||||
if (strcmp (q, "wb"))
|
||||
abort ();
|
||||
free (q);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
109
gcc/testsuite/gcc.dg/strlenopt-9.c
Normal file
109
gcc/testsuite/gcc.dg/strlenopt-9.c
Normal file
@ -0,0 +1,109 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen -fdump-tree-optimized" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) char *
|
||||
fn1 (int r)
|
||||
{
|
||||
char *p = r ? "a" : "bc";
|
||||
/* String length for p varies, therefore strchr below isn't
|
||||
optimized away. */
|
||||
return strchr (p, '\0');
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn2 (int r)
|
||||
{
|
||||
char *p, q[10];
|
||||
strcpy (q, "abc");
|
||||
p = r ? "a" : q;
|
||||
/* String length for p varies, therefore strlen below isn't
|
||||
optimized away. */
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn3 (char *p, int n)
|
||||
{
|
||||
int i;
|
||||
p = strchr (p, '\0');
|
||||
/* strcat here can be optimized into memcpy. */
|
||||
strcat (p, "abcd");
|
||||
for (i = 0; i < n; i++)
|
||||
if ((i % 123) == 53)
|
||||
/* strcat here is optimized into strlen and memcpy. */
|
||||
strcat (p, "efg");
|
||||
/* The strlen here can't be optimized away, as in the loop string
|
||||
length of p might change. */
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
char buf[64];
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn4 (char *x, int n)
|
||||
{
|
||||
int i;
|
||||
size_t l;
|
||||
char a[64];
|
||||
char *p = strchr (x, '\0');
|
||||
/* strcpy here is optimized into memcpy, length computed as p - x + 1. */
|
||||
strcpy (a, x);
|
||||
/* strcat here is optimized into memcpy. */
|
||||
strcat (p, "abcd");
|
||||
for (i = 0; i < n; i++)
|
||||
if ((i % 123) == 53)
|
||||
/* strcat here is optimized into strlen and memcpy. */
|
||||
strcat (a, "efg");
|
||||
/* The strlen should be optimized here into 4. */
|
||||
l = strlen (p);
|
||||
/* This stays strcpy. */
|
||||
strcpy (buf, a);
|
||||
return l;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
volatile int l = 1;
|
||||
char b[64];
|
||||
|
||||
if (memcmp (fn1 (l) - 1, "a", 2) != 0)
|
||||
abort ();
|
||||
if (memcmp (fn1 (!l) - 2, "bc", 3) != 0)
|
||||
abort ();
|
||||
if (fn2 (l) != 1 || fn2 (!l) != 3)
|
||||
abort ();
|
||||
memset (b, '\0', sizeof b);
|
||||
memset (b, 'a', 3);
|
||||
if (fn3 (b, 10) != 4 || memcmp (b, "aaaabcd", 8) != 0)
|
||||
abort ();
|
||||
if (fn3 (b, 128) != 7 || memcmp (b, "aaaabcdabcdefg", 15) != 0)
|
||||
abort ();
|
||||
if (fn3 (b, 256) != 10 || memcmp (b, "aaaabcdabcdefgabcdefgefg", 25) != 0)
|
||||
abort ();
|
||||
if (fn4 (b, 10) != 4
|
||||
|| memcmp (b, "aaaabcdabcdefgabcdefgefgabcd", 29) != 0
|
||||
|| memcmp (buf, "aaaabcdabcdefgabcdefgefg", 25) != 0)
|
||||
abort ();
|
||||
if (fn4 (b, 128) != 4
|
||||
|| memcmp (b, "aaaabcdabcdefgabcdefgefgabcdabcd", 33) != 0
|
||||
|| memcmp (buf, "aaaabcdabcdefgabcdefgefgabcdefg", 32) != 0)
|
||||
abort ();
|
||||
if (fn4 (b, 256) != 4
|
||||
|| memcmp (b, "aaaabcdabcdefgabcdefgefgabcdabcdabcd", 37) != 0
|
||||
|| memcmp (buf, "aaaabcdabcdefgabcdefgefgabcdabcdefgefg", 39) != 0)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strchr \\(" 3 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "return 4;" 1 "optimized" } } */
|
||||
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
59
gcc/testsuite/gcc.dg/strlenopt.h
Normal file
59
gcc/testsuite/gcc.dg/strlenopt.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* This is a replacement of needed parts from stdlib.h and string.h
|
||||
for -foptimize-strlen testing, to ensure we are testing the builtins
|
||||
rather than whatever the OS has in its headers. */
|
||||
|
||||
#define NULL ((void *) 0)
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
extern void abort (void);
|
||||
void *malloc (size_t);
|
||||
void free (void *);
|
||||
char *strdup (const char *);
|
||||
size_t strlen (const char *);
|
||||
void *memcpy (void *__restrict, const void *__restrict, size_t);
|
||||
char *strcpy (char *__restrict, const char *__restrict);
|
||||
char *strcat (char *__restrict, const char *__restrict);
|
||||
char *strchr (const char *, int);
|
||||
void *memset (void *, int, size_t);
|
||||
int memcmp (const void *, const void *, size_t);
|
||||
int strcmp (const char *, const char *);
|
||||
#ifdef USE_GNU
|
||||
void *mempcpy (void *__restrict, const void *__restrict, size_t);
|
||||
char *stpcpy (char *__restrict, const char *__restrict);
|
||||
#endif
|
||||
|
||||
#if defined(FORTIFY_SOURCE) && FORTIFY_SOURCE > 0 && __OPTIMIZE__
|
||||
# define bos(ptr) __builtin_object_size (ptr, FORTIFY_SOURCE > 0)
|
||||
# define bos0(ptr) __builtin_object_size (ptr, 0)
|
||||
|
||||
extern inline __attribute__((gnu_inline, always_inline, artificial)) void *
|
||||
memcpy (void *__restrict dest, const void *__restrict src, size_t len)
|
||||
{
|
||||
return __builtin___memcpy_chk (dest, src, len, bos0 (dest));
|
||||
}
|
||||
|
||||
extern inline __attribute__((gnu_inline, always_inline, artificial)) char *
|
||||
strcpy (char *__restrict dest, const char *__restrict src)
|
||||
{
|
||||
return __builtin___strcpy_chk (dest, src, bos (dest));
|
||||
}
|
||||
|
||||
extern inline __attribute__((gnu_inline, always_inline, artificial)) char *
|
||||
strcat (char *__restrict dest, const char *__restrict src)
|
||||
{
|
||||
return __builtin___strcat_chk (dest, src, bos (dest));
|
||||
}
|
||||
|
||||
# ifdef USE_GNU
|
||||
extern inline __attribute__((gnu_inline, always_inline, artificial)) void *
|
||||
mempcpy (void *__restrict dest, const void *__restrict src, size_t len)
|
||||
{
|
||||
return __builtin___mempcpy_chk (dest, src, len, bos0 (dest));
|
||||
}
|
||||
|
||||
extern inline __attribute__((gnu_inline, always_inline, artificial)) char *
|
||||
stpcpy (char *__restrict dest, const char *__restrict src)
|
||||
{
|
||||
return __builtin___stpcpy_chk (dest, src, bos (dest));
|
||||
}
|
||||
# endif
|
||||
#endif
|
@ -1,7 +1,7 @@
|
||||
/* This file contains the definitions for timing variables used to
|
||||
measure run-time performance of the compiler.
|
||||
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
||||
2009, 2010
|
||||
2009, 2010, 2011
|
||||
Free Software Foundation, Inc.
|
||||
Contributed by Alex Samuel <samuel@codesourcery.com>
|
||||
|
||||
@ -184,6 +184,7 @@ DEFTIMEVAR (TV_TREE_COPY_RENAME , "tree rename SSA copies")
|
||||
DEFTIMEVAR (TV_TREE_SSA_VERIFY , "tree SSA verifier")
|
||||
DEFTIMEVAR (TV_TREE_STMT_VERIFY , "tree STMT verifier")
|
||||
DEFTIMEVAR (TV_TREE_SWITCH_CONVERSION, "tree switch initialization conversion")
|
||||
DEFTIMEVAR (TV_TREE_STRLEN , "tree strlen optimization")
|
||||
DEFTIMEVAR (TV_CGRAPH_VERIFY , "callgraph verifier")
|
||||
DEFTIMEVAR (TV_DOM_FRONTIERS , "dominance frontiers")
|
||||
DEFTIMEVAR (TV_DOMINANCE , "dominance computation")
|
||||
|
@ -413,6 +413,7 @@ extern struct gimple_opt_pass pass_diagnose_omp_blocks;
|
||||
extern struct gimple_opt_pass pass_expand_omp;
|
||||
extern struct gimple_opt_pass pass_expand_omp_ssa;
|
||||
extern struct gimple_opt_pass pass_object_sizes;
|
||||
extern struct gimple_opt_pass pass_strlen;
|
||||
extern struct gimple_opt_pass pass_fold_builtins;
|
||||
extern struct gimple_opt_pass pass_stdarg;
|
||||
extern struct gimple_opt_pass pass_early_warn_uninitialized;
|
||||
|
1997
gcc/tree-ssa-strlen.c
Normal file
1997
gcc/tree-ssa-strlen.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user