Bug 57067

Summary: Missing control flow edges for setjmp/longjmp
Product: gcc Reporter: Andreas Krebbel <krebbel>
Component: rtl-optimizationAssignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: normal CC: dimhen, fxue, matz, qinzhao, rguenth, sjames
Priority: P3 Keywords: wrong-code
Version: 4.9.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2013-04-25 00:00:00
Bug Depends on: 56982    
Bug Blocks: 96672    
Attachments: testcase

Description Andreas Krebbel 2013-04-25 08:23:49 UTC
The fix for PR56982 adds abnormal control flow edges from function calls to a setjmp call in the same function. Unfortunately these edges do not survive until RTL so that the RTL passes might still do the wrong thing. 

The edges are removed in gimple_expand_cfg:

	  /* At the moment not all abnormal edges match the RTL
	     representation.  It is safe to remove them here as
	     find_many_sub_basic_blocks will rediscover them.
	     In the future we should get this fixed properly.  */
	  if ((e->flags & EDGE_ABNORMAL)
	      && !(e->flags & EDGE_SIBCALL))
	    remove_edge (e);
	  else
	    ei_next (&ei);


find_many_sub_basic_blocks needs a fix to add them back as well.

I don't have a testcase for GCC head.  The testcase I have fails only with GCC 4.4: http://gcc.gnu.org/ml/gcc/2013-04/msg00237.html

In this case the RTL scheduler pass generates broken code due to the missing control flow info.  I think this could potentially happen with GCC head as well.
Comment 1 Richard Biener 2013-04-25 09:17:03 UTC
I suppose more selectively removing edges would be best.  Eventually this is
done to cater for expansions of builtin calls to non-calls?  Then maybe
those edges should be removed later, _after_ builtin expansion and
find_many_sub_basic_blocks?
Comment 2 Andreas Krebbel 2013-04-25 14:46:09 UTC
(In reply to comment #1)
> I suppose more selectively removing edges would be best.  Eventually this is
> done to cater for expansions of builtin calls to non-calls?  Then maybe
> those edges should be removed later, _after_ builtin expansion and
> find_many_sub_basic_blocks?

Wouldn't it be better to keep all the edges and fix the fallout from the RTL passes?

Do you remember any example where this currently fails?

I've verified with GCC 4.4 that dropping the edge removal code from cfgexpand.c together with a backport of the PR56982 patch fixes the actual problem.
Comment 3 rguenther@suse.de 2013-04-25 15:11:00 UTC
On Thu, 25 Apr 2013, krebbel at gcc dot gnu.org wrote:

> 
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57067
> 
> --- Comment #2 from Andreas Krebbel <krebbel at gcc dot gnu.org> 2013-04-25 14:46:09 UTC ---
> (In reply to comment #1)
> > I suppose more selectively removing edges would be best.  Eventually this is
> > done to cater for expansions of builtin calls to non-calls?  Then maybe
> > those edges should be removed later, _after_ builtin expansion and
> > find_many_sub_basic_blocks?
> 
> Wouldn't it be better to keep all the edges and fix the fallout from the RTL
> passes?

Yes, we should be able to prune them when expansion sees that is 
necessary.

> Do you remember any example where this currently fails?

Not sure.  Run bootstrap & testing?
Comment 4 gretay 2013-04-29 16:58:34 UTC
Created attachment 29974 [details]
testcase

The attached test case fails for arm-none-eabi on trunk, caused by r198096 (the fix for PR56982). It seems related to this PR because the control flow edge after testing the return value of malloc disappears and it is sensitive to the setjmp() call placement.

Compile with:
/work/apr-builds/r198096/install/bin/arm-none-eabi-gcc -O1 -mcpu=cortex-a15 pr57067.c -o bad.elf
The test case should print PASS, but it prints FAIL.
Comment 5 Richard Biener 2013-05-14 11:15:53 UTC
The RTL except.c:can_nonlocal_goto () function does not consider setjmp.
Does

Index: gcc/except.c
===================================================================
--- gcc/except.c        (revision 198867)
+++ gcc/except.c        (working copy)
@@ -1936,7 +1936,9 @@ insn_nothrow_p (const_rtx insn)
 bool
 can_nonlocal_goto (const_rtx insn)
 {
-  if (nonlocal_goto_handler_labels && CALL_P (insn))
+  if ((nonlocal_goto_handler_labels
+       || cfun->calls_stjmp)
+      && CALL_P (insn))
     {
       rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
       if (!note || INTVAL (XEXP (note, 0)) != INT_MIN)

fix it?

For retaining edges we have to teach find_many_sub_basic_blocks to treat
abnormal outgoing edges similar to EH outgoing edges - they have to be
re-directed from the block ending in the actual call (and made
EDGE_ABNORMAL_CALL which doesn't exist on the GIMPLE CFG).

Also

          if ((e->flags & EDGE_ABNORMAL)
              && !(e->flags & EDGE_SIBCALL))
            remove_edge (e);

will happily remove an EDGE_FALLTHRU|EDGE_ABNORMAL edge.
Comment 6 gretay 2013-05-17 14:03:54 UTC
I tried the proposed patch (after fixing a typo: calls_setjmp / calls_stjmp). It causes an ICE on the attached testcase (and some regressions):

$ /work/apr-builds/pr57067/install/bin/arm-none-eabi-gcc -O1 -mcpu=cortex-a15 pr57067.c -o pr57067.elf 
pr57067.c: In function 'main':
pr57067.c:18:7: warning: incompatible implicit declaration of built-in function 'malloc' [enabled by default]
   p = malloc (0x1000);
       ^
pr57067.c:22:7: warning: incompatible implicit declaration of built-in function 'printf' [enabled by default]
       printf ("\nFAIL\n");
       ^
pr57067.c:23:7: warning: incompatible implicit declaration of built-in function 'exit' [enabled by default]
       exit (1);
       ^
pr57067.c:32:3: warning: incompatible implicit declaration of built-in function 'printf' [enabled by default]
   printf ("\nPASS\n");
   ^
pr57067.c:34:1: error: in basic block 2:
 }
 ^
pr57067.c:34:1: error: flow control insn inside a basic block
(call_insn 8 7 9 2 (parallel [
            (set (reg:SI 0 r0)
                (call (mem:SI (symbol_ref:SI ("malloc") [flags 0x41] <function_decl 0x7f0cc7362900 malloc>) [0 __builtin_malloc S4 A32])
                    (const_int 0 [0])))
            (use (const_int 0 [0]))
            (clobber (reg:SI 14 lr))
        ]) pr57067.c:18 -1
     (expr_list:REG_EH_REGION (const_int 0 [0])
        (nil))
    (expr_list:REG_CFA_WINDOW_SAVE (use (reg:SI 0 r0))
        (nil)))
pr57067.c:34:1: internal compiler error: in rtl_verify_flow_info_1, at cfgrtl.c:2321
0x7cc383 _fatal_insn(char const*, rtx_def const*, char const*, int, char const*)
	/work/local-checkouts/gcc-fsf/gcc/rtl-error.c:109
0x52ed65 rtl_verify_flow_info_1
	/work/local-checkouts/gcc-fsf/gcc/cfgrtl.c:2321
0x52efb2 rtl_verify_flow_info
	/work/local-checkouts/gcc-fsf/gcc/cfgrtl.c:2345
0x51ef49 verify_flow_info()
	/work/local-checkouts/gcc-fsf/gcc/cfghooks.c:258
0xc02464 try_optimize_cfg
	/work/local-checkouts/gcc-fsf/gcc/cfgcleanup.c:2812
0xc02464 cleanup_cfg(int)
	/work/local-checkouts/gcc-fsf/gcc/cfgcleanup.c:2974
0x51c7dd gimple_expand_cfg
	/work/local-checkouts/gcc-fsf/gcc/cfgexpand.c:4781
Comment 7 Andrew Pinski 2022-12-15 18:02:20 UTC
*** Bug 108132 has been marked as a duplicate of this bug. ***
Comment 8 Andrew Pinski 2022-12-15 18:04:29 UTC
*** Bug 108117 has been marked as a duplicate of this bug. ***
Comment 9 Alexander Monakov 2022-12-15 18:33:30 UTC
*** Bug 108117 has been marked as a duplicate of this bug. ***
Comment 10 Andrew Pinski 2022-12-15 19:33:52 UTC
*** Bug 108132 has been marked as a duplicate of this bug. ***