[LLVMdev] Plans considering first class structs and multiple return values

Matthijs Kooijman matthijs at stdin.nl
Mon Jun 2 08:45:46 PDT 2008


Hi Dan,

> Yes, the intention is that getresult will be removed once first-class
> aggregates are a ready replacement. This won't leave LLVM missing the
> concept of returning multiple values; a struct can be thought of as
> a container for multiple values.
I'm not saying we don't have some way of modeling multiple return values, I'm
sayin the explicit concept disappears. We can use a struct return type to
create a function that effectively returns multiple values, but that is still
a function returning a single value: A struct. In particular, it will be
impossible to distinguish between a function returning a single struct and a
function returning multiple values.

I'm not sure this is a big problem, but it makes adding a return value to a
function harder. I'm not sure this is really a problem though. Would adding a
function attribute returns_multiple or something like that be useful?
returns_multiple would mean to interpret the returned struct as multiple
return values and in particular forbids to use the resulting value in any way
but as an operand to extractvalue. The main goal of this is to make
adding/removing an argument easier, because you only need to modify the
extractvalues. On the other hand, this limitation sounds a lot like the
current getresult approach and might not be all to useful.

> > Additionally, the current form of the ret instruction is still  
> > useful, for
> > making multiple return values readable. In particular, writing
> > 	ret i32 1, i32 2
> > is a lot more readable than the (functionally identical) three line  
> > return
> > statement above. However, to make the first class aggregrates even  
> > more
> > usable, it might be better to remove the multi operand return  
> > instruction and
> > add support for literal aggregrates. Currently, I think these are only
> > supported as global constants. It would be useful if the following  
> > was valid:
> > 	ret { i32, i32 } { i32 1, i32 2 }
> 
> I think this form should be valid once first-class struct support is  more
> complete. If it's not accepted today it may be a conflict with the  current
> multiple-return-value syntax, or it may be a bug.
It doesn't seem to be accepted by llvm-as. I think you might be able to build
this in memory, since a ConstantStruct is just a Value*.

> > Even more, one would also like to be able to build non constant  structs
> > in a similar manner. i.e., writing
> > 	ret { i32, i32 } { i32 %a, i32 %b }
> > would be a lot more useful than the current
> > 	ret i32 %a, i32 %b
> > form, since in the first form the ret instruction still has a single
> > operand that is easy to work with.
> 
> The current design will have it looking like this:
> 
>         %t0 = insertvalue { i32, i32 } undef, i32 %a, 0
>         %t1 = insertvalue { i32, i32 } %t0,   i32 %b, 1
>         ret { i32, i32 } %t1
> 
> once first-class structs take over from the current multiple-return- value
> support. It's significantly more syntax, but it's a significantly  simpler
> IR schema.
On the other hand, anyone looking to support multiple return values but other
(potentially complicated) uses for first class structs would have a harder
time trying to find out what these nested insertvalues actually do. The main
difference here is that using insertvalue you can do something like:

	%a = phi { i32, i32 } [ %a.0, %foo ], [ %a.1, %bar ]
	%b = insertvalue { i32, i32 } %a, i32 0, 0

which you can't do directly using a literal { } or buildagg kind of
instruction. OTOH, you can still do things like this using nested structs
then, so having a builddag will probably not improve things much.

Anyhow, so much for my blabbering of incoherent thoughts. I think that simply
using insertvalue for now and not having an explicit multiple return function
attribute should work fine.

Whenever I want to add a function argument, I will just let it return a struct
of two elements (current value and the new value). 

I'll also add a feature to the sretpromotion pass that flattens out nested
struct return types as much as possible, without having to reconstruct structs
at the caller end (ie, preserver struct types that are used in any way other
than extractvalue in any caller and flatten out all other elements). Would
this be the right place for that? Or should sretpromotion really only take
care of promotion sret pointer arguments to multiple return values, and have
second pass for flattening them out? A problem of that seems to be that it is
hard for sretpromotion to simply add return values, since it doesn't know
whether to add to the existing struct return type (if any) or create a new
struct return type. I guess integrating these two passes makes the most sense,
then.

I guess the argumentpromotion pass also needs to be adapted to promote first
class struct arguments (probably handle them identical to how byval
pointer-to-struct are handled now), but I don't currently have need of that.

Lastly, I'll modify IPConstProp and DeadArgElim to properly handle multiple
return values and do constprop/removal on each of them individually, instead
of only working when all of them are constant/dead as is done currently.

I'm also thinking of adding a transformation that makes return values dead if
they only return an unmodified argument, this can probably go into
DeadArgElim.

Gr.

Matthijs
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20080602/963e1959/attachment.sig>


More information about the llvm-dev mailing list