authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-01-21 15:54:27+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-02-04 19:09:30+01:00
log408c1172463429c1dcf675c41225100ebc750a78
tree59ca353fd1bee2467840fce2937ee2eb9ded4a3b
parent7dfd403da1cd0f25e500ed67b2dfd21c669491fa
signaturebadge-check Signed by SSH key SHA256:ZS52FNyUv2WUXvO4njmVaFVO46RHojFuOrxRc4LuKzg

spirv: air is_(non_)null_ptr, optional_payload_ptr


4 files changed, 64 insertions(+), 24 deletions(-)

src/codegen/spirv.zig+64-18
...@@ -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),
22752275
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),
22802282
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),
22832286
2284 .assembly => try self.airAssembly(inst),2287 .assembly => try self.airAssembly(inst),
22852288
...@@ -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 }
47284731
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;
47314734
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);
47364739 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);
47384741
4739 const bool_ty_ref = try self.resolveType(Type.bool, .direct);4742 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
47404743
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;
47434750
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;
47484755
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 else4758 else
4752 operand_id;4759 loaded_id;
47534760
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 }
47624769
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 else4772 if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
4766 // Optional representation is bool indicating whether the optional is set4773 const storage_class = spvStorageClass(operand_ty.ptrAddressSpace(mod));
4767 // Optionals with no payload are represented as an (indirect) bool, so convert4774 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 };
47704790
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 }
48394859
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;
48424888
test/behavior/cast.zig-1
...@@ -1247,7 +1247,6 @@ test "implicit cast from *[N]T to ?[*]T" {...@@ -1247,7 +1247,6 @@ test "implicit cast from *[N]T to ?[*]T" {
1247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1248 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1248 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1249 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1249 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1250 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
12511250
1252 var x: ?[*]u16 = null;1251 var x: ?[*]u16 = null;
1253 var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };1252 var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };
test/behavior/null.zig-2
...@@ -32,7 +32,6 @@ test "test maybe object and get a pointer to the inner value" {...@@ -32,7 +32,6 @@ test "test maybe object and get a pointer to the inner value" {
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
3635
37 var maybe_bool: ?bool = true;36 var maybe_bool: ?bool = true;
3837
...@@ -142,7 +141,6 @@ test "if var maybe pointer" {...@@ -142,7 +141,6 @@ test "if var maybe pointer" {
142 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;141 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO143 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
146144
147 try expect(shouldBeAPlus1(Particle{145 try expect(shouldBeAPlus1(Particle{
148 .a = 14,146 .a = 14,
test/behavior/optional.zig-3
...@@ -72,7 +72,6 @@ test "address of unwrap optional" {...@@ -72,7 +72,6 @@ test "address of unwrap optional" {
72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO74 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
75 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
7675
77 const S = struct {76 const S = struct {
78 const Foo = struct {77 const Foo = struct {
...@@ -341,7 +340,6 @@ test "optional pointer to zero bit optional payload" {...@@ -341,7 +340,6 @@ test "optional pointer to zero bit optional payload" {
341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO340 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
344 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
345343
346 const B = struct {344 const B = struct {
347 fn foo(_: *@This()) void {}345 fn foo(_: *@This()) void {}
...@@ -518,7 +516,6 @@ test "copied optional doesn't alias source" {...@@ -518,7 +516,6 @@ test "copied optional doesn't alias source" {
518 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO516 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
519 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO517 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
520 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO518 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
521 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
522519
523 var opt_x: ?[3]f32 = [_]f32{0.0} ** 3;520 var opt_x: ?[3]f32 = [_]f32{0.0} ** 3;
524521