[PATCH] Teach DeadArgElimination not to eliminate return values of functions with 'returned' arguments

Dan Gohman dan433584 at gmail.com
Tue Jun 25 08:01:24 PDT 2013


Even with smarter heuristics, you're still breaking mid-level optimizations
in some cases. I think the fact that you're trying to represent the return
value at the IR at all is awkward. It'd be more natural to have the
function return void, and treat it specially in codegen. I propose the
following alternative:

Keep the 'returned' argument attribute, and add a 'returnsarg' function
attribute. Then, the semantics of 'returned' are that it is ignored unless
it is the first 'returned' argument in a function that is marked
'returnsarg' and has a void return type. Then at the codegen level, the
function is translated as if it had the return type of its first 'returned'
argument. As an optimization, codegen can rewrite uses after the call to
use the return value.

That way, DeadArgElimination and all the other mid-level optimizations can
run at full strength, and you can still get your optimization. What do you
think?

Dan

On Mon, Jun 24, 2013 at 11:23 AM, Stephen Lin <swlin at post.harvard.edu>wrote:

> > No, I don't have any alternatives, other than interprocedural
> coordination
> > of code generation. Do you have any alternatives?
>
> The only thing I can think of is a few more heuristics to avoid
> keeping the return value in cases where it is "obviously" not useful
> to the caller.
>
> >
> >>
> >> Also, in theory, some mid level optimization could be done, even if it
> >> is not done now. A 'returned' argument implies the argument and return
> >> value are aliases of each other in all code dominated by the function
> >> call, so IR optimizers would be free to replace one with the other. As
> >> mentioned in other e-mails, it is, the problem is that, in the general
> >> case, it is difficult to know which alternative to pick; however, an
> >> IR pass could, at a minimum, canonicalize this:
> >>
> >>   %struct.A = type { i32 }
> >>
> >>   declare %struct.A* @a_ctor(%struct.A* returned)
> >>   declare void @bar(%struct.A*)
> >>
> >>   define %struct.A* @foo() {
> >>   entry:
> >>     %a = alloca %struct.A, align 4
> >>     %b = call %struct.A* @a_ctor(%struct.A* %a)
> >>     call void @bar(%struct.A* %a)
> >>     ret %struct.A* %b
> >>   }
> >
> >
> > The canonical form would be:
> >
> > %struct.A = type { i32 }
> >
> >   declare %struct.A* @a_ctor(%struct.A* returned)
> >   declare void @bar(%struct.A*)
> >
> >   define %struct.A* @foo() {
> >   entry:
> >     %a = alloca %struct.A, align 4
> >     %b = call %struct.A* @a_ctor(%struct.A* %a)
> >     call void @bar(%struct.A* %a)
> >     ret %struct.A* %a
> >   }
> >
> > In other words, it's advantageous to see the actual value, and there's no
> > mid-level optimizer benefit to seeing the return value.
>
> I understand your point; I think canonicalization was not quite what I
> meant. It understand that it would be useful, from a mid-level
> optimizer perspective, to canonicalize usage to the argument rather
> than the return value, since the aliasing information would be just
> noise for an SSA representation with infinite virtual registers.
>
> But definitely, the information that the physical register containing
> the return value and argument are aliases of each other should not be
> lost, and code generation should not be forced to choose one or the
> other before register allocation. So even if there is a
> canonicalization to use the argument for the mid-level optimizers,
> there needs to be some way to recover the semantics of ""select i1
> undef, %struct.A* %argument, %struct.A* %return_value"" somewhere and
> to use it to optimizer register allocation, either as a late IR pass
> or during SelectionDAG lowering.
>
> Stephen
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130625/ab3bfcb4/attachment.html>


More information about the llvm-commits mailing list