[llvm] r220811 - Transforms: reapply SVN r219899

Reid Kleckner rnk at google.com
Mon Nov 3 18:19:00 PST 2014


I reverted this in r221226. It shouldn't be hard to fix, but I didn't want
to leave it broken overnight.

Basically, if you have the situation a musttail calls b which musttail
calls c and they all use byval, then you can inline b into a but you must
preserve the musttail call to c.

musttail is a *guarantee* that tail call elimination will occur, not an
optimization hint that we can remove. The musttail annotation guarantees
two things:
1. No stack frame will be created for the musttail call, so unbounded stack
growth cannot occur.
2. Any inalloca or variadic arguments are forwarded in place without
modification.

In the byval case, it's property 1 we need to think about. Suppose c was
actually a and this was mutual tail recursion. Now without musttail, the
program may blow the stack.

You can still do your optimization safely and preserve musttail. You just
have to realize that passing a pointer to a byval argument doesn't actually
escape it. The pointer parameter that the callee receives is actually a new
pointer that points to a fresh copy of the data. If a byval parameter
passed to b escapes to c in any way, that was already a violation of
musttail semantics, so the original program was incorrect. The only safe
way to pass a local alloca or byval parameter to a musttail callee is if
you pass it as a byval argument, because that creates a copy.

It took a while to talk this out with Nick this afternoon.

On Mon, Nov 3, 2014 at 11:50 AM, Reid Kleckner <rnk at google.com> wrote:

> I think the changes for musttail were wrong here, but I need to think
> harder. Mechanically, inlining one level of musttail -> musttail should
> work, but it violates the langref guarantees. Maybe we need to finesse the
> reference.
>
> This is the kind of optimizer change that should really get pre-commit
> code review.
>
> On Fri, Oct 31, 2014 at 11:02 PM, Rafael EspĂ­ndola <
> rafael.espindola at gmail.com> wrote:
>
>> >
>> > -; Don't insert lifetime end markers here, the lifetime is trivially
>> over due
>> > -; the return.
>> > -; CHECK: define void @test_byval_a(
>> > -; CHECK: musttail call void @test_byval_c(
>> > -; CHECK-NEXT: ret void
>> > -
>> > -declare void @test_byval_c(i32* byval %p)
>> > -define internal void @test_byval_b(i32* byval %p) {
>> > -  musttail call void @test_byval_c(i32* byval %p)
>> > -  ret void
>> > -}
>> > -define void @test_byval_a(i32* byval %p) {
>> > -  musttail call void @test_byval_b(i32* byval %p)
>> > -  ret void
>> > -}
>> > -
>> > -; Don't insert a stack restore, we're about to return.
>> > -; CHECK: define void @test_dynalloca_a(
>> > -; CHECK: call i8* @llvm.stacksave(
>> > -; CHECK: alloca i8, i32 %n
>> > -; CHECK: musttail call void @test_dynalloca_c(
>> > -; CHECK-NEXT: ret void
>> > -
>> > -declare void @escape(i8* %buf)
>> > -declare void @test_dynalloca_c(i32* byval %p, i32 %n)
>> > -define internal void @test_dynalloca_b(i32* byval %p, i32 %n)
>> alwaysinline {
>> > -  %buf = alloca i8, i32 %n              ; dynamic alloca
>> > -  call void @escape(i8* %buf)           ; escape it
>> > -  musttail call void @test_dynalloca_c(i32* byval %p, i32 %n)
>> > -  ret void
>> > -}
>> > -define void @test_dynalloca_a(i32* byval %p, i32 %n) {
>> > -  musttail call void @test_dynalloca_b(i32* byval %p, i32 %n)
>> > -  ret void
>> > -}
>>
>> Why remove these tests? The musttail case in particular is interesting.
>>
>> Cheers,
>> Rafael
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20141103/7034de96/attachment.html>


More information about the llvm-commits mailing list