On 02/28/2018 03:43 AM, Richard Biener wrote:
[ More snipping ]

>> It's actually pretty easy to fix the CFG.  We  just need to recognize
>> that a "returns twice" function returns not to the call, but to the
>> point immediately after the call.  So if we have a call to a returns
>> twice function that ends a block with a single successor, when we wire
>> up the abnormal dispatcher, we target the single successor rather than
>> the block containing the returns-twice call.
> Hmm, I think you need to check whether the successor has a single
> predecessor, not whether we have a single successor (we always have
> that unless setjmp also throws).  If you fix that you keep the CFG
> "incorrect" if there are multiple predecessors so I think in addition
> to properly creating the edges you have to work on the BB building
> part to ensure that there's a single-predecessor block after
> returns-twice function calls.  Note that currently we force returns-twice
> to be the first (and only) stmt of a block -- your fix would relax this,
> returns-twice no longer needs to start a new BB.
So I found the code which makes the setjmp start a new block. But I
haven't found the code which makes setjmp end a block.  I'm going to
have to throw things into the debugger  to find the latter.

We ought to remove the code that makes the setjmp start a new block.
That's just unnecessary.   setjmp certainly needs to end the block though.

> -               handle_abnormal_edges (dispatcher_bbs, bb, bb_to_omp_idx,
> -                                      &ab_edge_call, false);
> +               {
> +                 bool target_after_setjmp = false;
> +
> +                 /* If the returns twice statement looks like a setjmp
> +                    call at the end of a block with a single successor
> +                    then we want the edge from the dispatcher to target
> +                    that single successor.  That more accurately reflects
> +                    actual control flow.  The more accurate CFG also
> +                    results in fewer false positive warnings.  */
> +                 if (gsi_stmt (gsi_last_nondebug_bb (bb)) == call_stmt
> +                     && gimple_call_fndecl (call_stmt)
> +                     && setjmp_call_p (gimple_call_fndecl (call_stmt))
> +                     && single_succ_p (bb))
> +                   target_after_setjmp = true;
> +                 handle_abnormal_edges (dispatcher_bbs, bb, bb_to_omp_idx,
> +                                        &ab_edge_call, false,
> +                                        target_after_setjmp);
> +               }
> I don't exactly get the hops you jump through here -- I think it's
> better to split the returns-twice (always last stmt of a block after
> the fixing) and the setjmp-receiver (always first stmt of a block) cases.
> So, remove the handling of returns-twice from the above case and
> handle returns-twice via
Just wanted to verify the setjmp was the last statement in the block and
the block passed control to a single successor.  If the setjmp is not
the last statement, then having the longjmp pass control to the
successor block potentially skips over statements between the setjmp and
the end of the block.  That obviously would be bad.

As I mentioned before the single_succ_p test was just my paranoia.

Note that GSI can point to a setjmp receiver at this point.  We don't
want to treat that like a setjmp.

>   gimple *last = last_stmt (bb);
>   if (last && ...)
> also handle all returns-twice calls this way, not only setjmp_call_p.
Note that setjmp_call_p returns true for any returns-twice function.  So
we are handling those.

So I think the open issue with this patch is removal of making the
setjmp start a block and verification that we always have it end the
block.  The latter should allow some simplifications to the code I added
in make_edges and provide a level of consistency that is desirable.


Reply via email to