On Thu, Jun 11, 2026 at 3:53 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.

OK, so I realize the existing folding only inlines memset to a single store when
the destination is a local variable but you also want to handle
pointer destinations.

I think we should lift the restriction for the current folding,
possibly as a [1/2],
as that would simplify the code.  Most of the sanity checking placed on the
destination type is superfluous, you can look into gimple_fold_builtin_memory_op
on how to get a mode/type for the store:

              scalar_int_mode imode;
              machine_mode mode;
              if (int_mode_for_size (ilen * BITS_PER_UNIT, 0).exists (&imode)
                  && bitwise_mode_for_size (ilen
                                            * BITS_PER_UNIT).exists (&mode)
                  && known_eq (GET_MODE_BITSIZE (mode), ilen * BITS_PER_UNIT)
                  /* If the destination pointer is not aligned we must be able
                     to emit an unaligned store.  */
                  && (dest_align >= GET_MODE_ALIGNMENT (mode)
                      || !targetm.slow_unaligned_access (mode, dest_align)
                      || (optab_handler (movmisalign_optab, mode)
                          != CODE_FOR_nothing)))
...

Sorry for only noticing now.

Thanks,
Richard.

> 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                   | 117 ++++++++++++++++++---------
>  gcc/testsuite/gcc.dg/pr102202-fold.c |  25 ++++++
>  2 files changed, 102 insertions(+), 40 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..bbf407a98aa 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -1463,7 +1463,7 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, 
> tree c, tree len)
>  {
>    gimple *stmt = gsi_stmt (*gsi);
>    tree etype;
> -  unsigned HOST_WIDE_INT length, cval;
> +  unsigned HOST_WIDE_INT length;
>
>    /* If the LEN parameter is zero, return DEST.  */
>    if (integer_zerop (len))
> @@ -1478,67 +1478,104 @@ gimple_fold_builtin_memset (gimple_stmt_iterator 
> *gsi, tree c, tree len)
>    if (! tree_fits_uhwi_p (len))
>      return false;
>
> -  if (TREE_CODE (c) != INTEGER_CST)
> +  length = tree_to_uhwi (len);
> +  bool length_one_p = length == 1;
> +
> +  if (TREE_CODE (c) != INTEGER_CST && !length_one_p)
>      return false;
>
>    tree dest = gimple_call_arg (stmt, 0);
>    tree var = dest;
> -  if (TREE_CODE (var) != ADDR_EXPR)
> -    return false;
>
> -  var = TREE_OPERAND (var, 0);
> -  if (TREE_THIS_VOLATILE (var))
> -    return false;
> +  if (length_one_p)
> +    {
> +      if (!POINTER_TYPE_P (TREE_TYPE (dest)))
> +       return false;
>
> -  etype = TREE_TYPE (var);
> -  if (TREE_CODE (etype) == ARRAY_TYPE)
> -    etype = TREE_TYPE (etype);
> +      tree ptype = TREE_TYPE (TREE_TYPE (dest));
> +      etype = build_qualified_type (unsigned_char_type_node,
> +                                   TYPE_QUALS (ptype));
> +    }
> +  else
> +    {
> +      if (TREE_CODE (var) != ADDR_EXPR)
> +       return false;
>
> -  if ((!INTEGRAL_TYPE_P (etype)
> -       && !POINTER_TYPE_P (etype))
> -      || BITINT_TYPE_P (etype))
> -    return false;
> +      var = TREE_OPERAND (var, 0);
> +      if (TREE_THIS_VOLATILE (var))
> +       return false;
>
> -  if (! var_decl_component_p (var))
> -    return false;
> +      etype = TREE_TYPE (var);
> +      if (TREE_CODE (etype) == ARRAY_TYPE)
> +       etype = TREE_TYPE (etype);
>
> -  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)))
> -      || get_pointer_alignment (dest) / BITS_PER_UNIT < length)
> -    return false;
> +      if ((!INTEGRAL_TYPE_P (etype)
> +          && !POINTER_TYPE_P (etype))
> +          || BITINT_TYPE_P (etype))
> +       return false;
>
> -  if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT)
> -    return false;
> +      if (! var_decl_component_p (var))
> +       return false;
>
> -  if (!type_has_mode_precision_p (etype))
> -    etype = lang_hooks.types.type_for_mode (SCALAR_INT_TYPE_MODE (etype),
> -                                           TYPE_UNSIGNED (etype));
> +      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)))
> +         || get_pointer_alignment (dest) / BITS_PER_UNIT < length)
> +       return false;
> +
> +      if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT)
> +       return false;
> +
> +      if (!type_has_mode_precision_p (etype))
> +       etype = lang_hooks.types.type_for_mode (SCALAR_INT_TYPE_MODE (etype),
> +                                               TYPE_UNSIGNED (etype));
> +    }
> +
> +  location_t loc = gimple_location (stmt);
> +  tree cval_tree;
>
>    if (integer_zerop (c))
> -    cval = 0;
> +    cval_tree = build_zero_cst (etype);
>    else
>      {
> -      if (CHAR_BIT != 8 || BITS_PER_UNIT != 8 || HOST_BITS_PER_WIDE_INT > 64)
> -       return NULL_TREE;
> +      if (length_one_p)
> +       {
> +         /* Non-constant C is valid for length one.  Convert it to the byte
> +            store type as memset specifies before doing single-byte store.  
> */
> +         cval_tree = gimple_convert (gsi, true, GSI_SAME_STMT, loc,
> +                                     etype, c);
> +       }
> +      else
> +       {
> +         if (CHAR_BIT != 8 || BITS_PER_UNIT != 8
> +             || HOST_BITS_PER_WIDE_INT > 64)
> +           return false;
>
> -      cval = TREE_INT_CST_LOW (c);
> -      cval &= 0xff;
> -      cval |= cval << 8;
> -      cval |= cval << 16;
> -      cval |= (cval << 31) << 1;
> +         unsigned HOST_WIDE_INT cval = TREE_INT_CST_LOW (c);
> +         cval &= 0xff;
> +         cval |= cval << 8;
> +         cval |= cval << 16;
> +         cval |= (cval << 31) << 1;
> +
> +         cval_tree = build_int_cst_type (etype, cval);
> +       }
>      }
>
>    var = fold_build2 (MEM_REF, etype, dest, build_int_cst (ptr_type_node, 0));
> -  gimple *store = gimple_build_assign (var, build_int_cst_type (etype, 
> cval));
> +  gimple *store = gimple_build_assign (var, cval_tree);
>    gimple_move_vops (store, stmt);
> -  gimple_set_location (store, gimple_location (stmt));
> +  gimple_set_location (store, loc);
>    gsi_insert_before (gsi, store, GSI_SAME_STMT);
> -  if (gimple_call_lhs (stmt))
> +
> +  if (tree lhs = gimple_call_lhs (stmt))
>      {
> -      gimple *asgn = gimple_build_assign (gimple_call_lhs (stmt), dest);
> -      gsi_replace (gsi, asgn, false);
> +      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);
>      }
>    else
>      {
> 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