| ... | @@ -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), |
| 4906 | | 4906 | |
| 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..]), |
| 4910 | | 4910 | |
| 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 | } |
| 7181 | | 7191 | |
| 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 | } |
| 7206 | | 7247 | |
| 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 | } |
| 7238 | | 7287 | |
| 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); |