commit: 2f4f4f1d4b8134456c4a5e23607a44c59b5dd581 Author: Sam James <sam <AT> gentoo <DOT> org> AuthorDate: Wed Apr 2 18:03:43 2025 +0000 Commit: Sam James <sam <AT> gentoo <DOT> org> CommitDate: Wed Apr 2 18:03:43 2025 +0000 URL: https://gitweb.gentoo.org/proj/gcc-patches.git/commit/?id=2f4f4f1d
15.0.0: drop upstream tailcall eh patch Just merged. Signed-off-by: Sam James <sam <AT> gentoo.org> 15.0.0/gentoo/83_all_PR119491-tailcall-eh.patch | 409 ------------------------ 15.0.0/gentoo/README.history | 1 - 2 files changed, 410 deletions(-) diff --git a/15.0.0/gentoo/83_all_PR119491-tailcall-eh.patch b/15.0.0/gentoo/83_all_PR119491-tailcall-eh.patch deleted file mode 100644 index 040d2f8..0000000 --- a/15.0.0/gentoo/83_all_PR119491-tailcall-eh.patch +++ /dev/null @@ -1,409 +0,0 @@ -https://inbox.sourceware.org/gcc-patches/Z+1hCrznhv68Sv4J@tucnak/ - -From e561af4c75ca62ae9363700531e60cc5793a88b3 Mon Sep 17 00:00:00 2001 -Message-ID: <e561af4c75ca62ae9363700531e60cc5793a88b3.1743610408.git....@gentoo.org> -From: Jakub Jelinek <[email protected]> -Date: Wed, 2 Apr 2025 18:08:42 +0200 -Subject: [PATCH] tailc: Deal with trivially useless EH cleanups [PR119491] - -Hi! - -The following testcases FAIL, because EH cleanup is performed only before -IPA and then right before musttail pass. -At -O2 etc. (except for -O0/-Og) we handle musttail calls in the tailc -pass though, and we can fail at that point because the calls might appear -to throw internal exceptions which just don't do anything interesting -(perhaps have debug statements or clobber statements in them) before they -continue with resume of the exception (i.e. throw it externally). - -As Richi said in the PR (and I agree) that moving passes is risky at this -point, the following patch instead teaches the tail{r,c} and musttail -passes to deal with such extra EDGE_EH edges. - -It is fairly simple thing, if we see an EDGE_EH edge from the call we -just look up where it lands and if there are no -non-debug/non-clobber/non-label statements before resx which throws -externally, such edge can be ignored for tail call optimization or -tail recursion. At other spots I just need to avoid using -single_succ/single_succ_edge because the bb might have another edge - -EDGE_EH. - -To make this less risky, this is done solely for the musttail calls for now. - -Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? - -2025-04-02 Jakub Jelinek <[email protected]> - - PR tree-optimization/119491 - * tree-tailcall.cc (single_non_eh_succ_edge): New function. - (independent_of_stmt_p): Use single_non_eh_succ_edge (bb)->dest - instead of single_succ (bb). - (empty_eh_cleanup): New function. - (find_tail_calls): Diagnose throwing of exceptions which do not - propagate only if there are no EDGE_EH successor edges. If there are - and the call is musttail, use empty_eh_cleanup to find if the cleanup - is not empty. If not or the call is not musttail, use different - diagnostics. Set is_noreturn even if there are successor edges. Use - single_non_eh_succ_edge (abb) instead of single_succ_edge (abb). Punt - on internal noreturn calls. - (decrease_profile): Don't assert 0 or 1 successor edges. - (eliminate_tail_call): Use - single_non_eh_succ_edge (gsi_bb (t->call_gsi)) instead of - single_succ_edge (gsi_bb (t->call_gsi)). - (tree_optimize_tail_calls_1): Also look into basic blocks with - single succ edge which is EDGE_EH for noreturn musttail calls. - - * g++.dg/opt/musttail3.C: New test. - * g++.dg/opt/musttail4.C: New test. - * g++.dg/opt/musttail5.C: New test. ---- - gcc/testsuite/g++.dg/opt/musttail3.C | 41 ++++++++++ - gcc/testsuite/g++.dg/opt/musttail4.C | 35 +++++++++ - gcc/testsuite/g++.dg/opt/musttail5.C | 41 ++++++++++ - gcc/tree-tailcall.cc | 113 +++++++++++++++++++++------ - 4 files changed, 207 insertions(+), 23 deletions(-) - create mode 100644 gcc/testsuite/g++.dg/opt/musttail3.C - create mode 100644 gcc/testsuite/g++.dg/opt/musttail4.C - create mode 100644 gcc/testsuite/g++.dg/opt/musttail5.C - -diff --git a/gcc/testsuite/g++.dg/opt/musttail3.C b/gcc/testsuite/g++.dg/opt/musttail3.C -new file mode 100644 -index 000000000000..1c4e54952b1e ---- /dev/null -+++ b/gcc/testsuite/g++.dg/opt/musttail3.C -@@ -0,0 +1,41 @@ -+// PR tree-optimization/119491 -+// { dg-do compile { target { external_musttail && c++11 } } } -+// { dg-options "-O2" } -+ -+struct A { -+ struct B {}; -+ A () {} -+}; -+void qux (); -+unsigned char v; -+A w; -+void foo (A); -+ -+template <typename T> -+[[gnu::always_inline]] static inline void -+bar (int &) -+{ -+} -+ -+[[gnu::always_inline]] static inline void -+baz (int *) -+{ -+ int r = 0; -+ bar<int> (r); -+} -+ -+[[gnu::always_inline]] inline void -+corge (A) -+{ -+ if (v) -+ qux (); -+ [[gnu::musttail]] return foo (w); -+} -+ -+void -+freddy (A) -+{ -+ int t; -+ baz (&t); -+ [[gnu::musttail]] return corge (A{}); -+} -diff --git a/gcc/testsuite/g++.dg/opt/musttail4.C b/gcc/testsuite/g++.dg/opt/musttail4.C -new file mode 100644 -index 000000000000..ede2959f7d74 ---- /dev/null -+++ b/gcc/testsuite/g++.dg/opt/musttail4.C -@@ -0,0 +1,35 @@ -+// { dg-do compile { target { external_musttail && c++11 } } } -+// { dg-options "-O2 -fexceptions" } -+ -+struct S { ~S (); }; -+volatile int v; -+struct T { ~T () { v = v + 1; } }; -+struct U { ~U () {} }; -+int foo (); -+ -+int -+bar () noexcept -+{ -+ [[gnu::musttail]] return foo (); // { dg-error "cannot tail-call: call may throw exception that does not propagate" } -+} -+ -+int -+baz () -+{ -+ S s; -+ [[gnu::musttail]] return foo (); // { dg-error "cannot tail-call: other reasons" } -+} -+ -+int -+qux () -+{ -+ T t; -+ [[gnu::musttail]] return foo (); // { dg-error "cannot tail-call: other reasons" } -+} -+ -+int -+corge () -+{ -+ U u; -+ [[gnu::musttail]] return foo (); -+} -diff --git a/gcc/testsuite/g++.dg/opt/musttail5.C b/gcc/testsuite/g++.dg/opt/musttail5.C -new file mode 100644 -index 000000000000..604dd6907aa9 ---- /dev/null -+++ b/gcc/testsuite/g++.dg/opt/musttail5.C -@@ -0,0 +1,41 @@ -+// PR tree-optimization/119491 -+// { dg-do compile { target { external_musttail && c++11 } } } -+// { dg-options "-O2" } -+ -+struct A { -+ struct B {}; -+ A () {} -+}; -+void qux (); -+unsigned char v; -+A w; -+[[noreturn]] void foo (A); -+ -+template <typename T> -+[[gnu::always_inline]] static inline void -+bar (int &) -+{ -+} -+ -+[[gnu::always_inline]] static inline void -+baz (int *) -+{ -+ int r = 0; -+ bar<int> (r); -+} -+ -+[[gnu::always_inline]] inline void -+corge (A) -+{ -+ if (v) -+ qux (); -+ [[gnu::musttail]] return foo (w); -+} -+ -+void -+freddy (A) -+{ -+ int t; -+ baz (&t); -+ [[gnu::musttail]] return corge (A{}); -+} -diff --git a/gcc/tree-tailcall.cc b/gcc/tree-tailcall.cc -index 374be2ae6a75..477729ca2137 100644 ---- a/gcc/tree-tailcall.cc -+++ b/gcc/tree-tailcall.cc -@@ -253,6 +253,23 @@ suitable_for_tail_call_opt_p (gcall *call, bool diag_musttail) - return true; - } - -+/* Return single successor edge ignoring EDGE_EH edges. */ -+ -+static edge -+single_non_eh_succ_edge (basic_block bb) -+{ -+ edge e, ret = NULL; -+ edge_iterator ei; -+ FOR_EACH_EDGE (e, ei, bb->succs) -+ if ((e->flags & EDGE_EH) == 0) -+ { -+ gcc_assert (ret == NULL); -+ ret = e; -+ } -+ gcc_assert (ret); -+ return ret; -+} -+ - /* Checks whether the expression EXPR in stmt AT is independent of the - statement pointed to by GSI (in a sense that we already know EXPR's value - at GSI). We use the fact that we are only called from the chain of -@@ -279,7 +296,7 @@ independent_of_stmt_p (tree expr, gimple *at, gimple_stmt_iterator gsi, - /* Mark the blocks in the chain leading to the end. */ - at_bb = gimple_bb (at); - call_bb = gimple_bb (gsi_stmt (gsi)); -- for (bb = call_bb; bb != at_bb; bb = single_succ (bb)) -+ for (bb = call_bb; bb != at_bb; bb = single_non_eh_succ_edge (bb)->dest) - bb->aux = &bb->aux; - bb->aux = &bb->aux; - -@@ -323,7 +340,7 @@ independent_of_stmt_p (tree expr, gimple *at, gimple_stmt_iterator gsi, - } - - /* Unmark the blocks. */ -- for (bb = call_bb; bb != at_bb; bb = single_succ (bb)) -+ for (bb = call_bb; bb != at_bb; bb = single_non_eh_succ_edge (bb)->dest) - bb->aux = NULL; - bb->aux = NULL; - -@@ -496,6 +513,33 @@ maybe_error_musttail (gcall *call, const char *err, bool diag_musttail) - } - } - -+/* Return true if there is no real work performed in the exception -+ path starting at BB and it will in the end result in external exception. -+ Search at most CNT basic blocks (so that we don't need to do trivial -+ loop discovery). */ -+static bool -+empty_eh_cleanup (basic_block bb, int cnt) -+{ -+ if (EDGE_COUNT (bb->succs) > 1) -+ return false; -+ -+ for (gimple_stmt_iterator gsi = gsi_after_labels (bb); !gsi_end_p (gsi); -+ gsi_next (&gsi)) -+ { -+ gimple *g = gsi_stmt (gsi); -+ if (is_gimple_debug (g) || gimple_clobber_p (g)) -+ continue; -+ if (is_gimple_resx (g) && stmt_can_throw_external (cfun, g)) -+ return true; -+ return false; -+ } -+ if (!single_succ_p (bb)) -+ return false; -+ if (cnt == 1) -+ return false; -+ return empty_eh_cleanup (single_succ (bb), cnt - 1); -+} -+ - /* Argument for compute_live_vars/live_vars_at_stmt and what compute_live_vars - returns. Computed lazily, but just once for the function. */ - static live_vars_map *live_vars; -@@ -646,14 +690,36 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, - if ((stmt_could_throw_p (cfun, stmt) - && !stmt_can_throw_external (cfun, stmt)) || EDGE_COUNT (bb->succs) > 1) - { -- if (stmt == last_stmt) -- maybe_error_musttail (call, -- _("call may throw exception that does not " -- "propagate"), diag_musttail); -- else -- maybe_error_musttail (call, _("code between call and return"), -- diag_musttail); -- return; -+ if (stmt != last_stmt) -+ { -+ maybe_error_musttail (call, _("code between call and return"), -+ diag_musttail); -+ return; -+ } -+ -+ edge e; -+ edge_iterator ei; -+ FOR_EACH_EDGE (e, ei, bb->succs) -+ if (e->flags & EDGE_EH) -+ break; -+ -+ if (!e) -+ { -+ maybe_error_musttail (call, -+ _("call may throw exception that does not " -+ "propagate"), diag_musttail); -+ return; -+ } -+ -+ if (!gimple_call_must_tail_p (call) -+ || !empty_eh_cleanup (e->dest, 20) -+ || EDGE_COUNT (bb->succs) > 2) -+ { -+ maybe_error_musttail (call, -+ _("call may throw exception caught locally " -+ "or perform cleanups"), diag_musttail); -+ return; -+ } - } - - /* If the function returns a value, then at present, the tail call -@@ -844,8 +910,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, - a = NULL_TREE; - auto_bitmap to_move_defs; - auto_vec<gimple *> to_move_stmts; -- bool is_noreturn -- = EDGE_COUNT (bb->succs) == 0 && gimple_call_noreturn_p (call); -+ bool is_noreturn = gimple_call_noreturn_p (call); - - abb = bb; - agsi = gsi; -@@ -857,8 +922,9 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, - - while (gsi_end_p (agsi)) - { -- ass_var = propagate_through_phis (ass_var, single_succ_edge (abb)); -- abb = single_succ (abb); -+ edge e = single_non_eh_succ_edge (abb); -+ ass_var = propagate_through_phis (ass_var, e); -+ abb = e->dest; - agsi = gsi_start_bb (abb); - } - -@@ -932,6 +998,11 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, - /* See if this is a tail call we can handle. */ - if (is_noreturn) - { -+ if (gimple_call_internal_p (call)) -+ { -+ maybe_error_musttail (call, _("internal call"), diag_musttail); -+ return; -+ } - tree rettype = TREE_TYPE (TREE_TYPE (current_function_decl)); - tree calltype = TREE_TYPE (gimple_call_fntype (call)); - if (!VOID_TYPE_P (rettype) -@@ -1193,11 +1264,6 @@ static void - decrease_profile (basic_block bb, profile_count count) - { - bb->count = bb->count - count; -- if (!single_succ_p (bb)) -- { -- gcc_assert (!EDGE_COUNT (bb->succs)); -- return; -- } - } - - /* Eliminates tail call described by T. TMP_VARS is a list of -@@ -1262,7 +1328,7 @@ eliminate_tail_call (struct tailcall *t, class loop *&new_loop) - else - { - /* Number of executions of function has reduced by the tailcall. */ -- e = single_succ_edge (gsi_bb (t->call_gsi)); -+ e = single_non_eh_succ_edge (gsi_bb (t->call_gsi)); - - profile_count count = e->count (); - -@@ -1277,8 +1343,7 @@ eliminate_tail_call (struct tailcall *t, class loop *&new_loop) - decrease_profile (e->dest, count); - - /* Replace the call by a jump to the start of function. */ -- e = redirect_edge_and_branch (single_succ_edge (gsi_bb (t->call_gsi)), -- first); -+ e = redirect_edge_and_branch (e, first); - } - gcc_assert (e); - PENDING_STMT (e) = NULL; -@@ -1443,7 +1508,9 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls, bool only_musttail, - { - basic_block bb; - FOR_EACH_BB_FN (bb, cfun) -- if (EDGE_COUNT (bb->succs) == 0) -+ if (EDGE_COUNT (bb->succs) == 0 -+ || (single_succ_p (bb) -+ && (single_succ_edge (bb)->flags & EDGE_EH))) - if (gimple *c = last_nondebug_stmt (bb)) - if (is_gimple_call (c) - && gimple_call_must_tail_p (as_a <gcall *> (c)) - -base-commit: aca8155c09001f269a20d6df438fa0e749dd5388 --- -2.49.0 - diff --git a/15.0.0/gentoo/README.history b/15.0.0/gentoo/README.history index 8223363..48fa9bd 100644 --- a/15.0.0/gentoo/README.history +++ b/15.0.0/gentoo/README.history @@ -2,7 +2,6 @@ - 80_all_PR119376-tailc-Don-t-fail-musttail-calls-if-they-use-or-could.patch + 82_all_PR119318-ipa-cp.patch - + 83_all_PR119491-tailcall-eh.patch 50 31 March 2025
