Description
This issue is split from #287.
Now that we have result location semantics, the following code does not introduce an intermediate value with a copy:
const Point = struct {
x: i32,
y: i32,
};
fn foo() Point {
return bar();
}
fn bar() Point {
return Point{
.x = 1,
.y = 2,
};
}
test "result location" {
var point = foo();
}
Previously, the code return bar()
would introduce an extra copy, so the body of the function foo
would needlessly copy the point before returning it. This copying would happen at every expression, recursively when the type is an aggregate type (such as struct
). Now that the result location mechanism is merged into master, you can see that the foo
function does not introduce an extra copy:
define internal fastcc void @foo(%Point* nonnull sret) unnamed_addr #2 !dbg !35 {
Entry:
call fastcc void @bar(%Point* sret %0), !dbg !44
ret void, !dbg !46
}
However, if you capture the result in a variable and then return the variable, there is an intermediate value - the result
variable - which is copied at the return
statement:
fn foo() Point {
const result = bar();
return result;
}
Now there is a copy, because the Result Location of bar()
is the result
local variable, rather than the return result location:
define internal fastcc void @foo(%Point* nonnull sret) unnamed_addr #2 !dbg !35 {
Entry:
%result = alloca %Point, align 4
call fastcc void @bar(%Point* sret %result), !dbg !47
call void @llvm.dbg.declare(metadata %Point* %result, metadata !45, metadata !DIExpression()), !dbg !48
%1 = bitcast %Point* %result to i8*, !dbg !49
%2 = bitcast %Point* %0 to i8*, !dbg !49
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %1, i64 8, i1 false), !dbg !49
ret void, !dbg !50
}
This issue is to make it so that there is a way to refer to the result location, and even call methods on it, before returning it, all without introducing an intermediate value.
For the issue about getting rid of intermediate values when optionals and error unions are involved, see #2761.