On Mon, Jun 8, 2026 at 5:52 PM Naveen
<[email protected]> wrote:
>
> The function requires the fill value to be a compile-time INTEGER_CST before
> folding. This causes __builtin_memset (d, c, 1) with a non-constant fill to
> remain unfolded.  For the length-1 case this restriction is unnecessary since
> a single-byte store requires no broadcast of the fill value across a wider
> access mode.
> The patch adds an early special-case path for length == 1 that replaces the
> call with a direct MEM_REF byte store. The fill is constant propagating any
> qualifiers from the destination's pointed-to type onto the store.  If the call
> has an LHS the destination pointer is returned as the result matching memset.
>
> PR tree-optimization/102202
>
> gcc/ChangeLog:
>         * gimple-fold.cc (gimple_fold_builtin_memset): Hoist tree_to_uhwi 
> (len)
>         before the INTEGER_CST check.
>
> gcc/testsuite/ChangeLog:
>         * gcc.dg/pr102202-fold.c: New test.
>
> Signed-off-by: Naveen <[email protected]>
> ---
>  gcc/gimple-fold.cc                   | 46 ++++++++++++++++++++++++++--
>  gcc/testsuite/gcc.dg/pr102202-fold.c | 25 +++++++++++++++
>  2 files changed, 69 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 fab4886b0f2..d12a6c75c56 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -1478,10 +1478,53 @@ 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);
> +
> +  /* A single-byte store needs no broadcast of the fill value across a wider
> +     access.  So for length one we can fold a non-constant value, and a store
> +     through an arbitrary pointer rather than only the address of an object 
> as
> +     the constant-length code below requires.  */
> +  if (length == 1 && POINTER_TYPE_P (TREE_TYPE (dest)))
> +    {
> +      location_t loc = gimple_location (stmt);
> +      tree byte_type = unsigned_char_type_node;
> +

Can  you instead factor this into the existing flow at those points:

  if (TREE_CODE (c) != INTEGER_CST)
    return false;

&& !one-or-zero-length

  if (integer_zerop (c))
    cval = 0;
  else
    {

handle non-constant C and compute a cval_tree, hoisting

  gimple *store = gimple_build_assign (var, build_int_cst_type (etype, cval));
                                                                ^^^^^^^^^^^^^^^^

into the integer_zerop and else paths?

> +      /* Propagate qualifiers (e.g. volatile) from the pointed-to type so the
> +        replacement store does not silently drop them.  */
> +      tree ptype = TREE_TYPE (TREE_TYPE (dest));
> +      tree store_type
> +       = ptype ? build_qualified_type (byte_type, TYPE_QUALS (ptype))
> +               : byte_type;
> +      tree off = build_int_cst (build_pointer_type (store_type), 0);
> +      tree mem = fold_build2_loc (loc, MEM_REF, store_type, dest, off);
> +      tree rhs = gimple_convert (gsi, true, GSI_SAME_STMT, loc, byte_type, 
> c);
> +
> +      gimple *store = gimple_build_assign (mem, rhs);
> +      gimple_move_vops (store, stmt);
> +      gimple_set_location (store, loc);
> +      copy_warning (store, stmt);
> +      gsi_insert_before (gsi, store, GSI_SAME_STMT);
> +
> +      if (tree lhs = gimple_call_lhs (stmt))
> +       {
> +         tree 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);
> +       }
> +      else
> +       {
> +         gimple_stmt_iterator gsi2 = *gsi;
> +         gsi_prev (gsi);
> +         gsi_remove (&gsi2, true);
> +       }
> +      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 +1545,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..3c1a0ab4fa9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr102202-fold.c
> @@ -0,0 +1,25 @@
> +/* PR tree-optimization/102202 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +void *
> +g5 (char *d, int c)
> +{
> +  return __builtin_memset (d, c, 1);
> +}
> +
> +void
> +g6 (char *d, int c)
> +{
> +  __builtin_memset (d, c, 1);
> +}
> +
> +void *
> +g7 (int *p, int c)
> +{
> +  return __builtin_memset (p, c, 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" 
> } } */
> --
> 2.34.1
>

Reply via email to