[llvm-commits] [llvm] r38506 - in /llvm/trunk: lib/VMCore/Verifier.cpp test/Verifier/byval-1.ll test/Verifier/byval-2.ll test/Verifier/byval-3.ll test/Verifier/byval-4.ll
espindola at google.com
Mon Jul 16 08:05:03 CDT 2007
On 11/07/07, Duncan Sands <baldrick at free.fr> wrote:
> Hi Rafael,
> > + Assert(!Attrs->paramHasAttr(0, ParamAttr::ByVal),
> > + "Attribute ByVal should not apply to functions!");
> why not?
What does it means to a function to have such an attribute?
> > + "Attribute ByVal should only apply to pointer to structs!", &F);
> Why? Why are arrays not allowed?
They can be allowed latter. For now it is only going to be used by
structures, so I have arbitrary limited it.
> Here's my take on this whole area. Perhaps I'm just confused :)
> On some targets the ABI specifies that C functions that take a by-copy
> struct argument that is sufficiently small should pass it in registers,
> or maybe on the stack. Likewise, on some targets the ABI specifies
> that a function that returns a struct should return it in certain
> registers or on the stack (StructReturn attribute). On other targets,
> by-copy struct arguments are passed by passing pointer to a copy, or
> by passing a pointer to the original struct with a copy being made in
> the callee, I don't know which. Likewise, on targets with nothing
> specified for StructReturn in the ABI, the value is returned by writing
> through a pointer into a struct supplied by the caller.
> [ByVal and StructReturn are closely related, so maybe we should change
> the names: ByVal -> CopyIn, StructReturn -> CopyOut].
> Note that the representation in the IR is "by reference": a pointer to
> the struct is passed:
> declare void @h(%struct.foo* byval %num)
> I think ByVal should mean: if the struct is compatible with the ABI's way
> of passing structs by-copy, then pass using this method, otherwise pass by
> reference. At the level of the target independent IR, it would be *undefined*
> as to whether a ByVal parameter is in fact passed by reference or by copy.
> My understanding is that this is exactly how StructReturn works: if, before
> calling the function, you write to the struct that is passed in as the
> StructReturn parameter, and then you try reading from the struct inside the
> function you may (returned by reference) or may not (returned by copy)
> see the values you previously wrote.
> Thus on some targets ByVal parameters would always be passed by reference.
> On others, small structs would be passed by copy, large ones by reference.
> On others, all structs would be passed by copy.
I think that the C standard defines that structures are always passed
by value. On some architectures that is done by coping into registers.
In others it is done by putting a copy on the stack.
> Disadvantages of this scheme:
> (1) in order to implement C semantics of passing a struct by copy [which
> requires that a copy always be made, regardless of the size of the struct],
> it would be necessary to, for example, pass the parameter ByVal, immediately
> make a copy of the struct inside the function, and use the copy everywhere
> inside the function. This would always give the correct semantics while being
> compatible with ABI requirements (thanks to the ByVal). The downside is that
> in cases when the ByVal parameter is in fact passed by copy, an unnecessary copy
> is being made. Hopefully the codegen optimizers can be taught to remove the
> pointless copy in this case. Thus the disadvantage is: additional work may be
> needed on the codegen optimizers to get this to work optimally.
This is not how the x86_64 ABI works. A copy is generated by the
caller, and a pointer is passed *implicitly*. It is computed by
"stack_pointer + know_offset". We would have to change the abi to
support passing such implicit pointers.
One option that would make the copy creation explicit, is also passing
the stack pointer as an explicit argument. Doing that a call would be:
a = alloca (struct_that_describes f's stack frame)
memcpy(a + offset, second_arg_on_the_stack)
f(stack_pointer, reg_arg1, reg_arg2)
But again, this is a lot of work.
> Advantages of this scheme:
> (1) it doesn't *require* any changes to the target independent optimizers, eg
> to alias analysis, the inliner and who knows what else: they can just ignore
> the ByVal attribute, which amounts to considering the struct to have been
> passed by reference (which is how it is represented in the IR). Now, you
> might want to enhance the optimizers so they can exploit the undefinedness
> of whether the struct is passed by reference or by copy, but this is optional
> can be implemented incrementally. It seems to me that this is much much better
> than having to say in various places: ok, this thing looks like a pointer but
> it's not really a pointer! That way lies madness. If I dare say so, that way
> lies... gcc!
I know, that is one of the reasons I prefer the "explicit frame"
approach. But I think that implementing the struct passing on the
backend is a small hack that is much easier to implement and gives us
After this is done I promise to try to get some time to test some
approach that moves more of the ABI to the FE.
> (2) targets that don't have a special way of passing structs by-copy don't
> have to do anything.
All of them need to have it in order to implement the C semantics....
> (3) if a function is known not to write to a struct parameter, then that
> parameter could be marked ByVal, meaning that it will (hopefully) get passed
> by the most efficient method for the target (in registers). I say hopefully,
> because I suppose some ABIs may specify that by-copy structs of any size must
> be passed on the stack, which would mean that promoting a parameter to ByVal
> could result in a slowdown rather than a speedup.
> (4) it conceptually unifies the treatment of ByVal and StructReturn parameters.
Which might not be generic enough. I can imagine a ABI were two
passing structures to a function is handled in a different way then
Rafael Avila de Espindola
Google Ireland Ltd.
Registered in Dublin, Ireland
Registration Number: 368047
More information about the llvm-commits