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
>