r249880 installed the result of a strlen in a strinfo if the strinfo wasn't previously a full string. But as Jakub says in the PR comments, we can't just do that in isolation, because there are no vdefs on the call that would invalidate any related strinfos.
This patch updates the related strinfos if the adjustment is simple and invalidates them otherwise. As elsewhere, we treat adjustments of the form strlen +/- INTEGER_CST as simple but anything else as too complex. Tested on x86_64-linux-gnu and aarch64-linux-gnu. OK to install? Sorry for the breakage. Richard gcc/ PR tree-optimization/81292 * tree-ssa-strlen.c (handle_builtin_strlen): When setting full_string_p, also call adjust_related_strinfos if the adjustment is simple, otherwise invalidate related strinfos. gcc/testsuite/ PR tree-optimization/81292 * gcc.dg/pr81292-1.c: New test. * gcc.dg/pr81292-2.c: Likewise. Index: gcc/tree-ssa-strlen.c =================================================================== --- gcc/tree-ssa-strlen.c 2017-07-03 21:00:21.438433126 +0100 +++ gcc/tree-ssa-strlen.c 2017-07-03 21:00:34.971809881 +0100 @@ -1214,8 +1214,23 @@ handle_builtin_strlen (gimple_stmt_itera /* Until now we only had a lower bound on the string length. Install LHS as the actual length. */ si = unshare_strinfo (si); + tree old = si->nonzero_chars; si->nonzero_chars = lhs; si->full_string_p = true; + if (TREE_CODE (old) == INTEGER_CST) + { + location_t loc = gimple_location (stmt); + old = fold_convert_loc (loc, TREE_TYPE (lhs), old); + tree adj = fold_build2_loc (loc, MINUS_EXPR, + TREE_TYPE (lhs), lhs, old); + adjust_related_strinfos (loc, si, adj); + } + else + { + si->first = 0; + si->prev = 0; + si->next = 0; + } } return; } Index: gcc/testsuite/gcc.dg/pr81292-1.c =================================================================== --- /dev/null 2017-07-03 19:11:31.344941082 +0100 +++ gcc/testsuite/gcc.dg/pr81292-1.c 2017-07-03 21:00:34.971809881 +0100 @@ -0,0 +1,35 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fdump-tree-strlen" } */ + +#include "strlenopt.h" + +char a[10]; + +int __attribute__ ((noinline, noclone)) +f1 (int n) +{ + a[0] = '1'; + a[1] = '2'; + return strlen (a + 1) < n ? strlen (a) : 100; +} + +int __attribute__ ((noinline, noclone)) +f2 (char *a, int n) +{ + a[0] = '1'; + a[1] = '2'; + return strlen (a + 1) < n ? strlen (a) : 100; +} + +int +main (void) +{ + char b[10]; + strcpy (a + 2, "345"); + strcpy (b + 2, "34567"); + if (f1 (100) != 5 || f2 (b, 100) != 7) + __builtin_abort (); + return 0; +} + +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ Index: gcc/testsuite/gcc.dg/pr81292-2.c =================================================================== --- /dev/null 2017-07-03 19:11:31.344941082 +0100 +++ gcc/testsuite/gcc.dg/pr81292-2.c 2017-07-03 21:00:34.971809881 +0100 @@ -0,0 +1,35 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fdump-tree-strlen" } */ + +#include "strlenopt.h" + +char a[] = { 0, 'a', 0, 'b', 'c', 0, 'd', 'e', 'f', 0 }; + +int __attribute__ ((noinline, noclone)) +f1 (void) +{ + a[0] = '1'; + a[strlen (a)] = '2'; + a[strlen (a)] = '3'; + return strlen (a); +} + +int __attribute__ ((noinline, noclone)) +f2 (char *a) +{ + a[0] = '1'; + a[strlen (a)] = '2'; + a[strlen (a)] = '3'; + return strlen (a); +} + +int +main (void) +{ + char b[] = { 0, 0, 'a', 'b', 0, 0 }; + if (f1 () != 9 || f2 (b) != 5) + __builtin_abort (); + return 0; +} + +/* { dg-final { scan-tree-dump-times "strlen \\(" 6 "strlen" } } */