On Wed, Nov 19, 2025 at 7:34 AM Andrew Pinski <[email protected]> wrote: > > I found that the strlen pass ignores stores via references. > This shows up with C++ code more than C. > A simple: > ``` > int g(void) > { > std::string a="a"; > return __builtin_strlen(a.c_str()); > } > ``` > Should be optimized to just `return 1` but does not > currently due to use of references. > The problem in the code is direct comparison with POINTER_TYPE instead > of using POINTER_TYPE_P. > This fixes the cases I found all related to strings passes. All of them > were added by Martin Sebor which makes me think this was an oversight on his > part.
OK. Richard. > Bootstrapped and tested on x86_64-linux-gnu. > > PR tree-optimization/122754 > gcc/ChangeLog: > > * gimple-fold.cc (get_range_strlen_tree): Use POINTER_TYPE_P instead > of direct comparing to POINTER_TYPE. > * gimple-ssa-sprintf.cc (format_integer): Likewise. > * gimple-ssa-warn-access.cc (maybe_warn_nonstring_arg): Likewise. > * gimple-ssa-warn-restrict.cc (pass_wrestrict::check_call): Likewise. > * tree-ssa-strlen.cc (maybe_set_strlen_range): Likewise. > (is_strlen_related_p): Likewise. > (strlen_pass::handle_assign): Likewise. > > gcc/testsuite/ChangeLog: > > * g++.dg/tree-ssa/string-strlen-1.C: New test. > > Signed-off-by: Andrew Pinski <[email protected]> > --- > gcc/gimple-fold.cc | 2 +- > gcc/gimple-ssa-sprintf.cc | 6 +++--- > gcc/gimple-ssa-warn-access.cc | 2 +- > gcc/gimple-ssa-warn-restrict.cc | 4 ++-- > .../g++.dg/tree-ssa/string-strlen-1.C | 20 +++++++++++++++++++ > gcc/tree-ssa-strlen.cc | 8 ++++---- > 6 files changed, 31 insertions(+), 11 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/tree-ssa/string-strlen-1.C > > diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc > index 8f72dbb929b..3fc76313622 100644 > --- a/gcc/gimple-fold.cc > +++ b/gcc/gimple-fold.cc > @@ -1806,7 +1806,7 @@ get_range_strlen_tree (tree arg, bitmap visited, > strlen_range_kind rkind, > the size of the enclosing object minus the offset of > the referenced subobject minus 1 (for the terminating nul). */ > tree type = TREE_TYPE (base); > - if (TREE_CODE (type) == POINTER_TYPE > + if (POINTER_TYPE_P (type) > || (TREE_CODE (base) != PARM_DECL && !VAR_P (base)) > || !(val = DECL_SIZE_UNIT (base))) > val = build_all_ones_cst (size_type_node); > diff --git a/gcc/gimple-ssa-sprintf.cc b/gcc/gimple-ssa-sprintf.cc > index bcec5405242..3c2a742f512 100644 > --- a/gcc/gimple-ssa-sprintf.cc > +++ b/gcc/gimple-ssa-sprintf.cc > @@ -1372,7 +1372,7 @@ format_integer (const directive &dir, tree arg, > pointer_query &ptr_qry) > return res; > } > else if (INTEGRAL_TYPE_P (TREE_TYPE (arg)) > - || TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE) > + || POINTER_TYPE_P (TREE_TYPE (arg))) > /* Determine the type of the provided non-constant argument. */ > argtype = TREE_TYPE (arg); > else > @@ -1434,7 +1434,7 @@ format_integer (const directive &dir, tree arg, > pointer_query &ptr_qry) > { > tree type = TREE_TYPE (gimple_assign_rhs1 (def)); > if (INTEGRAL_TYPE_P (type) > - || TREE_CODE (type) == POINTER_TYPE) > + || POINTER_TYPE_P (type)) > argtype = type; > } > } > @@ -1443,7 +1443,7 @@ format_integer (const directive &dir, tree arg, > pointer_query &ptr_qry) > > if (!argmin) > { > - if (TREE_CODE (argtype) == POINTER_TYPE) > + if (POINTER_TYPE_P (argtype)) > { > argmin = build_int_cst (pointer_sized_int_node, 0); > argmax = build_all_ones_cst (pointer_sized_int_node); > diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc > index abfb8685ce7..d12f797f36b 100644 > --- a/gcc/gimple-ssa-warn-access.cc > +++ b/gcc/gimple-ssa-warn-access.cc > @@ -554,7 +554,7 @@ maybe_warn_nonstring_arg (tree fndecl, GimpleOrTree exp) > if (!argtype) > break; > > - if (TREE_CODE (argtype) != POINTER_TYPE) > + if (!POINTER_TYPE_P (argtype)) > continue; > > argtype = TREE_TYPE (argtype); > diff --git a/gcc/gimple-ssa-warn-restrict.cc b/gcc/gimple-ssa-warn-restrict.cc > index e48fe1eb841..0b383cced44 100644 > --- a/gcc/gimple-ssa-warn-restrict.cc > +++ b/gcc/gimple-ssa-warn-restrict.cc > @@ -1998,8 +1998,8 @@ pass_wrestrict::check_call (gimple *call) > /* DST, SRC, or DSTWR can also have the wrong type in a call to > a function declared without a prototype. Avoid checking such > invalid calls. */ > - if (TREE_CODE (TREE_TYPE (dst)) != POINTER_TYPE > - || (src && TREE_CODE (TREE_TYPE (src)) != POINTER_TYPE) > + if (!POINTER_TYPE_P (TREE_TYPE (dst)) > + || (src && !POINTER_TYPE_P (TREE_TYPE (src))) > || (dstwr && !INTEGRAL_TYPE_P (TREE_TYPE (dstwr)))) > return; > > diff --git a/gcc/testsuite/g++.dg/tree-ssa/string-strlen-1.C > b/gcc/testsuite/g++.dg/tree-ssa/string-strlen-1.C > new file mode 100644 > index 00000000000..fb7f9200f25 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/tree-ssa/string-strlen-1.C > @@ -0,0 +1,20 @@ > +// { dg-do compile } */ > +// { dg-additional-options "-fdump-tree-optimized -O2" } > +// { dg-skip-if "requires hosted libstdc++ for string" { ! hostedlib } } > +// PR tree-optimization/122754 > + > +#include <string> > + > +int g(void) > +{ > + std::string a="a"; > + return __builtin_strlen(a.c_str()); > +} > + > +// This should be optimized to just `return 1` without any > +// references to struct string or any other variables. > + > +// { dg-final { scan-tree-dump-not "strlen " "optimized" } } > +// { dg-final { scan-tree-dump-not "struct string" "optimized" } } > +// { dg-final { scan-tree-dump "return 1" "optimized" } } > + > diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc > index bb6561cde03..b9457c988ac 100644 > --- a/gcc/tree-ssa-strlen.cc > +++ b/gcc/tree-ssa-strlen.cc > @@ -1997,7 +1997,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound) > if (tree size = DECL_SIZE_UNIT (base)) > if (size > && TREE_CODE (size) == INTEGER_CST > - && TREE_CODE (TREE_TYPE (base)) != POINTER_TYPE) > + && !POINTER_TYPE_P (TREE_TYPE (base))) > max = wi::to_wide (size); > } > } > @@ -2792,7 +2792,7 @@ strlen_pass::handle_builtin_strncat (built_in_function) > bool > is_strlen_related_p (tree src, tree len) > { > - if (TREE_CODE (TREE_TYPE (len)) == POINTER_TYPE > + if (POINTER_TYPE_P (TREE_TYPE (len)) > && operand_equal_p (src, len, 0)) > return true; > > @@ -2853,7 +2853,7 @@ is_strlen_related_p (tree src, tree len) > tree rhs1 = gimple_assign_rhs1 (lendef); > tree rhstype = TREE_TYPE (rhs1); > > - if ((TREE_CODE (rhstype) == POINTER_TYPE && code == POINTER_PLUS_EXPR) > + if ((POINTER_TYPE_P (rhstype) && code == POINTER_PLUS_EXPR) > || (INTEGRAL_TYPE_P (rhstype) > && (code == BIT_AND_EXPR > || code == NOP_EXPR))) > @@ -5746,7 +5746,7 @@ strlen_pass::handle_assign (tree lhs, tree rhs, bool > *zero_write) > { > tree ref = TREE_OPERAND (lhs, i); > type = TREE_TYPE (ref); > - if (TREE_CODE (type) == POINTER_TYPE) > + if (POINTER_TYPE_P (type)) > type = TREE_TYPE (type); > if (TREE_CODE (type) == ARRAY_TYPE) > type = TREE_TYPE (type); > -- > 2.43.0 >
