https://gcc.gnu.org/g:c760057058e512027fe6662ed3088313f4dc5cb6
commit r16-5430-gc760057058e512027fe6662ed3088313f4dc5cb6 Author: Andrew Pinski <[email protected]> Date: Tue Nov 18 18:16:02 2025 -0800 gimple: fix strlen+more for references 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. 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]> Diff: --- 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 ++-- gcc/testsuite/g++.dg/tree-ssa/string-strlen-1.C | 20 ++++++++++++++++++++ gcc/tree-ssa-strlen.cc | 8 ++++---- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index 8f72dbb929be..3fc763136225 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 bcec54052422..3c2a742f512d 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 abfb8685ce7e..d12f797f36b3 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 e48fe1eb841a..0b383cced449 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 000000000000..fb7f9200f259 --- /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 bb6561cde039..b9457c988ac8 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);
