[gcc r17-2389] tree-optimization: Fold length-one memset through arbitrary pointers [PR102202]

"Naveen H.S via Gcc-cvs" <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:eae644638908427b11f8d791f718851e25bece01

commit r17-2389-geae644638908427b11f8d791f718851e25bece01
Author: Naveen <[email protected]>
Date:   Tue Jul 14 01:42:06 2026 -0700

    tree-optimization: Fold length-one memset through arbitrary pointers [PR102202]
    
    gimple_fold_builtin_memset currently folds constant-length memset calls
    into scalar stores only when the destination is an ADDR_EXPR. Calls
    through an arbitrary pointer, such as a function parameter are left as
    library calls and non-constant fill values are rejected even for the
    length-one case where byte replication is unnecessary.
    
    Add a dedicated folding path for length-one memset calls through
    arbitrary pointer destinations. Since the access is exactly one byte,
    use unsigned_char_type_node for the store. This supports both constant
    and non-constant fill values: constant fills are converted with
    fold_convert while non-constant fills use gimple_convert. Volatile
    qualification is preserved from the pointed-to type and the store is
    emitted as a MEM_REF at offset zero using the usual ref-all character
    pointer type.
    
    Defer this new arbitrary-pointer fold until after object-size analysis
    has run so that the original memset remains available to object-size
    based diagnostics. The existing ADDR_EXPR-based folding path for other
    constant lengths is unchanged.
    
    gcc/ChangeLog:
            PR tree-optimization/102202
            * gimple-fold.cc (gimple_fold_builtin_memset): Hoist
            tree_to_uhwi (len) before the INTEGER_CST guard.  Fold
            length-one memset calls through arbitrary pointer destinations.
            Build a ref-all MEM_REF at offset zero and preserve the call
            result when it is used.
    
    gcc/testsuite/ChangeLog:
            PR tree-optimization/102202
            * gcc.dg/pr102202-fold.c: New test.
    
    Signed-off-by: Naveen <[email protected]>

Diff:
---
 gcc/gimple-fold.cc                   | 63 ++++++++++++++++++++++++++++++++++--
 gcc/testsuite/gcc.dg/pr102202-fold.c | 35 ++++++++++++++++++++
 2 files changed, 96 insertions(+), 2 deletions(-)

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 4422a48383d5..fdb9b4197662 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -1478,10 +1478,70 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len)
   if (! tree_fits_uhwi_p (len))
     return false;
 
+  length = tree_to_uhwi (len);
+
+  tree dest = gimple_call_arg (stmt, 0);
+  if (length == 1
+      && POINTER_TYPE_P (TREE_TYPE (dest)))
+    {
+      /* Keep the original call until object-size analysis has inspected it.  */
+      if (!(cfun->curr_properties & PROP_objsz))
+	return false;
+
+      /* Detect out-of-bounds accesses without issuing warnings.
+	 Avoid folding out-of-bounds accesses but to avoid false
+	 positives for unreachable code defer warning until after
+	 DCE has worked its magic.
+	 -Wrestrict is still diagnosed.  */
+      if (int warning = check_bounds_or_overlap (as_a <gcall *>(stmt),
+						 dest, NULL_TREE, len,
+						 NULL_TREE, false, false))
+	if (warning != OPT_Wrestrict)
+	  return false;
+
+      etype = unsigned_char_type_node;
+      tree ptype = TREE_TYPE (TREE_TYPE (dest));
+      if (TYPE_VOLATILE (ptype))
+	etype = build_qualified_type (etype, TYPE_QUAL_VOLATILE);
+
+      location_t loc = gimple_location (stmt);
+      tree cval_tree;
+      if (TREE_CODE (c) == INTEGER_CST)
+	cval_tree = fold_convert (etype, c);
+      else
+	cval_tree = gimple_convert (gsi, true, GSI_SAME_STMT, loc, etype, c);
+
+      /* Build accesses at offset zero with a ref-all character type.  */
+      tree off0
+	= build_int_cst (build_pointer_type_for_mode (char_type_node,
+						      ptr_mode, true), 0);
+      tree var = fold_build2_loc (loc, MEM_REF, etype, dest, off0);
+      gimple *store = gimple_build_assign (var, cval_tree);
+      gimple_move_vops (store, stmt);
+      gimple_set_location (store, loc);
+      copy_warning (store, stmt);
+
+      tree lhs = gimple_call_lhs (stmt);
+      if (!lhs)
+	{
+	  gsi_replace (gsi, store, false);
+	  return true;
+	}
+
+      gsi_insert_before (gsi, store, GSI_SAME_STMT);
+      tree ret = dest;
+      if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (dest)))
+	ret = gimple_convert (gsi, true, GSI_SAME_STMT, loc,
+			      TREE_TYPE (lhs), dest);
+      gimple *asgn = gimple_build_assign (lhs, ret);
+      gsi_replace (gsi, asgn, false);
+
+      return true;
+    }
+
   if (TREE_CODE (c) != INTEGER_CST)
     return false;
 
-  tree dest = gimple_call_arg (stmt, 0);
   tree var = dest;
   if (TREE_CODE (var) != ADDR_EXPR)
     return false;
@@ -1502,7 +1562,6 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len)
   if (! var_decl_component_p (var))
     return false;
 
-  length = tree_to_uhwi (len);
   if (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (etype)) != length
       || (GET_MODE_PRECISION (SCALAR_INT_TYPE_MODE (etype))
 	  != GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (etype)))
diff --git a/gcc/testsuite/gcc.dg/pr102202-fold.c b/gcc/testsuite/gcc.dg/pr102202-fold.c
new file mode 100644
index 000000000000..5e2e58193c96
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr102202-fold.c
@@ -0,0 +1,35 @@
+/* PR tree-optimization/102202 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* A constant-length-one memset is folded to a single byte store, even for a
+   store through an arbitrary pointer.  */
+
+void *
+g1 (char *d, int c)
+{
+  return __builtin_memset (d, c, 1);
+}
+
+void
+g2 (char *d, int c)
+{
+  __builtin_memset (d, c, 1);
+}
+
+void *
+g3 (int *p, int c)
+{
+  return __builtin_memset (p, c, 1);
+}
+
+void *
+g4 (char *d)
+{
+  return __builtin_memset (d, 7, 1);
+}
+
+/* { dg-final { scan-tree-dump-not "__builtin_memset" "optimized" } } */
+/* { dg-final { scan-tree-dump-times {\(unsigned char\) c_[0-9]+\(D\)} 3 "optimized" } } */
+/* { dg-final { scan-tree-dump-times {MEM[^;\n\r]*= _[0-9]+;} 3 "optimized" } } */
+/* { dg-final { scan-tree-dump-times {MEM[^;\n\r]*= 7;} 1 "optimized" } } */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.