[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

Duncan Sands baldrick at free.fr
Wed Jul 11 02:43:53 PDT 2007


Hi Rafael,

> +    Assert(!Attrs->paramHasAttr(0, ParamAttr::ByVal),
> +           "Attribute ByVal should not apply to functions!");

why not?

> +                "Attribute ByVal should only apply to pointer to structs!", &F);

Why?  Why are arrays not allowed?

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.

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.

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!

(2) targets that don't have a special way of passing structs by-copy don't
have to do anything.

(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.

Ciao,

Duncan.



More information about the llvm-commits mailing list