]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/108691 - indirect calls to setjmp
authorRichard Biener <rguenther@suse.de>
Mon, 13 Feb 2023 09:41:51 +0000 (10:41 +0100)
committerRichard Biener <rguenther@suse.de>
Mon, 13 Feb 2023 14:57:08 +0000 (15:57 +0100)
DCE now chokes on indirect setjmp calls becoming direct because
that exposes them too late to be subject to abnormal edge creation.
The following patch honors gimple_call_ctrl_altering for those and
_not_ treat formerly indirect calls to setjmp as calls to setjmp
in notice_special_calls.

Unfortunately there's no way to have an indirect call to setjmp
properly annotated (the returns_twice attribute is ignored on types).

RTL expansion late discovers returns-twice for the purpose of
adding REG_SETJMP notes and also sets ->calls_setjmp
(instead of asserting it is set).  There's no good way to
transfer proper knowledge around here so I'm using ->calls_setjmp
as a flag to indicate whether gimple_call_ctrl_altering_p was set.

PR tree-optimization/108691
* tree-cfg.cc (notice_special_calls): When the CFG is built
honor gimple_call_ctrl_altering_p.
* cfgexpand.cc (expand_call_stmt): Clear cfun->calls_setjmp
temporarily if the call is not control-altering.
* calls.cc (emit_call_1): Do not add REG_SETJMP if
cfun->calls_setjmp is not set.  Do not alter cfun->calls_setjmp.

* gcc.dg/pr108691.c: New testcase.

gcc/calls.cc
gcc/cfgexpand.cc
gcc/testsuite/gcc.dg/pr108691.c [new file with mode: 0644]
gcc/tree-cfg.cc

index 4d7f6c3d2912c9dcb150d8d219dce07d99ada0a6..0242d52cfb35a90c2594e5f74579f45aecec76ce 100644 (file)
@@ -506,11 +506,11 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
   if (ecf_flags & ECF_NORETURN)
     add_reg_note (call_insn, REG_NORETURN, const0_rtx);
 
-  if (ecf_flags & ECF_RETURNS_TWICE)
-    {
-      add_reg_note (call_insn, REG_SETJMP, const0_rtx);
-      cfun->calls_setjmp = 1;
-    }
+  if (ecf_flags & ECF_RETURNS_TWICE
+      /* We rely on GIMPLE setting this flag and here use it to
+        catch formerly indirect and not control-altering calls.  */
+      && cfun->calls_setjmp)
+    add_reg_note (call_insn, REG_SETJMP, const0_rtx);
 
   SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0);
 
index 25b1558dcb941ea491a19aeeb2cd8f4d2dbdf7c6..ab143a6d2d3df70a0bdd7fbf842fd631c6888260 100644 (file)
@@ -2808,6 +2808,11 @@ expand_call_stmt (gcall *stmt)
   /* Must come after copying location.  */
   copy_warning (exp, stmt);
 
+  /* For calls that do not alter control flow avoid REG_SETJMP notes.  */
+  bool saved_calls_setjmp = cfun->calls_setjmp;
+  if (!gimple_call_ctrl_altering_p (stmt))
+    cfun->calls_setjmp = false;
+
   /* Ensure RTL is created for debug args.  */
   if (decl && DECL_HAS_DEBUG_ARGS_P (decl))
     {
@@ -2846,6 +2851,8 @@ expand_call_stmt (gcall *stmt)
     }
 
   mark_transaction_restart_calls (stmt);
+
+  cfun->calls_setjmp = saved_calls_setjmp;
 }
 
 
diff --git a/gcc/testsuite/gcc.dg/pr108691.c b/gcc/testsuite/gcc.dg/pr108691.c
new file mode 100644 (file)
index 0000000..e412df1
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+extern int __attribute__((returns_twice)) setjmp(void*);
+
+void bbb(void) {
+  int (*fnptr)(void*) = setjmp;
+  fnptr(0);
+}
index a9fcc7fd050f871437ef336ecfb8d6cc81280ee0..e23293e5cd1fbe606542f56e3da9fa5b84434cae 100644 (file)
@@ -2280,7 +2280,9 @@ notice_special_calls (gcall *call)
 
   if (flags & ECF_MAY_BE_ALLOCA)
     cfun->calls_alloca = true;
-  if (flags & ECF_RETURNS_TWICE)
+  if (flags & ECF_RETURNS_TWICE
+      && (!(cfun->curr_properties & PROP_cfg)
+         || gimple_call_ctrl_altering_p (call)))
     cfun->calls_setjmp = true;
 }