diff options
author | Roger Sayle <roger@nextmovesoftware.com> | 2022-05-13 22:20:16 +0100 |
---|---|---|
committer | Roger Sayle <roger@nextmovesoftware.com> | 2022-05-13 22:20:16 +0100 |
commit | 1fe04c497d5a16baee6af48a0b08ca99b75724e4 (patch) | |
tree | e913d36dacd0894c24eafb38386a16b20036319b | |
parent | 16f7fcadac19dabd04a5abbe6601df52d22e9685 (diff) | |
download | gcc-1fe04c497d5a16baee6af48a0b08ca99b75724e4.zip gcc-1fe04c497d5a16baee6af48a0b08ca99b75724e4.tar.gz gcc-1fe04c497d5a16baee6af48a0b08ca99b75724e4.tar.bz2 |
PR tree-optimization/83907: Improved memset handling in strlen pass.
This patch implements the missed optimization enhancement PR 83907,
by handling memset with a constant byte value in tree-ssa's strlen
optimization pass. Effectively, this treats memset(dst,'x',3) as
it would memcpy(dst,"xxx",3).
This patch also includes a tweak to handle_store to address another
missed optimization observed in the related test case pr83907-2.c.
The consecutive byte stores to memory get coalesced into a vector
write of a vector const, but unfortunately tree-ssa-strlen's
handle_store didn't previously handle the (unusual) case where the
stored "string" starts with a zero byte but also contains non-zero
bytes.
2022-05-13 Roger Sayle <roger@nextmovesoftware.com>
gcc/ChangeLog
PR tree-optimization/83907
* tree-ssa-strlen.cc (handle_builtin_memset): Record a strinfo
for memset with an constant char value.
(handle_store): Improved handling of stores with a first byte
of zero, but not storing_all_zeros_p.
gcc/testsuite/ChangeLog
PR tree-optimization/83907
* gcc.dg/tree-ssa/pr83907-1.c: New test case.
* gcc.dg/tree-ssa/pr83907-2.c: New test case.
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/pr83907-1.c | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/pr83907-2.c | 14 | ||||
-rw-r--r-- | gcc/tree-ssa-strlen.cc | 48 |
3 files changed, 69 insertions, 6 deletions
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr83907-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr83907-1.c new file mode 100644 index 0000000..2a6f4f5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr83907-1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +extern char str[]; + +unsigned int foo() +{ + __builtin_memset(str,'x',5); + str[5] = 0; + return __builtin_strlen (str); +} + +/* { dg-final { scan-tree-dump-not "strlen" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr83907-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr83907-2.c new file mode 100644 index 0000000..cc27504 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr83907-2.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +extern char str[]; + +unsigned int foo() +{ + __builtin_memset(str,'x',5); + str[5] = 0; + str[6] = 'z'; + return __builtin_strlen (str); +} + +/* { dg-final { scan-tree-dump-not "strlen" "optimized" } } */ diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc index bb7fe08..1d4c0f7 100644 --- a/gcc/tree-ssa-strlen.cc +++ b/gcc/tree-ssa-strlen.cc @@ -3805,9 +3805,44 @@ strlen_pass::handle_builtin_memset (bool *zero_write) { gimple *memset_stmt = gsi_stmt (m_gsi); tree ptr = gimple_call_arg (memset_stmt, 0); + tree memset_val = gimple_call_arg (memset_stmt, 1); + tree memset_size = gimple_call_arg (memset_stmt, 2); + /* Set to the non-constant offset added to PTR. */ wide_int offrng[2]; int idx1 = get_stridx (ptr, memset_stmt, offrng, ptr_qry.rvals); + if (idx1 == 0 + && TREE_CODE (memset_val) == INTEGER_CST + && ((TREE_CODE (memset_size) == INTEGER_CST + && !integer_zerop (memset_size)) + || TREE_CODE (memset_size) == SSA_NAME)) + { + unsigned HOST_WIDE_INT mask = (HOST_WIDE_INT_1U << CHAR_TYPE_SIZE) - 1; + bool full_string_p = (wi::to_wide (memset_val) & mask) == 0; + + /* We only handle symbolic lengths when writing non-zero values. */ + if (full_string_p && TREE_CODE (memset_size) != INTEGER_CST) + return false; + + idx1 = new_stridx (ptr); + if (idx1 == 0) + return false; + tree newlen; + if (full_string_p) + newlen = build_int_cst (size_type_node, 0); + else if (TREE_CODE (memset_size) == INTEGER_CST) + newlen = fold_convert (size_type_node, memset_size); + else + newlen = memset_size; + + strinfo *dsi = new_strinfo (ptr, idx1, newlen, full_string_p); + set_strinfo (idx1, dsi); + find_equal_ptrs (ptr, idx1); + dsi->dont_invalidate = true; + dsi->writable = true; + return false; + } + if (idx1 <= 0) return false; strinfo *si1 = get_strinfo (idx1); @@ -3820,7 +3855,6 @@ strlen_pass::handle_builtin_memset (bool *zero_write) if (!valid_builtin_call (alloc_stmt)) return false; tree alloc_size = gimple_call_arg (alloc_stmt, 0); - tree memset_size = gimple_call_arg (memset_stmt, 2); /* Check for overflow. */ maybe_warn_overflow (memset_stmt, false, memset_size, NULL, false, true); @@ -3836,7 +3870,7 @@ strlen_pass::handle_builtin_memset (bool *zero_write) return false; /* Bail when the call writes a non-zero value. */ - if (!integer_zerop (gimple_call_arg (memset_stmt, 1))) + if (!integer_zerop (memset_val)) return false; /* Let the caller know the memset call cleared the destination. */ @@ -5089,8 +5123,9 @@ strlen_pass::handle_store (bool *zero_write) return false; } - if (storing_all_zeros_p - || storing_nonzero_p + if (storing_nonzero_p + || storing_all_zeros_p + || (full_string_p && lenrange[1] == 0) || (offset != 0 && store_before_nul[1] > 0)) { /* When STORING_NONZERO_P, we know that the string will start @@ -5100,8 +5135,9 @@ strlen_pass::handle_store (bool *zero_write) of leading non-zero characters and set si->NONZERO_CHARS to the result instead. - When STORING_ALL_ZEROS_P, we know that the string is now - OFFSET characters long. + When STORING_ALL_ZEROS_P, or the first byte written is zero, + i.e. FULL_STRING_P && LENRANGE[1] == 0, we know that the + string is now OFFSET characters long. Otherwise, we're storing an unknown value at offset OFFSET, so need to clip the nonzero_chars to OFFSET. |