[llvm-commits] [PATCH] Remove tail marker when changing an argument to an alloca.

Nick Lewycky nicholas at mxc.ca
Sun Jan 19 12:34:26 PST 2014


Rafael EspĂ­ndola wrote:
> Ping. I found this in a corner of my local git repo. A rebased patch
> is attached.

LGTM. Good catch!

Sidenote: I assume that doing this transform is more important than 
leaving the call as a tail call? I think so, but I'm not sure. 
Otherwise, we ought to block this transform when we see the argument 
being used by a tail call.

Nick

>
>
>> I guess I started going a bit off topic. The test I posted is not
>> recursive as written, but can be optimized to one, but that is not the
>> big issue. The issue are the cases where we don't have the full body
>> to analyze and we are left with what guarantees the IL gives us.
>>
>> I think that an important case is:
>>
>> declare void @f(i32*)
>> define void @g(i32* byval %a) {
>>    tail call void @f(i32* %a)
>>    ret void
>> }
>>
>> Given the current rules, the above code is valid and, on x86-64 with
>> the default calling convention, llc can produce:
>>
>>          leaq    8(%rsp), %rdi
>>          jmp     f
>>
>> Note that this is valid even if f can write to its argument. This is
>> so because g knows that it has its own copy of %a.
>>
>> In a different ABI, this might not be possible. If for example g is
>> the one responsible for poping the storage used for %a, then it has to
>> do a regular call to f. On on the normal x86 abi, g has to align the
>> stack, and llc produces
>>
>>          subl    $12, %esp
>>          leal    16(%esp), %eax
>>          movl    %eax, (%esp)
>>          calll   f
>>          addl    $12, %esp
>>          ret
>>
>>
>> Also note that without knowing that f will not write to its argument,
>> we cannot optimize g to
>>
>> define void @g(i32* %a) {
>>    tail call void @f(i32* %a)
>>    ret void
>> }
>> declare void @f(i32*)
>>
>> even if the ABI for g in both cases would match. In the new code g
>> doesn't have its own copy of %a.
>>
>> Since the byval %a is allocated (and freed) in g's caller in most
>> ABIs, I think this is a good argument for why we should not count
>> byval as an alloca for the purposes of allowing the tail marker or
>> not.
>>
>> In a way, what is happening in this optimization is that the function
>> being tail called goes (in most ABIs) from accessing an alloca in the
>> caller's caller to accessing an alloca in the caller, and therefore we
>> have to remove the tail marker.
>>
>> While I acknowledge that this maintenance is an annoyance, it is not
>> specific to this pass or even to byval. Consider a slightly modified
>> example:
>>
>> declare  void @f(i32*)
>> define void @g(i32* %a) {
>>    tail call void @f(i32* %a)
>>    ret void
>> }
>> define void @h(i32 %x) {
>>    %b = alloca i32
>>    store i32 %x, i32* %b
>>    call void @g(i32* %b)
>>    ret void
>> }
>>
>> There is no byval in it and the tail marker is correct since f gets an
>> alloca in h, not in g. When inlining, the inliner correctly drops it
>> and h becomes:
>>
>> define void @h(i32 %x) {
>>    %b = alloca i32
>>    store i32 %x, i32* %b
>>    call void @f(i32* %b)
>>    ret void
>> }
>>
>> In general, any pass that changes the arguments to a function has to
>> be careful. If it now passes an local alloca as an argument, it has to
>> drop the tail marker.
>>
>>> Ciao, Duncan.
>>>
>>
>> Cheers,
>> Rafael
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list