| ... | ... | @@ -4904,9 +4904,9 @@ pub const FuncGen = struct { |
| 4904 | 4904 | .set_err_return_trace => try self.airSetErrReturnTrace(inst), |
| 4905 | 4905 | .save_err_return_trace_index => try self.airSaveErrReturnTraceIndex(inst), |
| 4906 | 4906 | |
| 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..]), |
| 4910 | 4910 | |
| 4911 | 4911 | .wasm_memory_size => try self.airWasmMemorySize(inst), |
| 4912 | 4912 | .wasm_memory_grow => try self.airWasmMemoryGrow(inst), |
| ... | ... | @@ -5299,6 +5299,16 @@ pub const FuncGen = struct { |
| 5299 | 5299 | if (self.ret_ptr != .none) { |
| 5300 | 5300 | const operand = try self.resolveInst(un_op); |
| 5301 | 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 | 5312 | try self.store(self.ret_ptr, ptr_ty, operand, .none); |
| 5303 | 5313 | _ = try self.wip.retVoid(); |
| 5304 | 5314 | return .none; |
| ... | ... | @@ -7179,9 +7189,33 @@ pub const FuncGen = struct { |
| 7179 | 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 | 7216 | const o = self.dg.object; |
| 7184 | 7217 | const mod = o.module; |
| 7218 | const inst = body_tail[0]; |
| 7185 | 7219 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7186 | 7220 | const payload_ty = self.typeOf(ty_op.operand); |
| 7187 | 7221 | const non_null_bit = try o.builder.intValue(.i8, 1); |
| ... | ... | @@ -7192,8 +7226,15 @@ pub const FuncGen = struct { |
| 7192 | 7226 | if (optional_ty.optionalReprIsPayload(mod)) return operand; |
| 7193 | 7227 | const llvm_optional_ty = try o.lowerType(optional_ty); |
| 7194 | 7228 | 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 | |
| 7197 | 7238 | const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, ""); |
| 7198 | 7239 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); |
| 7199 | 7240 | try self.store(payload_ptr, payload_ptr_ty, operand, .none); |
| ... | ... | @@ -7204,9 +7245,10 @@ pub const FuncGen = struct { |
| 7204 | 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 | 7249 | const o = self.dg.object; |
| 7209 | 7250 | const mod = o.module; |
| 7251 | const inst = body_tail[0]; |
| 7210 | 7252 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7211 | 7253 | const err_un_ty = self.typeOfIndex(inst); |
| 7212 | 7254 | const operand = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -7220,8 +7262,15 @@ pub const FuncGen = struct { |
| 7220 | 7262 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| 7221 | 7263 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 7222 | 7264 | 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 | |
| 7225 | 7274 | const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 7226 | 7275 | const error_alignment = Type.err_int.abiAlignment(mod).toLlvm(); |
| 7227 | 7276 | _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment); |
| ... | ... | @@ -7236,9 +7285,10 @@ pub const FuncGen = struct { |
| 7236 | 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 | 7289 | const o = self.dg.object; |
| 7241 | 7290 | const mod = o.module; |
| 7291 | const inst = body_tail[0]; |
| 7242 | 7292 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7243 | 7293 | const err_un_ty = self.typeOfIndex(inst); |
| 7244 | 7294 | const payload_ty = err_un_ty.errorUnionPayload(mod); |
| ... | ... | @@ -7249,8 +7299,15 @@ pub const FuncGen = struct { |
| 7249 | 7299 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| 7250 | 7300 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 7251 | 7301 | 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 | |
| 7254 | 7311 | const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 7255 | 7312 | const error_alignment = Type.err_int.abiAlignment(mod).toLlvm(); |
| 7256 | 7313 | _ = try self.wip.store(.normal, operand, err_ptr, error_alignment); |