Hare uses return-by-value generously, and this is somewhat inefficient on qbe, since it requires provisioning a new stack slot and copying data to its final location in the caller.
type coords = struct { x: int, y: int };
// ...
let pos: coords = mkcoords();
It would be useful if we could express that "pos" is the final destination for the result of the mkcoords call, and have a pointer to this location passed via %rdi directly rather than using a temporary slot.
Hi, Just to propose an alternative using what is already implemented because I think I had this same problem. I implemented a (kind of toy) system level QBE based programming language and I wanted to minimize copies when possible, and also had the return by value semantic. So for your snippet I would emit something like that:
%v1 =l alloc8 16 // allocate the stack slot for your pos and get %v1 to points to to it call $mkcoords(l %v1) // because source mkcoords return a record, SSA mkcoords takes an %out parameter and return nothing %v2_pos =l copy %v1 // copy the pointer from v1 to v2_pos, which map to the source pos (kind of pointless but easier to emit for me)
And then mkcoords would look something like:
function $mkcoords(l %v1_out) { // no return, single out parameter @start %v2_x_p =l add %v1_out, 0 // get offset to x ... // store something into %v2_x_p to write the x member %v3_y_p =l add %v1_out, 8 // get offset to y ... // store something into %v2_y_p to write the y member ret }
In my language, the user access this "no copy" feature by using a special "out" variable that is always the return slot, which makes it easy to emit for me (my compiler is pretty basic). However, I think some simple static analysis of the return(s) statement(s) should be enough to detect the use of some other variable as the return variable. Basically, when you can ensure that only one variable is used as the return value, you make it special and bind it to the return slot.