Add tree-ssa-strlen optimization.
From-SVN: r199006
This commit is contained in:
parent
68119618f7
commit
5b115c1f2b
@ -1,3 +1,12 @@
|
||||
2013-05-17 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
* tree-ssa-strlen.c (handle_char_store): Don't invalidate
|
||||
cached length when doing non-zero store of storing '\0' to
|
||||
'\0'.
|
||||
|
||||
* gcc.dg/strlenopt-25.c: New test.
|
||||
* gcc.dg/strlenopt-26.c: Likewise.
|
||||
|
||||
2013-05-17 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* tree-vect-patterns.c (vect_recog_rotate_pattern): For
|
||||
|
18
gcc/testsuite/gcc.dg/strlenopt-25.c
Normal file
18
gcc/testsuite/gcc.dg/strlenopt-25.c
Normal file
@ -0,0 +1,18 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
char p[] = "foobar";
|
||||
int len, len2;
|
||||
len = strlen (p);
|
||||
p[0] = 'O';
|
||||
len2 = strlen (p);
|
||||
return len - len2;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
25
gcc/testsuite/gcc.dg/strlenopt-26.c
Normal file
25
gcc/testsuite/gcc.dg/strlenopt-26.c
Normal file
@ -0,0 +1,25 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noinline, noclone)) size_t
|
||||
fn1 (char *p, const char *r)
|
||||
{
|
||||
size_t len1 = strlen (r);
|
||||
char *q = strchr (p, '\0');
|
||||
*q = '\0';
|
||||
return len1 - strlen (r); // This strlen should be optimized into len1.
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
char p[] = "foobar";
|
||||
const char *volatile q = "xyzzy";
|
||||
fn1 (p, q);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
|
||||
/* { dg-final { cleanup-tree-dump "strlen" } } */
|
@ -1694,7 +1694,8 @@ handle_char_store (gimple_stmt_iterator *gsi)
|
||||
else
|
||||
{
|
||||
si->writable = true;
|
||||
si->dont_invalidate = true;
|
||||
gsi_next (gsi);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1717,6 +1718,33 @@ handle_char_store (gimple_stmt_iterator *gsi)
|
||||
si->endptr = ssaname;
|
||||
si->dont_invalidate = true;
|
||||
}
|
||||
/* If si->length is non-zero constant, we aren't overwriting '\0',
|
||||
and if we aren't storing '\0', we know that the length of the
|
||||
string and any other zero terminated string in memory remains
|
||||
the same. In that case we move to the next gimple statement and
|
||||
return to signal the caller that it shouldn't invalidate anything.
|
||||
|
||||
This is benefical for cases like:
|
||||
|
||||
char p[20];
|
||||
void foo (char *q)
|
||||
{
|
||||
strcpy (p, "foobar");
|
||||
size_t len = strlen (p); // This can be optimized into 6
|
||||
size_t len2 = strlen (q); // This has to be computed
|
||||
p[0] = 'X';
|
||||
size_t len3 = strlen (p); // This can be optimized into 6
|
||||
size_t len4 = strlen (q); // This can be optimized into len2
|
||||
bar (len, len2, len3, len4);
|
||||
}
|
||||
*/
|
||||
else if (si != NULL && si->length != NULL_TREE
|
||||
&& TREE_CODE (si->length) == INTEGER_CST
|
||||
&& integer_nonzerop (gimple_assign_rhs1 (stmt)))
|
||||
{
|
||||
gsi_next (gsi);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user