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 {...@@ -1479,7 +1479,7 @@ pub const Cpu = struct {
1479 .fs, .gs, .ss => arch == .x86_64 or arch == .x86,1479 .fs, .gs, .ss => arch == .x86_64 or arch == .x86,
1480 .global, .constant, .local, .shared => is_gpu,1480 .global, .constant, .local, .shared => is_gpu,
1481 .param => is_nvptx,1481 .param => is_nvptx,
1482 .input, .output, .uniform => is_spirv,1482 .input, .output, .uniform, .push_constant => is_spirv,
1483 // TODO this should also check how many flash banks the cpu has1483 // TODO this should also check how many flash banks the cpu has
1484 .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr,1484 .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr,
14851485
lib/std/builtin.zig+1
...@@ -514,6 +514,7 @@ pub const AddressSpace = enum(u5) {...@@ -514,6 +514,7 @@ pub const AddressSpace = enum(u5) {
514 input,514 input,
515 output,515 output,
516 uniform,516 uniform,
517 push_constant,
517518
518 // AVR address spaces.519 // AVR address spaces.
519 flash,520 flash,
src/Sema.zig+1-1
...@@ -37820,7 +37820,7 @@ pub fn analyzeAsAddressSpace(...@@ -37820,7 +37820,7 @@ pub fn analyzeAsAddressSpace(
37820 .gs, .fs, .ss => (arch == .x86 or arch == .x86_64) and ctx == .pointer,37820 .gs, .fs, .ss => (arch == .x86 or arch == .x86_64) and ctx == .pointer,
37821 // TODO: check that .shared and .local are left uninitialized37821 // TODO: check that .shared and .local are left uninitialized
37822 .param => is_nv,37822 .param => is_nv,
37823 .input, .output, .uniform => is_spirv,37823 .input, .output, .uniform, .push_constant => is_spirv,
37824 .global, .shared, .local => is_gpu,37824 .global, .shared, .local => is_gpu,
37825 .constant => is_gpu and (ctx == .constant),37825 .constant => is_gpu and (ctx == .constant),
37826 // TODO this should also check how many flash banks the cpu has37826 // 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 {...@@ -897,7 +897,7 @@ const NavGen = struct {
897 const result_ty_id = try self.resolveType(ty, repr);897 const result_ty_id = try self.resolveType(ty, repr);
898 const ip = &zcu.intern_pool;898 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())) });
901 if (val.isUndefDeep(zcu)) {901 if (val.isUndefDeep(zcu)) {
902 return self.spv.constUndef(result_ty_id);902 return self.spv.constUndef(result_ty_id);
903 }903 }
...@@ -1167,7 +1167,6 @@ const NavGen = struct {...@@ -1167,7 +1167,6 @@ const NavGen = struct {
11671167
1168 fn derivePtr(self: *NavGen, derivation: Value.PointerDeriveStep) Error!IdRef {1168 fn derivePtr(self: *NavGen, derivation: Value.PointerDeriveStep) Error!IdRef {
1169 const pt = self.pt;1169 const pt = self.pt;
1170 const zcu = pt.zcu;
1171 switch (derivation) {1170 switch (derivation) {
1172 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,1171 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
1173 .int => |int| {1172 .int => |int| {
...@@ -1211,10 +1210,6 @@ const NavGen = struct {...@@ -1211,10 +1210,6 @@ const NavGen = struct {
1211 if (oac.byte_offset != 0) break :disallow;1210 if (oac.byte_offset != 0) break :disallow;
1212 // Allow changing the pointer type child only to restructure arrays.1211 // Allow changing the pointer type child only to restructure arrays.
1213 // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T.1212 // 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
1218 const result_ty_id = try self.resolveType(oac.new_ptr_ty, .direct);1213 const result_ty_id = try self.resolveType(oac.new_ptr_ty, .direct);
1219 const result_ptr_id = self.spv.allocId();1214 const result_ptr_id = self.spv.allocId();
1220 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{1215 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
...@@ -1224,7 +1219,7 @@ const NavGen = struct {...@@ -1224,7 +1219,7 @@ const NavGen = struct {
1224 });1219 });
1225 return result_ptr_id;1220 return result_ptr_id;
1226 }1221 }
1227 return self.fail("Cannot perform pointer cast: '{}' to '{}'", .{1222 return self.fail("cannot perform pointer cast: '{}' to '{}'", .{
1228 parent_ptr_ty.fmt(pt),1223 parent_ptr_ty.fmt(pt),
1229 oac.new_ptr_ty.fmt(pt),1224 oac.new_ptr_ty.fmt(pt),
1230 });1225 });
...@@ -1308,12 +1303,12 @@ const NavGen = struct {...@@ -1308,12 +1303,12 @@ const NavGen = struct {
1308 .global, .invocation_global => spv_decl.result_id,1303 .global, .invocation_global => spv_decl.result_id,
1309 };1304 };
13101305
1311 const final_storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");1306 const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");
1312 try self.addFunctionDep(spv_decl_index, final_storage_class);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) {
1317 .Generic => try self.castToGeneric(decl_ptr_ty_id, decl_id),1312 .Generic => try self.castToGeneric(decl_ptr_ty_id, decl_id),
1318 else => decl_id,1313 else => decl_id,
1319 };1314 };
...@@ -1399,6 +1394,10 @@ const NavGen = struct {...@@ -1399,6 +1394,10 @@ const NavGen = struct {
13991394
1400 const child_ty_id = try self.resolveType(child_ty, child_repr);1395 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
1402 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypePointer, .{1401 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypePointer, .{
1403 .id_result = result_id,1402 .id_result = result_id,
1404 .storage_class = storage_class,1403 .storage_class = storage_class,
...@@ -1503,10 +1502,13 @@ const NavGen = struct {...@@ -1503,10 +1502,13 @@ const NavGen = struct {
1503 member_names[layout.padding_index] = "(padding)";1502 member_names[layout.padding_index] = "(padding)";
1504 }1503 }
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
1507 const type_name = try self.resolveTypeName(ty);1508 const type_name = try self.resolveTypeName(ty);
1508 defer self.gpa.free(type_name);1509 defer self.gpa.free(type_name);
1509 try self.spv.debugName(result_id, type_name);1510 try self.spv.debugName(result_id, type_name);
1511
1510 return result_id;1512 return result_id;
1511 }1513 }
15121514
...@@ -1700,10 +1702,13 @@ const NavGen = struct {...@@ -1700,10 +1702,13 @@ const NavGen = struct {
1700 }1702 }
17011703
1702 const size_ty_id = try self.resolveType(Type.usize, .direct);1704 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,
1704 &.{ ptr_ty_id, size_ty_id },1708 &.{ ptr_ty_id, size_ty_id },
1705 &.{ "ptr", "len" },1709 &.{ "ptr", "len" },
1706 );1710 );
1711 return result_id;
1707 },1712 },
1708 .vector => {1713 .vector => {
1709 const elem_ty = ty.childType(zcu);1714 const elem_ty = ty.childType(zcu);
...@@ -1730,10 +1735,13 @@ const NavGen = struct {...@@ -1730,10 +1735,13 @@ const NavGen = struct {
1730 member_index += 1;1735 member_index += 1;
1731 }1736 }
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
1734 const type_name = try self.resolveTypeName(ty);1741 const type_name = try self.resolveTypeName(ty);
1735 defer self.gpa.free(type_name);1742 defer self.gpa.free(type_name);
1736 try self.spv.debugName(result_id, type_name);1743 try self.spv.debugName(result_id, type_name);
1744
1737 return result_id;1745 return result_id;
1738 },1746 },
1739 .struct_type => ip.loadStructType(ty.toIntern()),1747 .struct_type => ip.loadStructType(ty.toIntern()),
...@@ -1750,7 +1758,9 @@ const NavGen = struct {...@@ -1750,7 +1758,9 @@ const NavGen = struct {
1750 var member_names = std.ArrayList([]const u8).init(self.gpa);1758 var member_names = std.ArrayList([]const u8).init(self.gpa);
1751 defer member_names.deinit();1759 defer member_names.deinit();
17521760
1761 var index: u32 = 0;
1753 var it = struct_type.iterateRuntimeOrder(ip);1762 var it = struct_type.iterateRuntimeOrder(ip);
1763 const result_id = self.spv.allocId();
1754 while (it.next()) |field_index| {1764 while (it.next()) |field_index| {
1755 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);1765 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1756 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {1766 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
...@@ -1758,16 +1768,25 @@ const NavGen = struct {...@@ -1758,16 +1768,25 @@ const NavGen = struct {
1758 continue;1768 continue;
1759 }1769 }
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 }
1761 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse1776 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
1762 try ip.getOrPutStringFmt(zcu.gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);1777 try ip.getOrPutStringFmt(zcu.gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);
1763 try member_types.append(try self.resolveType(field_ty, .indirect));1778 try member_types.append(try self.resolveType(field_ty, .indirect));
1764 try member_names.append(field_name.toSlice(ip));1779 try member_names.append(field_name.toSlice(ip));
1780
1781 index += 1;
1765 }1782 }
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
1768 const type_name = try self.resolveTypeName(ty);1786 const type_name = try self.resolveTypeName(ty);
1769 defer self.gpa.free(type_name);1787 defer self.gpa.free(type_name);
1770 try self.spv.debugName(result_id, type_name);1788 try self.spv.debugName(result_id, type_name);
1789
1771 return result_id;1790 return result_id;
1772 },1791 },
1773 .optional => {1792 .optional => {
...@@ -1787,10 +1806,13 @@ const NavGen = struct {...@@ -1787,10 +1806,13 @@ const NavGen = struct {
17871806
1788 const bool_ty_id = try self.resolveType(Type.bool, .indirect);1807 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,
1791 &.{ payload_ty_id, bool_ty_id },1812 &.{ payload_ty_id, bool_ty_id },
1792 &.{ "payload", "valid" },1813 &.{ "payload", "valid" },
1793 );1814 );
1815 return result_id;
1794 },1816 },
1795 .@"union" => return try self.resolveUnionType(ty),1817 .@"union" => return try self.resolveUnionType(ty),
1796 .error_set => return try self.resolveType(Type.u16, repr),1818 .error_set => return try self.resolveType(Type.u16, repr),
...@@ -1819,7 +1841,9 @@ const NavGen = struct {...@@ -1819,7 +1841,9 @@ const NavGen = struct {
1819 // TODO: ABI padding?1841 // TODO: ABI padding?
1820 }1842 }
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;
1823 },1847 },
1824 .@"opaque" => {1848 .@"opaque" => {
1825 const type_name = try self.resolveTypeName(ty);1849 const type_name = try self.resolveTypeName(ty);
...@@ -1849,7 +1873,7 @@ const NavGen = struct {...@@ -1849,7 +1873,7 @@ const NavGen = struct {
1849 const target = self.getTarget();1873 const target = self.getTarget();
1850 return switch (as) {1874 return switch (as) {
1851 .generic => switch (target.os.tag) {1875 .generic => switch (target.os.tag) {
1852 .vulkan => .Private,1876 .vulkan => .Function,
1853 .opencl => .Generic,1877 .opencl => .Generic,
1854 else => unreachable,1878 else => unreachable,
1855 },1879 },
...@@ -1861,6 +1885,7 @@ const NavGen = struct {...@@ -1861,6 +1885,7 @@ const NavGen = struct {
1861 else => unreachable,1885 else => unreachable,
1862 },1886 },
1863 .constant => .UniformConstant,1887 .constant => .UniformConstant,
1888 .push_constant => .PushConstant,
1864 .input => .Input,1889 .input => .Input,
1865 .output => .Output,1890 .output => .Output,
1866 .uniform => .Uniform,1891 .uniform => .Uniform,
...@@ -2958,10 +2983,8 @@ const NavGen = struct {...@@ -2958,10 +2983,8 @@ const NavGen = struct {
2958 const spv_err_decl_index = try self.spv.allocDecl(.global);2983 const spv_err_decl_index = try self.spv.allocDecl(.global);
2959 try self.spv.declareDeclDeps(spv_err_decl_index, &.{});2984 try self.spv.declareDeclDeps(spv_err_decl_index, &.{});
29602985
2961 const push_constant_struct_ty_id = try self.spv.structType(2986 const push_constant_struct_ty_id = self.spv.allocId();
2962 &.{ptr_anyerror_ty_id},2987 try self.spv.structType(push_constant_struct_ty_id, &.{ptr_anyerror_ty_id}, &.{"error_out_ptr"});
2963 &.{"error_out_ptr"},
2964 );
2965 try self.spv.decorate(push_constant_struct_ty_id, .Block);2988 try self.spv.decorate(push_constant_struct_ty_id, .Block);
2966 try self.spv.decorateMember(push_constant_struct_ty_id, 0, .{ .Offset = .{ .byte_offset = 0 } });2989 try self.spv.decorateMember(push_constant_struct_ty_id, 0, .{ .Offset = .{ .byte_offset = 0 } });
29672990
...@@ -3145,15 +3168,15 @@ const NavGen = struct {...@@ -3145,15 +3168,15 @@ const NavGen = struct {
3145 };3168 };
3146 assert(maybe_init_val == null); // TODO3169 assert(maybe_init_val == null); // TODO
31473170
3148 const final_storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");3171 const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");
3149 assert(final_storage_class != .Generic); // These should be instance globals3172 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
3153 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpVariable, .{3176 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpVariable, .{
3154 .id_result_type = ptr_ty_id,3177 .id_result_type = ptr_ty_id,
3155 .id_result = result_id,3178 .id_result = result_id,
3156 .storage_class = final_storage_class,3179 .storage_class = storage_class,
3157 });3180 });
31583181
3159 try self.spv.debugName(result_id, nav.fqn.toSlice(ip));3182 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 {...@@ -402,9 +402,7 @@ pub fn resolveString(self: *Module, string: []const u8) !IdRef {
402 return id;402 return id;
403}403}
404404
405pub fn structType(self: *Module, types: []const IdRef, maybe_names: ?[]const []const u8) !IdRef {405pub fn structType(self: *Module, result_id: IdResult, types: []const IdRef, maybe_names: ?[]const []const u8) !void {
406 const result_id = self.allocId();
407
408 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeStruct, .{406 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeStruct, .{
409 .id_result = result_id,407 .id_result = result_id,
410 .id_ref = types,408 .id_ref = types,
...@@ -416,8 +414,6 @@ pub fn structType(self: *Module, types: []const IdRef, maybe_names: ?[]const []c...@@ -416,8 +414,6 @@ pub fn structType(self: *Module, types: []const IdRef, maybe_names: ?[]const []c
416 try self.memberDebugName(result_id, @intCast(i), name);414 try self.memberDebugName(result_id, @intCast(i), name);
417 }415 }
418 }416 }
419
420 return result_id;
421}417}
422418
423pub fn boolType(self: *Module) !IdRef {419pub fn boolType(self: *Module) !IdRef {
src/link/SpirV.zig+1-1
...@@ -296,7 +296,7 @@ fn writeCapabilities(spv: *SpvModule, target: std.Target) !void {...@@ -296,7 +296,7 @@ fn writeCapabilities(spv: *SpvModule, target: std.Target) !void {
296 // TODO: Integrate with a hypothetical feature system296 // TODO: Integrate with a hypothetical feature system
297 const caps: []const spec.Capability = switch (target.os.tag) {297 const caps: []const spec.Capability = switch (target.os.tag) {
298 .opencl => &.{ .Kernel, .Addresses, .Int8, .Int16, .Int64, .Float64, .Float16, .Vector16, .GenericPointer },298 .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 },
300 else => unreachable,300 else => unreachable,
301 };301 };
302302
src/target.zig+1-1
...@@ -418,7 +418,7 @@ pub fn arePointersLogical(target: std.Target, as: AddressSpace) bool {...@@ -418,7 +418,7 @@ pub fn arePointersLogical(target: std.Target, as: AddressSpace) bool {
418 .global => false,418 .global => false,
419 // TODO: Allowed with VK_KHR_variable_pointers.419 // TODO: Allowed with VK_KHR_variable_pointers.
420 .shared => true,420 .shared => true,
421 .constant, .local, .input, .output, .uniform => true,421 .constant, .local, .input, .output, .uniform, .push_constant => true,
422 else => unreachable,422 else => unreachable,
423 };423 };
424}424}