authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2024-11-01 02:03:33+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2024-11-01 02:03:33+03:30
loga1cb9563f6a421220f87692f16251f3628c8cf6c
treef497b95e06f0b8f082960cd4af696bf2f5f52d15
parent17a87d734167b500761ef0d61493342dea0ae01d
signaturelock-open Commit is signed but in an unrecognized format.

spirv: Uniform/PushConstant variables

- Rename GPU address spaces to match with SPIR-V spec. - Emit `Block` Decoration for Uniform/PushConstant variables. - Don't emit `OpTypeForwardPointer` for non-opencl targets. (there's still a false-positive about recursive structs) Signed-off-by: Ali Cheraghi <alichraghi@proton.me>

7 files changed, 55 insertions(+), 35 deletions(-)

lib/std/Target.zig+1-1
......@@ -1479,7 +1479,7 @@ pub const Cpu = struct {
14791479 .fs, .gs, .ss => arch == .x86_64 or arch == .x86,
14801480 .global, .constant, .local, .shared => is_gpu,
14811481 .param => is_nvptx,
1482 .input, .output, .uniform => is_spirv,
1482 .input, .output, .uniform, .push_constant => is_spirv,
14831483 // TODO this should also check how many flash banks the cpu has
14841484 .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr,
14851485
lib/std/builtin.zig+1
......@@ -514,6 +514,7 @@ pub const AddressSpace = enum(u5) {
514514 input,
515515 output,
516516 uniform,
517 push_constant,
517518
518519 // AVR address spaces.
519520 flash,
src/Sema.zig+1-1
......@@ -37820,7 +37820,7 @@ pub fn analyzeAsAddressSpace(
3782037820 .gs, .fs, .ss => (arch == .x86 or arch == .x86_64) and ctx == .pointer,
3782137821 // TODO: check that .shared and .local are left uninitialized
3782237822 .param => is_nv,
37823 .input, .output, .uniform => is_spirv,
37823 .input, .output, .uniform, .push_constant => is_spirv,
3782437824 .global, .shared, .local => is_gpu,
3782537825 .constant => is_gpu and (ctx == .constant),
3782637826 // TODO this should also check how many flash banks the cpu has
src/codegen/spirv.zig+49-26
......@@ -897,7 +897,7 @@ const NavGen = struct {
897897 const result_ty_id = try self.resolveType(ty, repr);
898898 const ip = &zcu.intern_pool;
899899
900 log.debug("lowering constant: ty = {}, val = {}", .{ ty.fmt(pt), val.fmtValue(pt) });
900 log.debug("lowering constant: ty = {}, val = {}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) });
901901 if (val.isUndefDeep(zcu)) {
902902 return self.spv.constUndef(result_ty_id);
903903 }
......@@ -1167,7 +1167,6 @@ const NavGen = struct {
11671167
11681168 fn derivePtr(self: *NavGen, derivation: Value.PointerDeriveStep) Error!IdRef {
11691169 const pt = self.pt;
1170 const zcu = pt.zcu;
11711170 switch (derivation) {
11721171 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
11731172 .int => |int| {
......@@ -1211,10 +1210,6 @@ const NavGen = struct {
12111210 if (oac.byte_offset != 0) break :disallow;
12121211 // Allow changing the pointer type child only to restructure arrays.
12131212 // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T.
1214 const src_base_ty = parent_ptr_ty.arrayBase(zcu)[0];
1215 const dest_base_ty = oac.new_ptr_ty.arrayBase(zcu)[0];
1216 if (self.getTarget().os.tag == .vulkan and src_base_ty.toIntern() != dest_base_ty.toIntern()) break :disallow;
1217
12181213 const result_ty_id = try self.resolveType(oac.new_ptr_ty, .direct);
12191214 const result_ptr_id = self.spv.allocId();
12201215 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
......@@ -1224,7 +1219,7 @@ const NavGen = struct {
12241219 });
12251220 return result_ptr_id;
12261221 }
1227 return self.fail("Cannot perform pointer cast: '{}' to '{}'", .{
1222 return self.fail("cannot perform pointer cast: '{}' to '{}'", .{
12281223 parent_ptr_ty.fmt(pt),
12291224 oac.new_ptr_ty.fmt(pt),
12301225 });
......@@ -1308,12 +1303,12 @@ const NavGen = struct {
13081303 .global, .invocation_global => spv_decl.result_id,
13091304 };
13101305
1311 const final_storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");
1312 try self.addFunctionDep(spv_decl_index, final_storage_class);
1306 const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");
1307 try self.addFunctionDep(spv_decl_index, storage_class);
13131308
1314 const decl_ptr_ty_id = try self.ptrType(nav_ty, final_storage_class);
1309 const decl_ptr_ty_id = try self.ptrType(nav_ty, storage_class);
13151310
1316 const ptr_id = switch (final_storage_class) {
1311 const ptr_id = switch (storage_class) {
13171312 .Generic => try self.castToGeneric(decl_ptr_ty_id, decl_id),
13181313 else => decl_id,
13191314 };
......@@ -1399,6 +1394,10 @@ const NavGen = struct {
13991394
14001395 const child_ty_id = try self.resolveType(child_ty, child_repr);
14011396
1397 if (storage_class == .Uniform or storage_class == .PushConstant) {
1398 try self.spv.decorate(child_ty_id, .Block);
1399 }
1400
14021401 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypePointer, .{
14031402 .id_result = result_id,
14041403 .storage_class = storage_class,
......@@ -1503,10 +1502,13 @@ const NavGen = struct {
15031502 member_names[layout.padding_index] = "(padding)";
15041503 }
15051504
1506 const result_id = try self.spv.structType(member_types[0..layout.total_fields], member_names[0..layout.total_fields]);
1505 const result_id = self.spv.allocId();
1506 try self.spv.structType(result_id, member_types[0..layout.total_fields], member_names[0..layout.total_fields]);
1507
15071508 const type_name = try self.resolveTypeName(ty);
15081509 defer self.gpa.free(type_name);
15091510 try self.spv.debugName(result_id, type_name);
1511
15101512 return result_id;
15111513 }
15121514
......@@ -1700,10 +1702,13 @@ const NavGen = struct {
17001702 }
17011703
17021704 const size_ty_id = try self.resolveType(Type.usize, .direct);
1703 return self.spv.structType(
1705 const result_id = self.spv.allocId();
1706 try self.spv.structType(
1707 result_id,
17041708 &.{ ptr_ty_id, size_ty_id },
17051709 &.{ "ptr", "len" },
17061710 );
1711 return result_id;
17071712 },
17081713 .vector => {
17091714 const elem_ty = ty.childType(zcu);
......@@ -1730,10 +1735,13 @@ const NavGen = struct {
17301735 member_index += 1;
17311736 }
17321737
1733 const result_id = try self.spv.structType(member_types[0..member_index], null);
1738 const result_id = self.spv.allocId();
1739 try self.spv.structType(result_id, member_types[0..member_index], null);
1740
17341741 const type_name = try self.resolveTypeName(ty);
17351742 defer self.gpa.free(type_name);
17361743 try self.spv.debugName(result_id, type_name);
1744
17371745 return result_id;
17381746 },
17391747 .struct_type => ip.loadStructType(ty.toIntern()),
......@@ -1750,7 +1758,9 @@ const NavGen = struct {
17501758 var member_names = std.ArrayList([]const u8).init(self.gpa);
17511759 defer member_names.deinit();
17521760
1761 var index: u32 = 0;
17531762 var it = struct_type.iterateRuntimeOrder(ip);
1763 const result_id = self.spv.allocId();
17541764 while (it.next()) |field_index| {
17551765 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
17561766 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
......@@ -1758,16 +1768,25 @@ const NavGen = struct {
17581768 continue;
17591769 }
17601770
1771 if (target.os.tag == .vulkan) {
1772 try self.spv.decorateMember(result_id, index, .{ .Offset = .{
1773 .byte_offset = @intCast(ty.structFieldOffset(field_index, zcu)),
1774 } });
1775 }
17611776 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
17621777 try ip.getOrPutStringFmt(zcu.gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);
17631778 try member_types.append(try self.resolveType(field_ty, .indirect));
17641779 try member_names.append(field_name.toSlice(ip));
1780
1781 index += 1;
17651782 }
17661783
1767 const result_id = try self.spv.structType(member_types.items, member_names.items);
1784 try self.spv.structType(result_id, member_types.items, member_names.items);
1785
17681786 const type_name = try self.resolveTypeName(ty);
17691787 defer self.gpa.free(type_name);
17701788 try self.spv.debugName(result_id, type_name);
1789
17711790 return result_id;
17721791 },
17731792 .optional => {
......@@ -1787,10 +1806,13 @@ const NavGen = struct {
17871806
17881807 const bool_ty_id = try self.resolveType(Type.bool, .indirect);
17891808
1790 return try self.spv.structType(
1809 const result_id = self.spv.allocId();
1810 try self.spv.structType(
1811 result_id,
17911812 &.{ payload_ty_id, bool_ty_id },
17921813 &.{ "payload", "valid" },
17931814 );
1815 return result_id;
17941816 },
17951817 .@"union" => return try self.resolveUnionType(ty),
17961818 .error_set => return try self.resolveType(Type.u16, repr),
......@@ -1819,7 +1841,9 @@ const NavGen = struct {
18191841 // TODO: ABI padding?
18201842 }
18211843
1822 return try self.spv.structType(&member_types, &member_names);
1844 const result_id = self.spv.allocId();
1845 try self.spv.structType(result_id, &member_types, &member_names);
1846 return result_id;
18231847 },
18241848 .@"opaque" => {
18251849 const type_name = try self.resolveTypeName(ty);
......@@ -1849,7 +1873,7 @@ const NavGen = struct {
18491873 const target = self.getTarget();
18501874 return switch (as) {
18511875 .generic => switch (target.os.tag) {
1852 .vulkan => .Private,
1876 .vulkan => .Function,
18531877 .opencl => .Generic,
18541878 else => unreachable,
18551879 },
......@@ -1861,6 +1885,7 @@ const NavGen = struct {
18611885 else => unreachable,
18621886 },
18631887 .constant => .UniformConstant,
1888 .push_constant => .PushConstant,
18641889 .input => .Input,
18651890 .output => .Output,
18661891 .uniform => .Uniform,
......@@ -2958,10 +2983,8 @@ const NavGen = struct {
29582983 const spv_err_decl_index = try self.spv.allocDecl(.global);
29592984 try self.spv.declareDeclDeps(spv_err_decl_index, &.{});
29602985
2961 const push_constant_struct_ty_id = try self.spv.structType(
2962 &.{ptr_anyerror_ty_id},
2963 &.{"error_out_ptr"},
2964 );
2986 const push_constant_struct_ty_id = self.spv.allocId();
2987 try self.spv.structType(push_constant_struct_ty_id, &.{ptr_anyerror_ty_id}, &.{"error_out_ptr"});
29652988 try self.spv.decorate(push_constant_struct_ty_id, .Block);
29662989 try self.spv.decorateMember(push_constant_struct_ty_id, 0, .{ .Offset = .{ .byte_offset = 0 } });
29672990
......@@ -3145,15 +3168,15 @@ const NavGen = struct {
31453168 };
31463169 assert(maybe_init_val == null); // TODO
31473170
3148 const final_storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");
3149 assert(final_storage_class != .Generic); // These should be instance globals
3171 const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");
3172 assert(storage_class != .Generic); // These should be instance globals
31503173
3151 const ptr_ty_id = try self.ptrType(ty, final_storage_class);
3174 const ptr_ty_id = try self.ptrType(ty, storage_class);
31523175
31533176 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpVariable, .{
31543177 .id_result_type = ptr_ty_id,
31553178 .id_result = result_id,
3156 .storage_class = final_storage_class,
3179 .storage_class = storage_class,
31573180 });
31583181
31593182 try self.spv.debugName(result_id, nav.fqn.toSlice(ip));
src/codegen/spirv/Module.zig+1-5
......@@ -402,9 +402,7 @@ pub fn resolveString(self: *Module, string: []const u8) !IdRef {
402402 return id;
403403}
404404
405pub fn structType(self: *Module, types: []const IdRef, maybe_names: ?[]const []const u8) !IdRef {
406 const result_id = self.allocId();
407
405pub fn structType(self: *Module, result_id: IdResult, types: []const IdRef, maybe_names: ?[]const []const u8) !void {
408406 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeStruct, .{
409407 .id_result = result_id,
410408 .id_ref = types,
......@@ -416,8 +414,6 @@ pub fn structType(self: *Module, types: []const IdRef, maybe_names: ?[]const []c
416414 try self.memberDebugName(result_id, @intCast(i), name);
417415 }
418416 }
419
420 return result_id;
421417}
422418
423419pub fn boolType(self: *Module) !IdRef {
src/link/SpirV.zig+1-1
......@@ -296,7 +296,7 @@ fn writeCapabilities(spv: *SpvModule, target: std.Target) !void {
296296 // TODO: Integrate with a hypothetical feature system
297297 const caps: []const spec.Capability = switch (target.os.tag) {
298298 .opencl => &.{ .Kernel, .Addresses, .Int8, .Int16, .Int64, .Float64, .Float16, .Vector16, .GenericPointer },
299 .vulkan => &.{ .Shader, .PhysicalStorageBufferAddresses, .StoragePushConstant16, .Int8, .Int16, .Int64, .Float64, .Float16 },
299 .vulkan => &.{ .Shader, .PhysicalStorageBufferAddresses, .Int8, .Int16, .Int64, .Float64, .Float16 },
300300 else => unreachable,
301301 };
302302
src/target.zig+1-1
......@@ -418,7 +418,7 @@ pub fn arePointersLogical(target: std.Target, as: AddressSpace) bool {
418418 .global => false,
419419 // TODO: Allowed with VK_KHR_variable_pointers.
420420 .shared => true,
421 .constant, .local, .input, .output, .uniform => true,
421 .constant, .local, .input, .output, .uniform, .push_constant => true,
422422 else => unreachable,
423423 };
424424}