https://gcc.gnu.org/g:6967bd6c9a0be06dfa9ad3b160701e862fe2baea
commit r17-5199-g6967bd6c9a0be06dfa9ad3b160701e862fe2baea Author: From: Jonas Hansen <[email protected]> Date: Wed Oct 14 07:28:06 2026 -0600 [PATCH v2 2/2] testsuite: Keep character-array and enum DSE coverage [PR127416] From: Jonas Hansen <[email protected]> Retain the original character-array program in ssa-dse-1.C and check that DSE removes the whole-object clear overwritten by the string assignment, including its implicit trailing zeros. Move the enum variant into ssa-dse-4.C with the original partial-DSE assertion. Tested on x86_64-pc-linux-gnu with 350 expected passes and three unsupported cases in the DSE and related initialization regression selection. Both tests also pass all four compile/dump checks for arm-none-eabi Cortex-M0. The new character-array assertion fails with the saved pre-follow-up compilers, and disabling partial DSE makes the enum assertion fail on both targets. gcc/testsuite/ChangeLog: PR tree-optimization/127416 * g++.dg/tree-ssa/ssa-dse-1.C (byte): Remove enum. (fixbuf): Restore char buffer elements. Update the dump assertion to check deletion of the redundant whole-object clear. * g++.dg/tree-ssa/ssa-dse-4.C: New test preserving the enum variant and partial-DSE assertion. Signed-off-by: Jonas Hansen <[email protected]> Diff: --- gcc/testsuite/g++.dg/tree-ssa/ssa-dse-1.C | 14 ++-- gcc/testsuite/g++.dg/tree-ssa/ssa-dse-4.C | 104 ++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 8 deletions(-) diff --git a/gcc/testsuite/g++.dg/tree-ssa/ssa-dse-1.C b/gcc/testsuite/g++.dg/tree-ssa/ssa-dse-1.C index a3dd41ff2eed..06cdfb5d6698 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/ssa-dse-1.C +++ b/gcc/testsuite/g++.dg/tree-ssa/ssa-dse-1.C @@ -3,10 +3,6 @@ using uint = unsigned int; -// Use a byte-sized enum so the initializer remains a CONSTRUCTOR rather than -// becoming a STRING_CST, preserving the stores this test exercises. -enum class byte : unsigned char {}; - template<typename C, uint S> struct FixBuf { @@ -75,10 +71,10 @@ template<uint N, uint S, bool BOS = 0> constexpr auto fixbuf() { - FixBuf<byte, S> fb; - OutBuf<byte> ob{fb}; + FixBuf<char, S> fb; + OutBuf<char> ob{fb}; for (uint i = 0; i <= N; ++i) { - ob << i << static_cast<byte>(i == N ? 0 : ' '); + ob << i << static_cast<char>(i == N ? 0 : ' '); } return BufOrSize<BOS>::Select(fb, ob); } @@ -101,4 +97,6 @@ int main() } -/* { dg-final { scan-tree-dump-times "MEM <char\\\[\[0-9\]+]> \\\[\\(struct FixBuf \\*\\)&<retval> \\+ \[0-9\]+B\\\] = {}" 1 "dse1" } } */ +// The string assignment includes the trailing zeros, making the preceding +// whole-object clear redundant. Keep partial DSE covered by ssa-dse-4.C. +/* { dg-final { scan-tree-dump-times "Deleted dead store: <retval> = {};" 1 "dse1" } } */ diff --git a/gcc/testsuite/g++.dg/tree-ssa/ssa-dse-4.C b/gcc/testsuite/g++.dg/tree-ssa/ssa-dse-4.C new file mode 100644 index 000000000000..a3dd41ff2eed --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/ssa-dse-4.C @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c++14 -O -fdump-tree-dse1-details" } */ + +using uint = unsigned int; + +// Use a byte-sized enum so the initializer remains a CONSTRUCTOR rather than +// becoming a STRING_CST, preserving the stores this test exercises. +enum class byte : unsigned char {}; + +template<typename C, uint S> +struct FixBuf +{ + C buf[S] = {}; +}; + +template<typename C> +struct OutBuf +{ + C* cur; + C* end; + C* beg; + + template<uint S> + constexpr + OutBuf(FixBuf<C, S>& b) : cur{b.buf}, end{b.buf + S}, beg{b.buf} { } + + OutBuf(C* b, C* e) : cur{b}, end{e} { } + OutBuf(C* b, uint s) : cur{b}, end{b + s} { } + + constexpr + OutBuf& operator<<(C v) + { + if (cur < end) { + *cur = v; + } + ++cur; + return *this; + } + + constexpr + OutBuf& operator<<(uint v) + { + uint q = v / 10U; + uint r = v % 10U; + if (q) { + *this << q; + } + *this << static_cast<C>(r + '0'); + return *this; + } +}; + +template<bool BOS> +struct BufOrSize +{ + template<typename C, uint S> + static constexpr auto Select(FixBuf<C, S>& fb, OutBuf<C>&) + { + return fb; + } +}; + +template<> +struct BufOrSize<true> +{ + template<typename C, uint S> + static constexpr auto Select(FixBuf<C, S>&, OutBuf<C>& ob) + { + return ob.cur - ob.beg; + } +}; + +// if BOS=1, it will return the size of the generated data, else the data itself +template<uint N, uint S, bool BOS = 0> +constexpr +auto fixbuf() +{ + FixBuf<byte, S> fb; + OutBuf<byte> ob{fb}; + for (uint i = 0; i <= N; ++i) { + ob << i << static_cast<byte>(i == N ? 0 : ' '); + } + return BufOrSize<BOS>::Select(fb, ob); +} + +auto foo() +{ + constexpr auto x = fixbuf<13, 200>(); + return x; +} + +auto foo_sized() +{ + constexpr auto s = fixbuf<13, 0, 1>(); + constexpr auto x = fixbuf<13, s>(); + return x; +} + +int main() +{ +} + + +/* { dg-final { scan-tree-dump-times "MEM <char\\\[\[0-9\]+]> \\\[\\(struct FixBuf \\*\\)&<retval> \\+ \[0-9\]+B\\\] = {}" 1 "dse1" } } */
