From 63e1b2e767a3f4695373c2406ff719c0a60c1858 Mon Sep 17 00:00:00 2001 From: Kewen Lin Date: Tue, 15 Nov 2022 20:26:07 -0600 Subject: [PATCH] rtl: Try to remove EH edges after {pro,epi}logue generation [PR90259] After prologue and epilogue generation, the judgement on whether one memory access onto stack frame may trap or not could change, since we get more exact stack information by now. As PR90259 shows, some memory access becomes impossible to trap any more after prologue and epilogue generation, it can make subsequent optimization be able to remove it if safe, but it results in unexpected control flow status due to REG_EH_REGION note missing. This patch proposes to try to remove EH edges with function purge_all_dead_edges after prologue and epilogue generation, it simplifies CFG as early as we can and don't need any fixup in downstream passes. CFG simplification result with PR90259's case as example: *before* 18: %1:TF=call [`__gcc_qdiv'] argc:0 REG_EH_REGION 0x2 77: NOTE_INSN_BASIC_BLOCK 3 19: NOTE_INSN_DELETED 20: NOTE_INSN_DELETED 110: [%31:SI+0x20]=%1:DF REG_EH_REGION 0x2 116: NOTE_INSN_BASIC_BLOCK 4 111: [%31:SI+0x28]=%2:DF REG_EH_REGION 0x2 22: NOTE_INSN_BASIC_BLOCK 5 108: %0:DF=[%31:SI+0x20] REG_EH_REGION 0x2 117: NOTE_INSN_BASIC_BLOCK 6 109: %1:DF=[%31:SI+0x28] REG_EH_REGION 0x2 79: NOTE_INSN_BASIC_BLOCK 7 26: [%31:SI+0x18]=%0:DF 104: pc=L69 105: barrier *after* 18: %1:TF=call [`__gcc_qdiv'] argc:0 REG_EH_REGION 0x2 77: NOTE_INSN_BASIC_BLOCK 3 19: NOTE_INSN_DELETED 20: NOTE_INSN_DELETED 110: [%31:SI+0x20]=%1:DF 111: [%31:SI+0x28]=%2:DF 108: %0:DF=[%31:SI+0x20] 109: %1:DF=[%31:SI+0x28] 26: [%31:SI+0x18]=%0:DF 104: pc=L69 105: barrier PR rtl-optimization/90259 gcc/ChangeLog: * function.cc (rest_of_handle_thread_prologue_and_epilogue): Add parameter fun, and call function purge_all_dead_edges. (pass_thread_prologue_and_epilogue::execute): Name unamed parameter as fun, and use it for rest_of_handle_thread_prologue_and_epilogue. gcc/testsuite/ChangeLog: * g++.target/powerpc/pr90259.C: New. --- gcc/function.cc | 13 ++- gcc/testsuite/g++.target/powerpc/pr90259.C | 103 +++++++++++++++++++++ 2 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.target/powerpc/pr90259.C diff --git a/gcc/function.cc b/gcc/function.cc index d3da20ede7f..361aa5f7ed1 100644 --- a/gcc/function.cc +++ b/gcc/function.cc @@ -6546,7 +6546,7 @@ make_pass_leaf_regs (gcc::context *ctxt) } static unsigned int -rest_of_handle_thread_prologue_and_epilogue (void) +rest_of_handle_thread_prologue_and_epilogue (function *fun) { /* prepare_shrink_wrap is sensitive to the block structure of the control flow graph, so clean it up first. */ @@ -6563,6 +6563,13 @@ rest_of_handle_thread_prologue_and_epilogue (void) Fix that up. */ fixup_partitions (); + /* After prologue and epilogue generation, the judgement on whether + one memory access onto stack frame may trap or not could change, + since we get more exact stack information by now. So try to + remove any EH edges here, see PR90259. */ + if (fun->can_throw_non_call_exceptions) + purge_all_dead_edges (); + /* Shrink-wrapping can result in unreachable edges in the epilogue, see PR57320. */ cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0); @@ -6631,9 +6638,9 @@ public: {} /* opt_pass methods: */ - unsigned int execute (function *) final override + unsigned int execute (function * fun) final override { - return rest_of_handle_thread_prologue_and_epilogue (); + return rest_of_handle_thread_prologue_and_epilogue (fun); } }; // class pass_thread_prologue_and_epilogue diff --git a/gcc/testsuite/g++.target/powerpc/pr90259.C b/gcc/testsuite/g++.target/powerpc/pr90259.C new file mode 100644 index 00000000000..db75ac7fe02 --- /dev/null +++ b/gcc/testsuite/g++.target/powerpc/pr90259.C @@ -0,0 +1,103 @@ +/* { dg-require-effective-target long_double_ibm128 } */ +/* { dg-options "-O2 -ffloat-store -fgcse -fnon-call-exceptions -fno-forward-propagate -fno-omit-frame-pointer -fstack-protector-all" } */ +/* { dg-add-options long_double_ibm128 } */ + +/* Verify there is no ICE. */ + +template struct b +{ + static constexpr int c = a; +}; +template using d = b; +struct e +{ + int f; + int + g () + { + return __builtin_ceil (f / (long double) h); + } + float h; +}; +template using k = d; +template class n +{ +public: + e ae; + void af (); +}; +template +void +n::af () +{ + ae.g (); +} +template using m = int; +template ::c>> +using aj = n; +struct o +{ + void + af () + { + al.af (); + } + aj al; +}; +template class am; +template class ao +{ +protected: + static i *ap (int); +}; +template class p; +template class p : ao +{ +public: + static ar + as (const int &p1, j...) + { + (*ao::ap (p1)) (j ()...); + } +}; +template class am +{ + template using av = int; + +public: + template , void>, + typename = av> + am (i); + using aw = ar (*) (const int &, j...); + aw ax; +}; +template +template +am::am (i) +{ + ax = p::as; +} +struct G +{ + void ba (am); +}; +struct q +{ + q () + { + G a; + a.ba (r ()); + } + struct r + { + void + operator() (o p1) + try + { + p1.af (); + } + catch (int) + { + } + }; +} s;