aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilip Kastl <fkastl@suse.cz>2025-03-02 06:39:17 +0100
committerFilip Kastl <fkastl@suse.cz>2025-03-02 06:39:17 +0100
commit5349aa2accdf34a7bf9cabd1447878aaadfc0e87 (patch)
tree0df81b7f14a2e83cbbea0cd687c12f0f089acc41
parent88e620c8d55a889c33e12b218cd51a3e6ac5011d (diff)
downloadgcc-5349aa2accdf34a7bf9cabd1447878aaadfc0e87.zip
gcc-5349aa2accdf34a7bf9cabd1447878aaadfc0e87.tar.gz
gcc-5349aa2accdf34a7bf9cabd1447878aaadfc0e87.tar.bz2
gimple: sccopy: Prune removed statements from SCCs [PR117919]
While writing the sccopy pass I didn't realize that 'replace_uses_by ()' can remove portions of the CFG. This happens when replacing arguments of some statement results in the removal of an EH edge. Because of this sccopy can then work with GIMPLE statements that aren't part of the IR anymore. In PR117919 this triggered an assertion within the pass which assumes that statements the pass works with are reachable. This patch tells the pass to notice when a statement isn't in the IR anymore and remove it from it's worklist. PR tree-optimization/117919 gcc/ChangeLog: * gimple-ssa-sccopy.cc (scc_copy_prop::propagate): Prune statements that 'replace_uses_by ()' removed. gcc/testsuite/ChangeLog: * g++.dg/pr117919.C: New test. Signed-off-by: Filip Kastl <fkastl@suse.cz>
-rw-r--r--gcc/gimple-ssa-sccopy.cc13
-rw-r--r--gcc/testsuite/g++.dg/pr117919.C52
2 files changed, 65 insertions, 0 deletions
diff --git a/gcc/gimple-ssa-sccopy.cc b/gcc/gimple-ssa-sccopy.cc
index 9f25fba..7ffb571 100644
--- a/gcc/gimple-ssa-sccopy.cc
+++ b/gcc/gimple-ssa-sccopy.cc
@@ -568,6 +568,19 @@ scc_copy_prop::propagate ()
{
vec<gimple *> scc = worklist.pop ();
+ /* When we do 'replace_scc_by_value' it may happen that some EH edges
+ get removed. That means parts of CFG get removed. Those may
+ contain copy statements. For that reason we prune SCCs here. */
+ unsigned i;
+ for (i = 0; i < scc.length (); i++)
+ if (gimple_bb (scc[i]) == NULL)
+ scc.unordered_remove (i);
+ if (scc.is_empty ())
+ {
+ scc.release ();
+ continue;
+ }
+
auto_vec<gimple *> inner;
hash_set<tree> outer_ops;
tree last_outer_op = NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/pr117919.C b/gcc/testsuite/g++.dg/pr117919.C
new file mode 100644
index 0000000..fa2d9c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr117919.C
@@ -0,0 +1,52 @@
+/* PR tree-optimization/117919 */
+/* { dg-do compile } */
+/* { dg-options "-O1 -fno-tree-forwprop -fnon-call-exceptions --param=early-inlining-insns=192 -std=c++20" } */
+
+char _M_p, _M_construct___beg;
+struct _Alloc_hider {
+ _Alloc_hider(char);
+};
+long _M_string_length;
+void _M_destroy();
+void _S_copy_chars(char *, char *, char *) noexcept;
+char _M_local_data();
+struct Trans_NS___cxx11_basic_string {
+ _Alloc_hider _M_dataplus;
+ bool _M_is_local() {
+ if (_M_local_data())
+ if (_M_string_length)
+ return true;
+ return false;
+ }
+ void _M_dispose() {
+ if (!_M_is_local())
+ _M_destroy();
+ }
+ char *_M_construct___end;
+ Trans_NS___cxx11_basic_string(Trans_NS___cxx11_basic_string &)
+ : _M_dataplus(0) {
+ struct _Guard {
+ ~_Guard() { _M_guarded->_M_dispose(); }
+ Trans_NS___cxx11_basic_string *_M_guarded;
+ } __guard0;
+ _S_copy_chars(&_M_p, &_M_construct___beg, _M_construct___end);
+ }
+};
+namespace filesystem {
+struct path {
+ path();
+ Trans_NS___cxx11_basic_string _M_pathname;
+};
+} // namespace filesystem
+struct FileWriter {
+ filesystem::path path;
+ FileWriter() : path(path) {}
+};
+struct LanguageFileWriter : FileWriter {
+ LanguageFileWriter(filesystem::path) {}
+};
+int
+main() {
+ filesystem::path output_file;
+ LanguageFileWriter writer(output_file);
+}