Skip to content

Commit c933a7c

Browse files
nohenryandrewrk
authored andcommitted
llvm: remove extra copy of wrapped payloads
1 parent 5c3393d commit c933a7c

File tree

1 file changed

+69
-12
lines changed

1 file changed

+69
-12
lines changed

src/codegen/llvm.zig

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4904,9 +4904,9 @@ pub const FuncGen = struct {
49044904
.set_err_return_trace => try self.airSetErrReturnTrace(inst),
49054905
.save_err_return_trace_index => try self.airSaveErrReturnTraceIndex(inst),
49064906

4907-
.wrap_optional => try self.airWrapOptional(inst),
4908-
.wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
4909-
.wrap_errunion_err => try self.airWrapErrUnionErr(inst),
4907+
.wrap_optional => try self.airWrapOptional(body[i..]),
4908+
.wrap_errunion_payload => try self.airWrapErrUnionPayload(body[i..]),
4909+
.wrap_errunion_err => try self.airWrapErrUnionErr(body[i..]),
49104910

49114911
.wasm_memory_size => try self.airWasmMemorySize(inst),
49124912
.wasm_memory_grow => try self.airWasmMemoryGrow(inst),
@@ -5299,6 +5299,16 @@ pub const FuncGen = struct {
52995299
if (self.ret_ptr != .none) {
53005300
const operand = try self.resolveInst(un_op);
53015301
const ptr_ty = try mod.singleMutPtrType(ret_ty);
5302+
5303+
const unwrapped_operand = operand.unwrap();
5304+
const unwrapped_ret = self.ret_ptr.unwrap();
5305+
5306+
// Return value was stored previously
5307+
if (unwrapped_operand == .instruction and unwrapped_ret == .instruction and unwrapped_operand.instruction == unwrapped_ret.instruction) {
5308+
_ = try self.wip.retVoid();
5309+
return .none;
5310+
}
5311+
53025312
try self.store(self.ret_ptr, ptr_ty, operand, .none);
53035313
_ = try self.wip.retVoid();
53045314
return .none;
@@ -7179,9 +7189,33 @@ pub const FuncGen = struct {
71797189
return self.load(field_ptr, field_ptr_ty);
71807190
}
71817191

7182-
fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7192+
/// As an optimization, we want to avoid unnecessary copies of
7193+
/// error union/optional types when returning from a function.
7194+
/// Here, we scan forward in the current block, looking to see
7195+
/// if the next instruction is a return (ignoring debug instructions).
7196+
///
7197+
/// The first instruction of `body_tail` is a wrap instruction.
7198+
fn isNextRet(
7199+
self: *FuncGen,
7200+
body_tail: []const Air.Inst.Index,
7201+
) bool {
7202+
const air_tags = self.air.instructions.items(.tag);
7203+
for (body_tail[1..]) |body_inst| {
7204+
switch (air_tags[body_inst]) {
7205+
.ret => return true,
7206+
.dbg_block_begin, .dbg_stmt => continue,
7207+
else => return false,
7208+
}
7209+
}
7210+
// The only way to get here is to hit the end of a loop instruction
7211+
// (implicit repeat).
7212+
return false;
7213+
}
7214+
7215+
fn airWrapOptional(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
71837216
const o = self.dg.object;
71847217
const mod = o.module;
7218+
const inst = body_tail[0];
71857219
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
71867220
const payload_ty = self.typeOf(ty_op.operand);
71877221
const non_null_bit = try o.builder.intValue(.i8, 1);
@@ -7192,8 +7226,15 @@ pub const FuncGen = struct {
71927226
if (optional_ty.optionalReprIsPayload(mod)) return operand;
71937227
const llvm_optional_ty = try o.lowerType(optional_ty);
71947228
if (isByRef(optional_ty, mod)) {
7195-
const alignment = optional_ty.abiAlignment(mod).toLlvm();
7196-
const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment);
7229+
const directReturn = self.isNextRet(body_tail);
7230+
const optional_ptr = if (directReturn)
7231+
self.ret_ptr
7232+
else brk: {
7233+
const alignment = optional_ty.abiAlignment(mod).toLlvm();
7234+
const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment);
7235+
break :brk optional_ptr;
7236+
};
7237+
71977238
const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, "");
71987239
const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
71997240
try self.store(payload_ptr, payload_ptr_ty, operand, .none);
@@ -7204,9 +7245,10 @@ pub const FuncGen = struct {
72047245
return self.wip.buildAggregate(llvm_optional_ty, &.{ operand, non_null_bit }, "");
72057246
}
72067247

7207-
fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7248+
fn airWrapErrUnionPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
72087249
const o = self.dg.object;
72097250
const mod = o.module;
7251+
const inst = body_tail[0];
72107252
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
72117253
const err_un_ty = self.typeOfIndex(inst);
72127254
const operand = try self.resolveInst(ty_op.operand);
@@ -7220,8 +7262,15 @@ pub const FuncGen = struct {
72207262
const payload_offset = errUnionPayloadOffset(payload_ty, mod);
72217263
const error_offset = errUnionErrorOffset(payload_ty, mod);
72227264
if (isByRef(err_un_ty, mod)) {
7223-
const alignment = err_un_ty.abiAlignment(mod).toLlvm();
7224-
const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7265+
const directReturn = self.isNextRet(body_tail);
7266+
const result_ptr = if (directReturn)
7267+
self.ret_ptr
7268+
else brk: {
7269+
const alignment = err_un_ty.abiAlignment(mod).toLlvm();
7270+
const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7271+
break :brk result_ptr;
7272+
};
7273+
72257274
const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
72267275
const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();
72277276
_ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment);
@@ -7236,9 +7285,10 @@ pub const FuncGen = struct {
72367285
return self.wip.buildAggregate(err_un_llvm_ty, &fields, "");
72377286
}
72387287

7239-
fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7288+
fn airWrapErrUnionErr(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
72407289
const o = self.dg.object;
72417290
const mod = o.module;
7291+
const inst = body_tail[0];
72427292
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
72437293
const err_un_ty = self.typeOfIndex(inst);
72447294
const payload_ty = err_un_ty.errorUnionPayload(mod);
@@ -7249,8 +7299,15 @@ pub const FuncGen = struct {
72497299
const payload_offset = errUnionPayloadOffset(payload_ty, mod);
72507300
const error_offset = errUnionErrorOffset(payload_ty, mod);
72517301
if (isByRef(err_un_ty, mod)) {
7252-
const alignment = err_un_ty.abiAlignment(mod).toLlvm();
7253-
const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7302+
const directReturn = self.isNextRet(body_tail);
7303+
const result_ptr = if (directReturn)
7304+
self.ret_ptr
7305+
else brk: {
7306+
const alignment = err_un_ty.abiAlignment(mod).toLlvm();
7307+
const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7308+
break :brk result_ptr;
7309+
};
7310+
72547311
const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
72557312
const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();
72567313
_ = try self.wip.store(.normal, operand, err_ptr, error_alignment);

0 commit comments

Comments
 (0)