authorgravatar for oliverhenryc@gmail.comocrap7 <oliverhenryc@gmail.com> 2023-09-28 12:38:26-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-03 11:16:11-07:00
logc933a7c58c6685f65da26e7c4cc826a32c3d1e43
tree75b7a544aa166837f77bae83847eb74152d2703c
parent5c3393dc2efc836b0ec23e3c2c5ad3da4f8d6a59

llvm: remove extra copy of wrapped payloads


1 files changed, 69 insertions(+), 12 deletions(-)

src/codegen/llvm.zig+69-12
...@@ -4904,9 +4904,9 @@ pub const FuncGen = struct {...@@ -4904,9 +4904,9 @@ pub const FuncGen = struct {
4904 .set_err_return_trace => try self.airSetErrReturnTrace(inst),4904 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
4905 .save_err_return_trace_index => try self.airSaveErrReturnTraceIndex(inst),4905 .save_err_return_trace_index => try self.airSaveErrReturnTraceIndex(inst),
49064906
4907 .wrap_optional => try self.airWrapOptional(inst),4907 .wrap_optional => try self.airWrapOptional(body[i..]),
4908 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),4908 .wrap_errunion_payload => try self.airWrapErrUnionPayload(body[i..]),
4909 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),4909 .wrap_errunion_err => try self.airWrapErrUnionErr(body[i..]),
49104910
4911 .wasm_memory_size => try self.airWasmMemorySize(inst),4911 .wasm_memory_size => try self.airWasmMemorySize(inst),
4912 .wasm_memory_grow => try self.airWasmMemoryGrow(inst),4912 .wasm_memory_grow => try self.airWasmMemoryGrow(inst),
...@@ -5299,6 +5299,16 @@ pub const FuncGen = struct {...@@ -5299,6 +5299,16 @@ pub const FuncGen = struct {
5299 if (self.ret_ptr != .none) {5299 if (self.ret_ptr != .none) {
5300 const operand = try self.resolveInst(un_op);5300 const operand = try self.resolveInst(un_op);
5301 const ptr_ty = try mod.singleMutPtrType(ret_ty);5301 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
5302 try self.store(self.ret_ptr, ptr_ty, operand, .none);5312 try self.store(self.ret_ptr, ptr_ty, operand, .none);
5303 _ = try self.wip.retVoid();5313 _ = try self.wip.retVoid();
5304 return .none;5314 return .none;
...@@ -7179,9 +7189,33 @@ pub const FuncGen = struct {...@@ -7179,9 +7189,33 @@ pub const FuncGen = struct {
7179 return self.load(field_ptr, field_ptr_ty);7189 return self.load(field_ptr, field_ptr_ty);
7180 }7190 }
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 {
7183 const o = self.dg.object;7216 const o = self.dg.object;
7184 const mod = o.module;7217 const mod = o.module;
7218 const inst = body_tail[0];
7185 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7219 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7186 const payload_ty = self.typeOf(ty_op.operand);7220 const payload_ty = self.typeOf(ty_op.operand);
7187 const non_null_bit = try o.builder.intValue(.i8, 1);7221 const non_null_bit = try o.builder.intValue(.i8, 1);
...@@ -7192,8 +7226,15 @@ pub const FuncGen = struct {...@@ -7192,8 +7226,15 @@ pub const FuncGen = struct {
7192 if (optional_ty.optionalReprIsPayload(mod)) return operand;7226 if (optional_ty.optionalReprIsPayload(mod)) return operand;
7193 const llvm_optional_ty = try o.lowerType(optional_ty);7227 const llvm_optional_ty = try o.lowerType(optional_ty);
7194 if (isByRef(optional_ty, mod)) {7228 if (isByRef(optional_ty, mod)) {
7195 const alignment = optional_ty.abiAlignment(mod).toLlvm();7229 const directReturn = self.isNextRet(body_tail);
7196 const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment);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
7197 const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, "");7238 const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, "");
7198 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);7239 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
7199 try self.store(payload_ptr, payload_ptr_ty, operand, .none);7240 try self.store(payload_ptr, payload_ptr_ty, operand, .none);
...@@ -7204,9 +7245,10 @@ pub const FuncGen = struct {...@@ -7204,9 +7245,10 @@ pub const FuncGen = struct {
7204 return self.wip.buildAggregate(llvm_optional_ty, &.{ operand, non_null_bit }, "");7245 return self.wip.buildAggregate(llvm_optional_ty, &.{ operand, non_null_bit }, "");
7205 }7246 }
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 {
7208 const o = self.dg.object;7249 const o = self.dg.object;
7209 const mod = o.module;7250 const mod = o.module;
7251 const inst = body_tail[0];
7210 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7252 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7211 const err_un_ty = self.typeOfIndex(inst);7253 const err_un_ty = self.typeOfIndex(inst);
7212 const operand = try self.resolveInst(ty_op.operand);7254 const operand = try self.resolveInst(ty_op.operand);
...@@ -7220,8 +7262,15 @@ pub const FuncGen = struct {...@@ -7220,8 +7262,15 @@ pub const FuncGen = struct {
7220 const payload_offset = errUnionPayloadOffset(payload_ty, mod);7262 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
7221 const error_offset = errUnionErrorOffset(payload_ty, mod);7263 const error_offset = errUnionErrorOffset(payload_ty, mod);
7222 if (isByRef(err_un_ty, mod)) {7264 if (isByRef(err_un_ty, mod)) {
7223 const alignment = err_un_ty.abiAlignment(mod).toLlvm();7265 const directReturn = self.isNextRet(body_tail);
7224 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);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
7225 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");7274 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
7226 const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();7275 const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();
7227 _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment);7276 _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment);
...@@ -7236,9 +7285,10 @@ pub const FuncGen = struct {...@@ -7236,9 +7285,10 @@ pub const FuncGen = struct {
7236 return self.wip.buildAggregate(err_un_llvm_ty, &fields, "");7285 return self.wip.buildAggregate(err_un_llvm_ty, &fields, "");
7237 }7286 }
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 {
7240 const o = self.dg.object;7289 const o = self.dg.object;
7241 const mod = o.module;7290 const mod = o.module;
7291 const inst = body_tail[0];
7242 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7292 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7243 const err_un_ty = self.typeOfIndex(inst);7293 const err_un_ty = self.typeOfIndex(inst);
7244 const payload_ty = err_un_ty.errorUnionPayload(mod);7294 const payload_ty = err_un_ty.errorUnionPayload(mod);
...@@ -7249,8 +7299,15 @@ pub const FuncGen = struct {...@@ -7249,8 +7299,15 @@ pub const FuncGen = struct {
7249 const payload_offset = errUnionPayloadOffset(payload_ty, mod);7299 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
7250 const error_offset = errUnionErrorOffset(payload_ty, mod);7300 const error_offset = errUnionErrorOffset(payload_ty, mod);
7251 if (isByRef(err_un_ty, mod)) {7301 if (isByRef(err_un_ty, mod)) {
7252 const alignment = err_un_ty.abiAlignment(mod).toLlvm();7302 const directReturn = self.isNextRet(body_tail);
7253 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);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
7254 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");7311 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
7255 const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();7312 const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();
7256 _ = try self.wip.store(.normal, operand, err_ptr, error_alignment);7313 _ = try self.wip.store(.normal, operand, err_ptr, error_alignment);