mirror of git://gcc.gnu.org/git/gcc.git
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>
|
2013-05-17 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
* tree-vect-patterns.c (vect_recog_rotate_pattern): For
|
* tree-vect-patterns.c (vect_recog_rotate_pattern): For
|
||||||
|
|
|
||||||
|
|
@ -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" } } */
|
||||||
|
|
@ -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
|
else
|
||||||
{
|
{
|
||||||
si->writable = true;
|
si->writable = true;
|
||||||
si->dont_invalidate = true;
|
gsi_next (gsi);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1717,6 +1718,33 @@ handle_char_store (gimple_stmt_iterator *gsi)
|
||||||
si->endptr = ssaname;
|
si->endptr = ssaname;
|
||||||
si->dont_invalidate = true;
|
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)))
|
else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue