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
signaturebadge-check 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 {
10081008 .func => {
10091009 // TODO: Properly lower function pointers. For now we are going to hack around it and
10101010 // just generate an empty pointer. Function pointers are represented by a pointer to usize.
1011 // TODO: Add dependency
1012 return try self.spv.constNull(ty_ref);
1011 return try self.spv.constUndef(ty_ref);
10131012 },
10141013 .extern_func => unreachable, // TODO
10151014 else => {},
......@@ -1253,6 +1252,18 @@ const DeclGen = struct {
12531252 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse {
12541253 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)});
12551254 };
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
12561267 const ty_ref = try self.spv.arrayType(total_len, elem_ty_ref);
12571268 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
12581269 return ty_ref;
......@@ -2742,22 +2753,23 @@ const DeclGen = struct {
27422753 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
27432754 const array_ptr_ty = self.typeOf(ty_op.operand);
27442755 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)));
27482756 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);
27492760 const slice_ty_ref = try self.resolveType(slice_ty, .direct);
27502761 const size_ty_ref = try self.sizeType();
27512762
27522763 const array_ptr_id = try self.resolve(ty_op.operand);
27532764 const len_id = try self.constInt(size_ty_ref, array_ty.arrayLen(mod));
27542765
2755 if (!array_ty.hasRuntimeBitsIgnoreComptime(mod)) {
2756 unreachable; // TODO
2757 }
2766 const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))
2767 // Note: The pointer is something like *opaque{}, so we need to bitcast it to the element type.
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});
27612773 return try self.constructStruct(slice_ty_ref, &.{ elem_ptr_id, len_id });
27622774 }
27632775
......@@ -2916,8 +2928,10 @@ const DeclGen = struct {
29162928 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
29172929 const ptr_ty = self.typeOf(bin_op.lhs);
29182930 const elem_ty = ptr_ty.childType(mod);
2919 // TODO: Make this return a null ptr or something
2920 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;
2931 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) {
2932 const ptr_ty_ref = try self.resolveType(ptr_ty, .direct);
2933 return try self.spv.constUndef(ptr_ty_ref);
2934 }
29212935
29222936 const ptr_id = try self.resolve(bin_op.lhs);
29232937 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" {
6464
6565test "implicitly cast array of size 0 to slice" {
6666 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
6867
6968 var msg = [_]u8{};
7069 try assertLenIsZero(&msg);
......@@ -172,7 +171,6 @@ test "comptime pointer cast array and then slice" {
172171test "slicing zero length array" {
173172 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
174173 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
175 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
176174
177175 const s1 = ""[0..];
178176 const s2 = ([_]u32{})[0..];
......@@ -583,7 +581,6 @@ test "slice pointer-to-array null terminated" {
583581
584582test "slice pointer-to-array zero length" {
585583 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
586 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
587584
588585 comptime {
589586 {
......@@ -793,8 +790,6 @@ test "global slice field access" {
793790}
794791
795792test "slice of void" {
796 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
797
798793 var n: usize = 10;
799794 var arr: [12]void = undefined;
800795 const slice = @as([]void, &arr)[0..n];
......@@ -802,8 +797,6 @@ test "slice of void" {
802797}
803798
804799test "slice with dereferenced value" {
805 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
806
807800 var a: usize = 0;
808801 var idx: *usize = &a;
809802 _ = blk: {
......@@ -819,7 +812,6 @@ test "slice with dereferenced value" {
819812
820813test "empty slice ptr is non null" {
821814 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
824816 {
825817 const empty_slice: []u8 = &[_]u8{};