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

Chris Lattner sabre at nondot.org
Sat Jun 7 14:59:03 PDT 2008

On Jun 2, 2008, at 1:03 PM, Matthijs Kooijman wrote:
>> Can you give some background about what kinds of things you're  
>> thinking
>> about for this?
> For example, when I have a function returning {i32, i32} and I want  
> to add
> another i32 to that. If this was a function that simply returns two  
> i32
> values, any caller will only use extractvalue on the result to get the
> seperate values (since the struct as a whole has no meaning). In  
> this case, I
> can make the function return {i32, i32, i32}, add an extra  
> extractvalue in
> each caller and be done.

This can't really work in either case.  Once created, there is no way  
to change the type of a Value*.  Changing the result of a call from  
{i32, i32} to {i32, i32, i32} is just as impossible as changing it  
from {i32,i32} to i32.  You have to create a new callinst in either  

> Then after adding an argument we get something like:
> 	%tmp = @foo () ; {i32, i32, i32}
> 	%im  = extractvalue {i32, i32, i32} %tmp, 0
> 	%re  = extractvalue {i32, i32, i32} %tmp, 1
> 	%c0  = insertvalue {i32, i32} undef, %im, 0
> 	%c1  = insertvalue {i32, i32} %c0, %re, 1
> 	@bar ( {i32, i32 } %c1)
> Which isn't pretty code and needs quite some lines of code to  
> generate. In
> this case, we're better off creating a new struct, so a function  
> that returns
> { {i32, i32}, i32}, which means we get something like:
> 	%tmp = @foo () ; { {i32, i32}, i32}
> 	%complex  = extractvalue { {i32, i32}, i32} %tmp, 0
> 	@bar ( {i32, i32 } %complex)

Why would you ever want to pass multiple values as an aggregate to a  
call?  The only thing I can think of is for ABI reasons.  If you can  
do an ABI changing transformation (such as you propose) the first  
thing I'd do is  expand the aggregate to pass as a series of scalars.   
Having argpromotion do this would be very natural.

> However, the only way to really do this is to make all functions  
> return a
> struct, possibly of only a single element. This also requires a  
> guarantee that
> nothing special happens to the return value as a whole, but only the
> individual elements are accessed through extractvalue.

After MRVs are working really well, I'd like to consider removing the  
void type:

This would make it so that calls always return a value, and 'ret'  
always takes a value.  This would be a nice simplification to the IR I  

>> Ok. And as I mentioned before, we can add buildagg (maybe with a
>> different name ;-))
> Yeah, builddag is an ugly name :-p
>> later if we find it would be of significant use or convenience.
> By then, we will probably have though our backend to read  
> insertvalue chains,
> so it won't be really necessary anymore :-) But let's keep it in mind.

If you're using IRBuilder, why not just add a new CreateBuildMRV  
method that inserts the sequence of insertvalue's for you?

> Reconsidering, the sretpromotion pass might not be the best place  
> for this. It
> currently promotes the special sret pointer arguments to multiple  
> return
> values (I should probably modify it to use a struct return and  
> insertvalue
> instead?). Since an sret function will, by definition, have a void  
> return
> type, the new return values will never have to be merged.
> In that light, I will be probably building an internal (i.e., to our  
> company)
> pass that flattens struct return values.

stretpromotion was really just for testing.  I expect that when MRVs  
work predictably 100% of the time (even if not something the ABI  
supports, for example) that the functionality will be pulled into the  
argpromotion pass.

>> Sounds interesting. One thing to keep in mind here is the tradeoff
>> between teaching existing optimizations special things about
>> aggregate values, versus having a separate pass that just promotes
>> first-class aggregate arguments to a bunch of individual
>> non-aggregate arguments.

> Promoting struct arguments to multiple seperate values is exactly  
> what I said
> that needed happening (but since I'm currently using byval struct*  
> arguments,
> which are already handled by argpromotion) I'm probably not going to  
> change
> this.

In general, I think that all the optimizers should try to rip apart  
MRVs when possible and focus on optimizing scalars.  This is not  
generally possible for return values, because there is no other way to  
return multiple values, but it is possible for arguments to calls.


More information about the llvm-dev mailing list