Hi,

On Wed, 28 Feb 2018, Jeff Law wrote:

> The single successor test was strictly my paranoia WRT abnormal/EH edges.
> 
> I don't immediately see why the CFG would be incorrect if the successor
> of the setjmp block has multiple preds.

Actually, without further conditions I don't see how it would be safe for 
the successor to have multiple preds.  We might have this situation:

bb1: ret = setjmp
bb2: x0 = phi <x1 (bb1), foo(bbX)>

As you noted the second "return" from setjmp is precisely after the setjmp 
call itself, i.e. on the edge bb1->bb2.  Simply regarding it as landing at 
the start of bb2 it becomes unclear from which edge bb2 was entered and 
hence the runtime model of PHI nodes breaks down.

So, the mental model would be that a hypothetical setjmp_receiver (which 
isn't hypothetical for SJLJ) would have to be inserted on the bb1->bb2 
edge.  From then normal edge insertion routines take over: because the 
bb1-setjmp block only has a single successor (I know it currently doesn't, 
bear with me) it's actually inserted at the end of bb1 (so that edge 
doesn't need splitting), which is indeed what you want.  Except that to 
have a target for the abnormal edges the setjmp_receiver needs to start 
its own basic block, so you'd need to create a new edge, which then 
implicitely creates the situation that the successor of the setjmp block 
only has a single predecessor (until you add the abnormal edges to the 
receiver of course):

bb1 : setjmp; /* fallthrough */
bb1': ret = setjmp_receiver /* fallthrough */
bg2 : x0 = phi<x1(bb1'), foo(bbX)>

While this models what actually happens with setjmp quite fine it poses 
the problem that nothing must be moved between setjmp and setjmp_receiver, 
so it seems indeed better to leave them as just one instruction.  But the 
edge modelling needs to ensure that the above runtime model is followed, 
and so needs to ensure that the actual target of the abnormal edge doesn't 
have multiple predecessors (before adding the abnormal edge that is), so 
the edge must be split I think.

Actually I wonder if it weren't better to regard return-twice functions 
like COND_EXPR, and always create two outgoing edges of such blocks, one 
the normal first-return, the other the (abnormal) second-return.  The 
target block of that second-return would then also be the target of all 
function calls potentially calling longjmp, and so on.  That target block 
would then only have abnormal predecessors, and your problem would have 
also gone away.  In addition a setjmp call would then be normally 
eliminable by unreachable-code analysis (and the second-return target 
block as well eventually)  This would also naturally deal with the 
problem, that while the real second return is after the setjmp call it 
happens before the setting of the return value.


Ciao,
Michael.

Reply via email to