authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-08 10:54:41+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-15 14:00:05+02:00
log2d52fc762da7e7288c4caa381fb02933c205e9be
tree685680a036fb8323c5d4049c5838c97c22287f33
parentd8b591766ac37090ae77f7b67d0ce6b54c64254e
signature Signed by SSH key SHA256:CQ99aPxq+RueiL9u7z0FEki5Fm7V6T8q4PrEGmINrA4

spirv: handle zero-sized arrays


2 files changed, 26 insertions(+), 20 deletions(-)

src/codegen/spirv.zig+26-12
...@@ -1008,8 +1008,7 @@ const DeclGen = struct {...@@ -1008,8 +1008,7 @@ const DeclGen = struct {
1008 .func => {1008 .func => {
1009 // TODO: Properly lower function pointers. For now we are going to hack around it and1009 // TODO: Properly lower function pointers. For now we are going to hack around it and
1010 // just generate an empty pointer. Function pointers are represented by a pointer to usize.1010 // just generate an empty pointer. Function pointers are represented by a pointer to usize.
1011 // TODO: Add dependency1011 return try self.spv.constUndef(ty_ref);
1012 return try self.spv.constNull(ty_ref);
1013 },1012 },
1014 .extern_func => unreachable, // TODO1013 .extern_func => unreachable, // TODO
1015 else => {},1014 else => {},
...@@ -1253,6 +1252,18 @@ const DeclGen = struct {...@@ -1253,6 +1252,18 @@ const DeclGen = struct {
1253 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse {1252 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse {
1254 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)});1253 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)});
1255 };1254 };
1255 if (!ty.hasRuntimeBitsIgnoreComptime(mod)) {
1256 // The size of the array would be 0, but that is not allowed in SPIR-V.
1257 // This path can be reached for example when there is a slicing of a pointer
1258 // that produces a zero-length array. In all cases where this type can be generated,
1259 // we should be in an indirect path (direct uses of this type should be filtered out in Sema).
1260 assert(repr == .indirect);
1261
1262 return try self.spv.resolve(.{ .opaque_type = .{
1263 .name = try self.spv.resolveString("zero-sized array"),
1264 } });
1265 }
1266
1256 const ty_ref = try self.spv.arrayType(total_len, elem_ty_ref);1267 const ty_ref = try self.spv.arrayType(total_len, elem_ty_ref);
1257 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });1268 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
1258 return ty_ref;1269 return ty_ref;
...@@ -2742,22 +2753,23 @@ const DeclGen = struct {...@@ -2742,22 +2753,23 @@ const DeclGen = struct {
2742 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2753 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2743 const array_ptr_ty = self.typeOf(ty_op.operand);2754 const array_ptr_ty = self.typeOf(ty_op.operand);
2744 const array_ty = array_ptr_ty.childType(mod);2755 const array_ty = array_ptr_ty.childType(mod);
2745 const elem_ty = array_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T.
2746 const elem_ty_ref = try self.resolveType(elem_ty, .indirect);
2747 const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(array_ptr_ty.ptrAddressSpace(mod)));
2748 const slice_ty = self.typeOfIndex(inst);2756 const slice_ty = self.typeOfIndex(inst);
2757 const elem_ptr_ty = slice_ty.slicePtrFieldType(mod);
2758
2759 const elem_ptr_ty_ref = try self.resolveType(elem_ptr_ty, .direct);
2749 const slice_ty_ref = try self.resolveType(slice_ty, .direct);2760 const slice_ty_ref = try self.resolveType(slice_ty, .direct);
2750 const size_ty_ref = try self.sizeType();2761 const size_ty_ref = try self.sizeType();
27512762
2752 const array_ptr_id = try self.resolve(ty_op.operand);2763 const array_ptr_id = try self.resolve(ty_op.operand);
2753 const len_id = try self.constInt(size_ty_ref, array_ty.arrayLen(mod));2764 const len_id = try self.constInt(size_ty_ref, array_ty.arrayLen(mod));
27542765
2755 if (!array_ty.hasRuntimeBitsIgnoreComptime(mod)) {2766 const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))
2756 unreachable; // TODO2767 // Note: The pointer is something like *opaque{}, so we need to bitcast it to the element type.
2757 }2768 try self.bitCast(elem_ptr_ty, array_ptr_ty, array_ptr_id)
2769 else
2770 // Convert the pointer-to-array to a pointer to the first element.
2771 try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0});
27582772
2759 // Convert the pointer-to-array to a pointer to the first element.
2760 const elem_ptr_id = try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0});
2761 return try self.constructStruct(slice_ty_ref, &.{ elem_ptr_id, len_id });2773 return try self.constructStruct(slice_ty_ref, &.{ elem_ptr_id, len_id });
2762 }2774 }
27632775
...@@ -2916,8 +2928,10 @@ const DeclGen = struct {...@@ -2916,8 +2928,10 @@ const DeclGen = struct {
2916 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;2928 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2917 const ptr_ty = self.typeOf(bin_op.lhs);2929 const ptr_ty = self.typeOf(bin_op.lhs);
2918 const elem_ty = ptr_ty.childType(mod);2930 const elem_ty = ptr_ty.childType(mod);
2919 // TODO: Make this return a null ptr or something2931 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) {
2920 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;2932 const ptr_ty_ref = try self.resolveType(ptr_ty, .direct);
2933 return try self.spv.constUndef(ptr_ty_ref);
2934 }
29212935
2922 const ptr_id = try self.resolve(bin_op.lhs);2936 const ptr_id = try self.resolve(bin_op.lhs);
2923 const index_id = try self.resolve(bin_op.rhs);2937 const index_id = try self.resolve(bin_op.rhs);
test/behavior/slice.zig-8
...@@ -64,7 +64,6 @@ test "comptime slice of undefined pointer of length 0" {...@@ -64,7 +64,6 @@ test "comptime slice of undefined pointer of length 0" {
6464
65test "implicitly cast array of size 0 to slice" {65test "implicitly cast array of size 0 to slice" {
66 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO66 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
6867
69 var msg = [_]u8{};68 var msg = [_]u8{};
70 try assertLenIsZero(&msg);69 try assertLenIsZero(&msg);
...@@ -172,7 +171,6 @@ test "comptime pointer cast array and then slice" {...@@ -172,7 +171,6 @@ test "comptime pointer cast array and then slice" {
172test "slicing zero length array" {171test "slicing zero length array" {
173 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;172 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
174 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO173 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
175 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
176174
177 const s1 = ""[0..];175 const s1 = ""[0..];
178 const s2 = ([_]u32{})[0..];176 const s2 = ([_]u32{})[0..];
...@@ -583,7 +581,6 @@ test "slice pointer-to-array null terminated" {...@@ -583,7 +581,6 @@ test "slice pointer-to-array null terminated" {
583581
584test "slice pointer-to-array zero length" {582test "slice pointer-to-array zero length" {
585 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO583 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
586 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
587584
588 comptime {585 comptime {
589 {586 {
...@@ -793,8 +790,6 @@ test "global slice field access" {...@@ -793,8 +790,6 @@ test "global slice field access" {
793}790}
794791
795test "slice of void" {792test "slice of void" {
796 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
797
798 var n: usize = 10;793 var n: usize = 10;
799 var arr: [12]void = undefined;794 var arr: [12]void = undefined;
800 const slice = @as([]void, &arr)[0..n];795 const slice = @as([]void, &arr)[0..n];
...@@ -802,8 +797,6 @@ test "slice of void" {...@@ -802,8 +797,6 @@ test "slice of void" {
802}797}
803798
804test "slice with dereferenced value" {799test "slice with dereferenced value" {
805 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
806
807 var a: usize = 0;800 var a: usize = 0;
808 var idx: *usize = &a;801 var idx: *usize = &a;
809 _ = blk: {802 _ = blk: {
...@@ -819,7 +812,6 @@ test "slice with dereferenced value" {...@@ -819,7 +812,6 @@ test "slice with dereferenced value" {
819812
820test "empty slice ptr is non null" {813test "empty slice ptr is non null" {
821 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO814 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO
822 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
823815
824 {816 {
825 const empty_slice: []u8 = &[_]u8{};817 const empty_slice: []u8 = &[_]u8{};