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;
+
+ /* 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