Prathamesh's fix restores the optimization for the test case reported in the bug (thanks!) but it isn't sufficient to bring GCC 8 completely up to par with 7. Prior GCC versions are able to compute the string length in the test case below but GCC 8 cannot.
char d[8]; const char s[] = "1234567"; void f (void) { __builtin_strcpy (d, s); if (__builtin_strlen (d) != sizeof s - 1) __builtin_abort (); } The attached patch slightly tweaks Prathamesh's patch to also handle the case above. There still are outstanding cases where folding into MEM_REF defeats the strlen pass (I've raised a couple of new bugs to track those I noticed today) but, AFAICT, those aren't recent regressions so they can be dealt with later and separately. Martin PS I've renamed the function because I had initially thought it also needed to handle PHIs that refer to strings of the same length (and there isn't necessarily one "right" string to return) but then realized that the lack of that handling isn't part of the regression so I didn't include it but kept the new return type and name. When the pass is enhanced to handle PHIs and some of the other cases it doesn't handle the function won't need to change.
PR tree-optimization/83501 - strlen(a) not folded after strcpy(a, ...) gcc/ChangeLog: PR tree-optimization/83501 * tree-ssa-strlen.c (get_string_cst): Rename... (get_strlen): ...to this. Handle global constants. (handle_char_store): Adjust. gcc/testsuite/ChangeLog: PR tree-optimization/83501 * gcc.dg/strlenopt-39.c: New test. Index: gcc/testsuite/gcc.dg/strlenopt-39.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-39.c (nonexistent) +++ gcc/testsuite/gcc.dg/strlenopt-39.c (working copy) @@ -0,0 +1,66 @@ +/* PR tree-optimization/83444 + { dg-do compile } + { dg-options "-O2 -fdump-tree-optimized" } */ + +#include "strlenopt.h" + +#define STR "1234567" + +const char str[] = STR; + +char dst[10]; + +void copy_from_global_str (void) +{ + strcpy (dst, str); + + if (strlen (dst) != sizeof str - 1) + abort (); +} + +void copy_from_local_str (void) +{ + const char s[] = STR; + + strcpy (dst, s); + + if (strlen (dst) != sizeof s - 1) + abort (); +} + +void copy_from_local_memstr (void) +{ + struct { + char s[sizeof STR]; + } x = { STR }; + + strcpy (dst, x.s); + + if (strlen (dst) != sizeof x.s - 1) + abort (); +} + +void copy_to_local_str (void) +{ + char d[sizeof STR]; + + strcpy (d, str); + + if (strlen (d) != sizeof str - 1) + abort (); +} + +void copy_to_local_memstr (void) +{ + struct { + char d[sizeof STR]; + } x; + + strcpy (x.d, str); + + if (strlen (x.d) != sizeof str- 1) + abort (); +} + +/* Verify that all calls to strlen have been eliminated. + { dg-final { scan-tree-dump-not "(abort|strlen) \\(\\)" "optimized" } } */ Index: gcc/tree-ssa-strlen.c =================================================================== --- gcc/tree-ssa-strlen.c (revision 256180) +++ gcc/tree-ssa-strlen.c (working copy) @@ -2772,9 +2772,11 @@ handle_pointer_plus (gimple_stmt_iterator *gsi) } } -/* Check if RHS is string_cst possibly wrapped by mem_ref. */ -static tree -get_string_cst (tree rhs) +/* If RHS, either directly or indirectly, refers to a string of constant + length, return it. Otherwise return a negative value. */ + +static int +get_strlen (tree rhs) { if (TREE_CODE (rhs) == MEM_REF && integer_zerop (TREE_OPERAND (rhs, 1))) @@ -2784,7 +2786,17 @@ handle_pointer_plus (gimple_stmt_iterator *gsi) rhs = TREE_OPERAND (rhs, 0); } - return (TREE_CODE (rhs) == STRING_CST) ? rhs : NULL_TREE; + if (TREE_CODE (rhs) == VAR_DECL + && TREE_READONLY (rhs)) + rhs = DECL_INITIAL (rhs); + + if (rhs && TREE_CODE (rhs) == STRING_CST) + { + unsigned HOST_WIDE_INT ilen = strlen (TREE_STRING_POINTER (rhs)); + return ilen <= INT_MAX ? ilen : -1; + } + + return -1; } /* Handle a single character store. */ @@ -2799,6 +2811,9 @@ handle_char_store (gimple_stmt_iterator *gsi) tree rhs = gimple_assign_rhs1 (stmt); unsigned HOST_WIDE_INT offset = 0; + /* Set to the length of the string being assigned if known. */ + int rhslen; + if (TREE_CODE (lhs) == MEM_REF && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME) { @@ -2942,19 +2957,18 @@ handle_char_store (gimple_stmt_iterator *gsi) } } else if (idx == 0 - && (rhs = get_string_cst (gimple_assign_rhs1 (stmt))) + && (rhslen = get_strlen (gimple_assign_rhs1 (stmt))) >= 0 && ssaname == NULL_TREE && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE) { - size_t l = strlen (TREE_STRING_POINTER (rhs)); HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs)); - if (a > 0 && (unsigned HOST_WIDE_INT) a > l) + if (a > 0 && (unsigned HOST_WIDE_INT) a > (unsigned HOST_WIDE_INT) rhslen) { int idx = new_addr_stridx (lhs); if (idx != 0) { si = new_strinfo (build_fold_addr_expr (lhs), idx, - build_int_cst (size_type_node, l), true); + build_int_cst (size_type_node, rhslen), true); set_strinfo (idx, si); si->dont_invalidate = true; }