Dan Gohman wrote:
Dan Gohman wrote:
Having a dom tree with multiple roots, where blocks may
not be dominated by the entry block is pretty scary.
The dom tree code already supports it, because it already happens to
postdominator trees. There are some clients that will need to be
changed, but I think it's pretty minimal.
Please reconsider prohibiting the entry block from having an
"unwinds to". Beyond dom tree clients, there's also the widely
useful idiom of allocas in the entry block that this would
break.
*shrug* I'm not married to the idea. It just hasn't hit me that it's necessary.
Put another way, if I actually encounter passes doing things like inserting alloca's in the first block and this is harder to fix than disallowing 'unwinds to' on the entry BB would be, I'll disallow 'unwinds to' on the entry BB.
I just hunted through the archives and confirmed my memory
of seeing this concern raised but never addressed. If I
missed a reason why entry needs to have "unwinds to", please
point it out again.
Also, in that case, please also explain what will happen here:
entry: unwinds to %handler
call void @foo()
br label %exit
handler:
br label %exit
exit:
ret void
Where does %exit stand in dom tree land?
Yup, it's exactly where you think:
> > >
entry handler exit
Having
"predecessor" mean different things in the context of the CFG
versus the context of the dom tree is very scary.
Say we have this CFG:
A
>
B X
>
C
and B "unwinds to" X. Instead of having X be a successor to B,
how about making X a successor to A (and A a predecessor of X)?
A would need a special new kind of terminator instruction which
looks something like a conditional branch with B and X as
destinations, though it would always branch to B when executed.
Sure. We could even call it "invoke".
The problem is that you end up with a CFG that looks like this:
A
/ \
B X
which doesn't represent what could happen at all. Any pass should be
able to reasonably look at that CFG and say that instructions from B and
X are exclusive. The reality is that instructions in X will occur after
some of the instructions in B are executed.
I maintain that it does represent what happens, with a little
abstraction :-). Control will flow to B in the case that B doesn't
end up interrupted by an exception, and to X in the case that
it does. It's not a coincidence that this is the CFG that results
from reverse-engineering a CFG from the dom tree that you're
proposing to use.
That drops the fact that some instructions from B may execute before X.
In practise, what users want out of the domtree is to know the nearest block they can put an instruction that is guaranteed to be executed before entering this/these other blocks. That's how I justify my change to the domtree -- it doesn't really apply to the CFG though.
Unfortunately, after thinking this through a little more I
found a problem with the magic side-effects intrinsic. As a
call it can easily appear to have lots of side-effects, but it
won't easily be able to appear to access alloca or malloc
memory in the function that doesn't escape.
There were some other minor issues with my proposal which I
believe can be reasonably fixed, but this issue with the
side-effects intrinsic is a fundamental problem :-/.
Right. Calling an intrinsic that might have arbitrary side-effects (modify arbitrary memory) would also break mem2reg in all cases.
The simpler method of avoiding an intrinsic and just having a "br label %foo, onunwind %unwind" instruction is still up for grabs, but I still think it's bad for reasons up 2 frames in this thread.
Nick