diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 407250f70fdc2e7309bc93d5f70705ad23a207e4..2c4e5de420e0b1a746e8c8d466e52fb2e23fb0a2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2003-08-10 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> + + * builtins.c (expand_builtin_strcat): Optimize constant strings. + 2003-08-10 Gabriel Dos Reis <gdr@integrable-solutions.net> * pretty-print.c (pp_base_indent): Rename from pp_indent. diff --git a/gcc/builtins.c b/gcc/builtins.c index f9d953cc7d1b8254db1ac98609396e0239dfec12..a7265bf374cdf154af6fad3c154e4a1245c68280 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -3577,9 +3577,52 @@ expand_builtin_strcat (tree arglist, rtx target, enum machine_mode mode) src = TREE_VALUE (TREE_CHAIN (arglist)); const char *p = c_getstr (src); - /* If the string length is zero, return the dst parameter. */ - if (p && *p == '\0') - return expand_expr (dst, target, mode, EXPAND_NORMAL); + if (p) + { + /* If the string length is zero, return the dst parameter. */ + if (*p == '\0') + return expand_expr (dst, target, mode, EXPAND_NORMAL); + else if (!optimize_size) + { + /* Otherwise if !optimize_size, see if we can store by + pieces into (dst + strlen(dst)). */ + tree newdst, arglist, + strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN]; + + /* This is the length argument. */ + arglist = build_tree_list (NULL_TREE, + fold (size_binop (PLUS_EXPR, + c_strlen (src, 0), + ssize_int (1)))); + /* Prepend src argument. */ + arglist = tree_cons (NULL_TREE, src, arglist); + + /* We're going to use dst more than once. */ + dst = save_expr (dst); + + /* Create strlen (dst). */ + newdst = + fold (build_function_call_expr (strlen_fn, + build_tree_list (NULL_TREE, + dst))); + /* Create (dst + strlen (dst)). */ + newdst = fold (build (PLUS_EXPR, TREE_TYPE (dst), dst, newdst)); + + /* Prepend the new dst argument. */ + arglist = tree_cons (NULL_TREE, newdst, arglist); + + /* We don't want to get turned into a memcpy if the + target is const0_rtx, i.e. when the return value + isn't used. That would produce pessimized code so + pass in a target of zero, it should never actually be + used. If this was successful return the original + dst, not the result of mempcpy. */ + if (expand_builtin_mempcpy (arglist, /*target=*/0, mode, /*endp=*/0)) + return expand_expr (dst, target, mode, EXPAND_NORMAL); + else + return 0; + } + } return 0; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9580129a8b58c850d2f7f71c007c0f3cf6a5c8af..d4bd22d6b5aa73599302655119164e3d5b0c5a4b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-08-10 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> + + * gcc.c-torture/execute/string-opt-9.c: Add more strcat cases. + 2003-08-10 Mark Mitchell <mark@codesourcery.com> PR c++/11789.C diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-9.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-9.c index 889425d7dc4a8053aa1932065e65413a59712fa9..0c21957f28642775c0b0c6528e5d7a5c45b05c81 100644 --- a/gcc/testsuite/gcc.c-torture/execute/string-opt-9.c +++ b/gcc/testsuite/gcc.c-torture/execute/string-opt-9.c @@ -10,6 +10,10 @@ typedef __SIZE_TYPE__ size_t; extern char *strcat (char *, const char *); extern char *strcpy (char *, const char *); extern int strcmp (const char *, const char *); +extern void *memset (void *, int, size_t); +extern int memcmp (const void *, const void *, size_t); +#define RESET_DST_WITH(FILLER) \ + do { memset (dst, 'X', sizeof (dst)); strcpy (dst, (FILLER)); } while (0) int main () { @@ -17,25 +21,48 @@ int main () const char *const s2 = ""; char dst[64], *d2; - strcpy (dst, s1); + RESET_DST_WITH (s1); if (strcat (dst, "") != dst || strcmp (dst, s1)) abort(); - strcpy (dst, s1); + RESET_DST_WITH (s1); if (strcat (dst, s2) != dst || strcmp (dst, s1)) abort(); - strcpy (dst, s1); d2 = dst; + RESET_DST_WITH (s1); d2 = dst; if (strcat (++d2, s2) != dst+1 || d2 != dst+1 || strcmp (dst, s1)) abort(); - strcpy (dst, s1); d2 = dst; + RESET_DST_WITH (s1); d2 = dst; if (strcat (++d2+5, s2) != dst+6 || d2 != dst+1 || strcmp (dst, s1)) abort(); - strcpy (dst, s1); d2 = dst; + RESET_DST_WITH (s1); d2 = dst; if (strcat (++d2+5, s1+11) != dst+6 || d2 != dst+1 || strcmp (dst, s1)) abort(); +#ifndef __OPTIMIZE_SIZE__ + RESET_DST_WITH (s1); + if (strcat (dst, " 1111") != dst + || memcmp (dst, "hello world 1111\0XXX", 20)) + abort(); + + RESET_DST_WITH (s1); + if (strcat (dst+5, " 2222") != dst+5 + || memcmp (dst, "hello world 2222\0XXX", 20)) + abort(); + + RESET_DST_WITH (s1); d2 = dst; + if (strcat (++d2+5, " 3333") != dst+6 || d2 != dst+1 + || memcmp (dst, "hello world 3333\0XXX", 20)) + abort(); + + RESET_DST_WITH (s1); + strcat (strcat (strcat (strcat (strcat (strcat (dst, ": this "), ""), + "is "), "a "), "test"), "."); + if (memcmp (dst, "hello world: this is a test.\0X", 30)) + abort(); +#endif + /* Test at least one instance of the __builtin_ style. We do this to ensure that it works and that the prototype is correct. */ - strcpy (dst, s1); + RESET_DST_WITH (s1); if (__builtin_strcat (dst, "") != dst || strcmp (dst, s1)) abort();