This is an archive of the discontinued LLVM Phabricator instance.

Avoid tail recursion elimination across calls with operand bundles
ClosedPublic

Authored by sanjoy on Nov 2 2016, 7:37 PM.

Details

Summary

In some specific scenarios with well understood operand bundle types
(like "deopt") it may be possible to go ahead and convert recursion to
iteration, but TailRecursionElimination does not have that logic today
so avoid doing the right thing for now.

I need some input on whether "funclet" operand bundles should also
block tail recursion elimination. If not, I'll allow TRE across calls
with "funclet" operand bundles and add a test case.

Diff Detail

Repository
rL LLVM

Event Timeline

sanjoy updated this revision to Diff 76811.Nov 2 2016, 7:37 PM
sanjoy retitled this revision from to Avoid tail recursion elimination across calls with operand bundles.
sanjoy updated this object.
sanjoy added reviewers: rnk, majnemer, nlewycky, ahatanak.
sanjoy added a subscriber: llvm-commits.
majnemer edited edge metadata.Nov 2 2016, 7:50 PM

I don't think funclets need to worry about this.

sanjoy updated this revision to Diff 76815.Nov 2 2016, 10:14 PM
sanjoy edited edge metadata.

Address review: don't block TRE on funclet operand bundles.

I don't think funclets need to worry about this.

I would have thought they did. If an exception is caught (so we enter the funclet) and then there's a recursive call to the main method (which has the funclet bundle), I think we want a new frame for the main method; if we rewrite that recursive call as a jump, but then an exception is raised in the recursive invocation, is the unwinder going to do the right thing? The IP will be telling it that we're in the main function, not the funclet. If that catch handler enters a try region before it makes the recursive call, then the main function and funclet would have different handlers, so we should be able to see empirically whether the right thing happens.

I don't think funclets need to worry about this.

I would have thought they did. If an exception is caught (so we enter the funclet) and then there's a recursive call to the main method (which has the funclet bundle), I think we want a new frame for the main method; if we rewrite that recursive call as a jump, but then an exception is raised in the recursive invocation, is the unwinder going to do the right thing? The IP will be telling it that we're in the main function, not the funclet. If that catch handler enters a try region before it makes the recursive call, then the main function and funclet would have different handlers, so we should be able to see empirically whether the right thing happens.

This makes sense. OK, so we should treat funclet bundles like deopt bundles here.

rnk added inline comments.Nov 7 2016, 1:06 PM
test/Transforms/TailCallElim/operand-bundles.ll
53–54 ↗(On Diff #76815)

It's kind of meaningless to attempt to return from a funclet without first returning to the parent function. Bad things would happen. I think we should go with the previous patch without the special casing for funclet.

This revision was automatically updated to reflect the committed changes.
efriedma added inline comments.
llvm/trunk/lib/Transforms/Scalar/TailRecursionElimination.cpp
259

If CI->hasOperandBundles() is true, IsNoTail Is true, so this code is never reached. Therefore, this is equivalent to "SafeToTail = false;".