On Fri, Jul 3, 2026 at 7:42 AM Naveen
<[email protected]> wrote:
>
> 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.

OK.

Thanks,
Richard.

> 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]>
> ---
>  gcc/gimple-fold.cc                   | 63 +++++++++++++++++++++++++++-
>  gcc/testsuite/gcc.dg/pr102202-fold.c | 35 ++++++++++++++++
>  2 files changed, 96 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/pr102202-fold.c
>
> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
> index 4422a48383d..fdb9b419766 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 00000000000..5e2e58193c9
> --- /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" } } */
> --
> 2.34.1
>

Reply via email to