[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