Hi!

On the following testcase, we have a call (not marked noreturn), which can
throw, followed immediately by __builtin_unreachable (), so it effectively
is noreturn in this particular call site (i.e. if it returns, it is UB).
In RTL this is represented by the corresponding bb having just EH edge
successor, no fallthrough edge.  If one of the callers of
fixup_abnormal_edges (the stack pass in this case, or LRA or reload) adds
some instructions after the call and calls fixup_abnormal_edges, it ICEs,
as it tries to delete those insns and insert them on the NULL edge.
Somebody has hit that issue already but solved it for USE insns only, this
patch does that for all the cases where we don't have the fallthru edge.
If there weren't any instructions after the call before one of these 3
passes, I'd say it must be UB to return from such a call and thus it should
be unimportant if those insns are executed or not.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-11-15  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/88018
        * cfgrtl.c (fixup_abnormal_edges): Guard moving insns to fallthru edge
        on the presence of fallthru edge, rather than if it is a USE or not.

        * g++.dg/tsan/pr88018.C: New test.

--- gcc/cfgrtl.c.jj     2018-11-14 00:55:51.695333876 +0100
+++ gcc/cfgrtl.c        2018-11-14 17:24:46.414915101 +0100
@@ -3332,8 +3332,15 @@ fixup_abnormal_edges (void)
                         If it's placed after a trapping call (i.e. that
                         call is the last insn anyway), we have no fallthru
                         edge.  Simply delete this use and don't try to insert
-                        on the non-existent edge.  */
-                     if (GET_CODE (PATTERN (insn)) != USE)
+                        on the non-existent edge.
+                        Similarly, sometimes a call that can throw is
+                        followed in the source with __builtin_unreachable (),
+                        meaning that there is UB if the call returns rather
+                        than throws.  If there weren't any instructions
+                        following such calls before, supposedly even the ones
+                        we've deleted aren't significant and can be
+                        removed.  */
+                     if (e)
                        {
                          /* We're not deleting it, we're moving it.  */
                          insn->set_undeleted ();
--- gcc/testsuite/g++.dg/tsan/pr88018.C.jj      2018-11-14 17:26:46.224944969 
+0100
+++ gcc/testsuite/g++.dg/tsan/pr88018.C 2018-11-14 17:28:40.057073142 +0100
@@ -0,0 +1,6 @@
+// PR rtl-optimization/88018
+// { dg-do compile }
+// { dg-skip-if "" { *-*-* }  { "*" } { "-O0" } }
+// { dg-options "-fsanitize=thread -fno-ipa-pure-const -O1 
-fno-inline-functions-called-once -w" }
+
+#include "../pr69667.C"

        Jakub

Reply via email to