| ... | @@ -2273,13 +2273,16 @@ const DeclGen = struct { | ... | @@ -2273,13 +2273,16 @@ const DeclGen = struct { |
| 2273 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), | 2273 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 2274 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), | 2274 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 2275 | | 2275 | |
| 2276 | .is_null => try self.airIsNull(inst, .is_null), | 2276 | .is_null => try self.airIsNull(inst, false, .is_null), |
| 2277 | .is_non_null => try self.airIsNull(inst, .is_non_null), | 2277 | .is_non_null => try self.airIsNull(inst, false, .is_non_null), |
| 2278 | .is_err => try self.airIsErr(inst, .is_err), | 2278 | .is_null_ptr => try self.airIsNull(inst, true, .is_null), |
| 2279 | .is_non_err => try self.airIsErr(inst, .is_non_err), | 2279 | .is_non_null_ptr => try self.airIsNull(inst, true, .is_non_null), |
| | 2280 | .is_err => try self.airIsErr(inst, .is_err), |
| | 2281 | .is_non_err => try self.airIsErr(inst, .is_non_err), |
| 2280 | | 2282 | |
| 2281 | .optional_payload => try self.airUnwrapOptional(inst), | 2283 | .optional_payload => try self.airUnwrapOptional(inst), |
| 2282 | .wrap_optional => try self.airWrapOptional(inst), | 2284 | .optional_payload_ptr => try self.airUnwrapOptionalPtr(inst), |
| | 2285 | .wrap_optional => try self.airWrapOptional(inst), |
| 2283 | | 2286 | |
| 2284 | .assembly => try self.airAssembly(inst), | 2287 | .assembly => try self.airAssembly(inst), |
| 2285 | | 2288 | |
| ... | @@ -4726,20 +4729,24 @@ const DeclGen = struct { | ... | @@ -4726,20 +4729,24 @@ const DeclGen = struct { |
| 4726 | return try self.constructStruct(err_union_ty, &types, &members); | 4729 | return try self.constructStruct(err_union_ty, &types, &members); |
| 4727 | } | 4730 | } |
| 4728 | | 4731 | |
| 4729 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { | 4732 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?IdRef { |
| 4730 | if (self.liveness.isUnused(inst)) return null; | 4733 | if (self.liveness.isUnused(inst)) return null; |
| 4731 | | 4734 | |
| 4732 | const mod = self.module; | 4735 | const mod = self.module; |
| 4733 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; | 4736 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 4734 | const operand_id = try self.resolve(un_op); | 4737 | const operand_id = try self.resolve(un_op); |
| 4735 | const optional_ty = self.typeOf(un_op); | 4738 | const operand_ty = self.typeOf(un_op); |
| 4736 | | 4739 | const optional_ty = if (is_pointer) operand_ty.childType(mod) else operand_ty; |
| 4737 | const payload_ty = optional_ty.optionalChild(mod); | 4740 | const payload_ty = optional_ty.optionalChild(mod); |
| 4738 | | 4741 | |
| 4739 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); | 4742 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| 4740 | | 4743 | |
| 4741 | if (optional_ty.optionalReprIsPayload(mod)) { | 4744 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 4742 | // Pointer payload represents nullability: pointer or slice. | 4745 | // Pointer payload represents nullability: pointer or slice. |
| | 4746 | const loaded_id = if (is_pointer) |
| | 4747 | try self.load(optional_ty, operand_id, .{}) |
| | 4748 | else |
| | 4749 | operand_id; |
| 4743 | | 4750 | |
| 4744 | const ptr_ty = if (payload_ty.isSlice(mod)) | 4751 | const ptr_ty = if (payload_ty.isSlice(mod)) |
| 4745 | payload_ty.slicePtrFieldType(mod) | 4752 | payload_ty.slicePtrFieldType(mod) |
| ... | @@ -4747,9 +4754,9 @@ const DeclGen = struct { | ... | @@ -4747,9 +4754,9 @@ const DeclGen = struct { |
| 4747 | payload_ty; | 4754 | payload_ty; |
| 4748 | | 4755 | |
| 4749 | const ptr_id = if (payload_ty.isSlice(mod)) | 4756 | const ptr_id = if (payload_ty.isSlice(mod)) |
| 4750 | try self.extractField(ptr_ty, operand_id, 0) | 4757 | try self.extractField(ptr_ty, loaded_id, 0) |
| 4751 | else | 4758 | else |
| 4752 | operand_id; | 4759 | loaded_id; |
| 4753 | | 4760 | |
| 4754 | const payload_ty_ref = try self.resolveType(ptr_ty, .direct); | 4761 | const payload_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 4755 | const null_id = try self.spv.constNull(payload_ty_ref); | 4762 | const null_id = try self.spv.constNull(payload_ty_ref); |
| ... | @@ -4760,13 +4767,26 @@ const DeclGen = struct { | ... | @@ -4760,13 +4767,26 @@ const DeclGen = struct { |
| 4760 | return try self.cmp(op, Type.bool, ptr_ty, ptr_id, null_id); | 4767 | return try self.cmp(op, Type.bool, ptr_ty, ptr_id, null_id); |
| 4761 | } | 4768 | } |
| 4762 | | 4769 | |
| 4763 | const is_non_null_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) | 4770 | const is_non_null_id = blk: { |
| 4764 | try self.extractField(Type.bool, operand_id, 1) | 4771 | if (is_pointer) { |
| 4765 | else | 4772 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4766 | // Optional representation is bool indicating whether the optional is set | 4773 | const storage_class = spvStorageClass(operand_ty.ptrAddressSpace(mod)); |
| 4767 | // Optionals with no payload are represented as an (indirect) bool, so convert | 4774 | const bool_ptr_ty = try self.ptrType(Type.bool, storage_class); |
| 4768 | // it back to the direct bool here. | 4775 | const tag_ptr_id = try self.accessChain(bool_ptr_ty, operand_id, &.{1}); |
| 4769 | try self.convertToDirect(Type.bool, operand_id); | 4776 | break :blk try self.load(Type.bool, tag_ptr_id, .{}); |
| | 4777 | } |
| | 4778 | |
| | 4779 | break :blk try self.load(Type.bool, operand_id, .{}); |
| | 4780 | } |
| | 4781 | |
| | 4782 | break :blk if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| | 4783 | try self.extractField(Type.bool, operand_id, 1) |
| | 4784 | else |
| | 4785 | // Optional representation is bool indicating whether the optional is set |
| | 4786 | // Optionals with no payload are represented as an (indirect) bool, so convert |
| | 4787 | // it back to the direct bool here. |
| | 4788 | try self.convertToDirect(Type.bool, operand_id); |
| | 4789 | }; |
| 4770 | | 4790 | |
| 4771 | return switch (pred) { | 4791 | return switch (pred) { |
| 4772 | .is_null => blk: { | 4792 | .is_null => blk: { |
| ... | @@ -4837,6 +4857,32 @@ const DeclGen = struct { | ... | @@ -4837,6 +4857,32 @@ const DeclGen = struct { |
| 4837 | return try self.extractField(payload_ty, operand_id, 0); | 4857 | return try self.extractField(payload_ty, operand_id, 0); |
| 4838 | } | 4858 | } |
| 4839 | | 4859 | |
| | 4860 | fn airUnwrapOptionalPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| | 4861 | if (self.liveness.isUnused(inst)) return null; |
| | 4862 | |
| | 4863 | const mod = self.module; |
| | 4864 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| | 4865 | const operand_id = try self.resolve(ty_op.operand); |
| | 4866 | const operand_ty = self.typeOf(ty_op.operand); |
| | 4867 | const optional_ty = operand_ty.childType(mod); |
| | 4868 | const payload_ty = optional_ty.optionalChild(mod); |
| | 4869 | const result_ty = self.typeOfIndex(inst); |
| | 4870 | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| | 4871 | |
| | 4872 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| | 4873 | // There is no payload, but we still need to return a valid pointer. |
| | 4874 | // We can just return anything here, so just return a pointer to the operand. |
| | 4875 | return try self.bitCast(result_ty, operand_ty, operand_id); |
| | 4876 | } |
| | 4877 | |
| | 4878 | if (optional_ty.optionalReprIsPayload(mod)) { |
| | 4879 | // They are the same value. |
| | 4880 | return try self.bitCast(result_ty, operand_ty, operand_id); |
| | 4881 | } |
| | 4882 | |
| | 4883 | return try self.accessChain(result_ty_ref, operand_id, &.{0}); |
| | 4884 | } |
| | 4885 | |
| 4840 | fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 4886 | fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 4841 | if (self.liveness.isUnused(inst)) return null; | 4887 | if (self.liveness.isUnused(inst)) return null; |
| 4842 | | 4888 | |