https://gcc.gnu.org/g:7e7412042e90ec1b6f1268049061bcdc208ae267

commit r15-11226-g7e7412042e90ec1b6f1268049061bcdc208ae267
Author: Jakub Jelinek <[email protected]>
Date:   Fri May 1 14:54:35 2026 +0200

    strlen: Adjust objsz arg in __strcat_chk -> __stpcpy_chk transformation 
[PR125079]
    
    As the following testcase shows, we have two different transformations
    of __strcat_chk.  One done in strlen_pass::handle_builtin_strcat,
    which transforms __strcat_chk (x, y, z) if we know beforehand strlen (x),
    so something like:
      l = strlen (x);
      __strcat_chk (x, y, z);
    and since PR87672 we change that to
      l = strlen (x);
      __strcpy_chk (x + l, y, z - l);
    i.e. decrease the objsz in
      if (objsz)
        {
          objsz = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (objsz), objsz,
                                   fold_convert_loc (loc, TREE_TYPE (objsz),
                                                     unshare_expr (dstlen)));
          objsz = force_gimple_operand_gsi (&m_gsi, objsz, true, NULL_TREE, 
true,
                                            GSI_SAME_STMT);
        }
    And another transformation is when we have earlier __strcat_chk (x, y, z)
    call and want to compute strlen (x) after that.  In that case
    get_string_length transforms
      __strcat_chk (x, y, z);
    to
      t = strlen (x);
      l = __stpcpy_chk (x + t, y, z) - x;
    where l is the len we are looking for.  This patch changes it similarly to
    the PR87672 to
      t = strlen (x);
      l = __stpcpy_chk (x + t, y, z - t) - x;
    instead.
    
    2026-05-01  Jakub Jelinek  <[email protected]>
    
            PR tree-optimization/125079
            * tree-ssa-strlen.cc (get_string_length): Transform
            __strcat_chk (x, y, z) when we need strlen (x) afterwards into
            l1 = strlen (x); l = __stpcpy_chk (x + l1, y, z - l1) - x;
            where l is the strlen (x), instead of using z as last __stpcpy_chk
            argument.
    
            * gcc.dg/strlenopt-97.c: New test.
    
    Reviewed-by: Richard Biener <[email protected]>
    (cherry picked from commit c1aa090bb8e1c23e733bc7beafceb7c34dc713f8)

Diff:
---
 gcc/testsuite/gcc.dg/strlenopt-97.c | 33 +++++++++++++++++++++++++++++++++
 gcc/tree-ssa-strlen.cc              | 19 +++++++++++++++----
 2 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/strlenopt-97.c 
b/gcc/testsuite/gcc.dg/strlenopt-97.c
new file mode 100644
index 000000000000..c4fadbd89425
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-97.c
@@ -0,0 +1,33 @@
+/* PR tree-optimization/125079 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-strlen1" } */
+/* { dg-final { scan-tree-dump-times "__builtin___strcpy_chk \\\(" 1 "strlen1" 
} } */
+/* { dg-final { scan-tree-dump-not "__builtin___strcpy_chk \\\(\[^\n\r]*, 
64\\\)" "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___stpcpy_chk \\\(" 1 "strlen1" 
} } */
+/* { dg-final { scan-tree-dump-not "__builtin___stpcpy_chk \\\(\[^\n\r]*, 
128\\\)" "strlen1" } } */
+
+typedef __SIZE_TYPE__ size_t;
+void foo (char *, int);
+char *stpcpy (char *, const char *);
+
+size_t
+bar (char *r)
+{
+  char buf[64];
+  foo (buf, 0);
+  size_t ret = __builtin_strlen (buf);
+  __builtin___strcat_chk (buf, r, 64);
+  foo (buf, 1);
+  return ret;
+}
+
+size_t
+baz (char *r)
+{
+  char buf[128];
+  foo (buf, 2);
+  __builtin___strcat_chk (buf, r, 128);
+  size_t ret = __builtin_strlen (buf);
+  foo (buf, 3);
+  return ret;
+}
diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc
index c5e9c0b94c62..8057da7bbd4e 100644
--- a/gcc/tree-ssa-strlen.cc
+++ b/gcc/tree-ssa-strlen.cc
@@ -848,7 +848,7 @@ get_string_length (strinfo *si)
      attempt to compute the length from the call statement.  */
   if (si->stmt)
     {
-      gimple *stmt = si->stmt, *lenstmt;
+      gimple *stmt = si->stmt, *lenstmt = NULL, *g;
       tree callee, lhs, fn, tem;
       location_t loc;
       gimple_stmt_iterator gsi;
@@ -883,11 +883,11 @@ get_string_length (strinfo *si)
               lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
                                               true, GSI_SAME_STMT);
             }
-         lenstmt = gimple_build_assign
+         g = gimple_build_assign
                        (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
                         POINTER_PLUS_EXPR,tem, lhs);
-         gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
-         gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
+         gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+         gimple_call_set_arg (stmt, 0, gimple_assign_lhs (g));
          lhs = NULL_TREE;
          /* FALLTHRU */
        case BUILT_IN_STRCPY:
@@ -906,6 +906,17 @@ get_string_length (strinfo *si)
          gimple_call_set_fndecl (stmt, fn);
          lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
          gimple_call_set_lhs (stmt, lhs);
+         if (DECL_FUNCTION_CODE (callee) == BUILT_IN_STRCAT_CHK)
+           {
+             tree objsz = gimple_call_lhs (lenstmt);
+             gimple *g
+               = gimple_build_assign (make_ssa_name (TREE_TYPE (objsz)),
+                                      MINUS_EXPR, gimple_call_arg (stmt, 2),
+                                      objsz);
+             gimple_set_location (g, gimple_location (stmt));
+             gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+             gimple_call_set_arg (stmt, 2, gimple_assign_lhs (g));
+           }
          update_stmt (stmt);
          if (dump_file && (dump_flags & TDF_DETAILS) != 0)
            {

Reply via email to