authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-05-29 19:51:01+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-05-30 19:43:37+02:00
log112acb1bda04c16bf1d25f7fbbe9855c35725347
treeac7489db734477873413301f4060c34df762e4b9
parenta72179fed0f20619f6787c760fae00ece16e9d20
signaturelock-open Commit is signed but in an unrecognized format.

spirv: cache strings for debug names


1 files changed, 113 insertions(+), 6 deletions(-)

src/codegen/spirv/TypeConstantCache.zig+113-6
...@@ -28,6 +28,9 @@ map: std.AutoArrayHashMapUnmanaged(void, void) = .{},...@@ -28,6 +28,9 @@ map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
28items: std.MultiArrayList(Item) = .{},28items: std.MultiArrayList(Item) = .{},
29extra: std.ArrayListUnmanaged(u32) = .{},29extra: std.ArrayListUnmanaged(u32) = .{},
3030
31string_bytes: std.ArrayListUnmanaged(u8) = .{},
32strings: std.AutoArrayHashMapUnmanaged(void, u32) = .{},
33
31const Item = struct {34const Item = struct {
32 tag: Tag,35 tag: Tag,
33 /// The result-id that this item uses.36 /// The result-id that this item uses.
...@@ -74,6 +77,10 @@ const Tag = enum {...@@ -74,6 +77,10 @@ const Tag = enum {
74 /// Simple structure type that does not have any decorations.77 /// Simple structure type that does not have any decorations.
75 /// data is payload to SimpleStructType78 /// data is payload to SimpleStructType
76 type_struct_simple,79 type_struct_simple,
80 /// Simple structure type that does not have any decorations, but does
81 /// have member names trailing.
82 /// data is payload to SimpleStructType
83 type_struct_simple_with_member_names,
7784
78 // -- Values85 // -- Values
79 /// Value of type u886 /// Value of type u8
...@@ -124,7 +131,10 @@ const Tag = enum {...@@ -124,7 +131,10 @@ const Tag = enum {
124131
125 /// Trailing:132 /// Trailing:
126 /// - [members_len]Ref: Member types.133 /// - [members_len]Ref: Member types.
134 /// - [members_len]String: Member names, -- ONLY if the tag is type_struct_simple_with_member_names
127 const SimpleStructType = struct {135 const SimpleStructType = struct {
136 /// (optional) The name of the struct.
137 name: String,
128 /// Number of members that this struct has.138 /// Number of members that this struct has.
129 members_len: u32,139 members_len: u32,
130 };140 };
...@@ -252,8 +262,16 @@ pub const Key = union(enum) {...@@ -252,8 +262,16 @@ pub const Key = union(enum) {
252262
253 pub const StructType = struct {263 pub const StructType = struct {
254 // TODO: Decorations.264 // TODO: Decorations.
265 /// The name of the structure. Can be `.none`.
266 name: String,
255 /// The type of each member.267 /// The type of each member.
256 member_types: []const Ref,268 member_types: []const Ref,
269 /// Name for each member. May be omitted.
270 member_names: ?[]const String = null,
271
272 fn memberNames(self: @This()) []const String {
273 return if (self.member_names) |member_names| member_names else &.{};
274 }
257 };275 };
258276
259 pub const Int = struct {277 pub const Int = struct {
...@@ -323,9 +341,13 @@ pub const Key = union(enum) {...@@ -323,9 +341,13 @@ pub const Key = union(enum) {
323 }341 }
324 },342 },
325 .struct_type => |struct_type| {343 .struct_type => |struct_type| {
344 std.hash.autoHash(&hasher, struct_type.name);
326 for (struct_type.member_types) |member_type| {345 for (struct_type.member_types) |member_type| {
327 std.hash.autoHash(&hasher, member_type);346 std.hash.autoHash(&hasher, member_type);
328 }347 }
348 for (struct_type.memberNames()) |member_name| {
349 std.hash.autoHash(&hasher, member_name);
350 }
329 },351 },
330 inline else => |key| std.hash.autoHash(&hasher, key),352 inline else => |key| std.hash.autoHash(&hasher, key),
331 }353 }
...@@ -347,7 +369,9 @@ pub const Key = union(enum) {...@@ -347,7 +369,9 @@ pub const Key = union(enum) {
347 },369 },
348 .struct_type => |a_struct| {370 .struct_type => |a_struct| {
349 const b_struct = b.struct_type;371 const b_struct = b.struct_type;
350 return std.mem.eql(Ref, a_struct.member_types, b_struct.member_types);372 return a_struct.name == b_struct.name and
373 std.mem.eql(Ref, a_struct.member_types, b_struct.member_types) and
374 std.mem.eql(String, a_struct.memberNames(), b_struct.memberNames());
351 },375 },
352 // TODO: Unroll?376 // TODO: Unroll?
353 else => std.meta.eql(a, b),377 else => std.meta.eql(a, b),
...@@ -381,6 +405,8 @@ pub fn deinit(self: *Self, spv: *const Module) void {...@@ -381,6 +405,8 @@ pub fn deinit(self: *Self, spv: *const Module) void {
381 self.map.deinit(spv.gpa);405 self.map.deinit(spv.gpa);
382 self.items.deinit(spv.gpa);406 self.items.deinit(spv.gpa);
383 self.extra.deinit(spv.gpa);407 self.extra.deinit(spv.gpa);
408 self.string_bytes.deinit(spv.gpa);
409 self.strings.deinit(spv.gpa);
384}410}
385411
386/// Actually materialize the database into spir-v instructions.412/// Actually materialize the database into spir-v instructions.
...@@ -475,6 +501,14 @@ fn emit(...@@ -475,6 +501,14 @@ fn emit(
475 for (struct_type.member_types) |member_type| {501 for (struct_type.member_types) |member_type| {
476 section.writeOperand(IdResult, self.resultId(member_type));502 section.writeOperand(IdResult, self.resultId(member_type));
477 }503 }
504 if (self.getString(struct_type.name)) |name| {
505 try spv.debugName(result_id, "{s}", .{name});
506 }
507 for (struct_type.memberNames(), 0..) |member_name, i| {
508 if (self.getString(member_name)) |name| {
509 try spv.memberDebugName(result_id, @intCast(u32, i), "{s}", .{name});
510 }
511 }
478 // TODO: Decorations?512 // TODO: Decorations?
479 },513 },
480 .int => |int| {514 .int => |int| {
...@@ -589,15 +623,25 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {...@@ -589,15 +623,25 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {
589 },623 },
590 .struct_type => |struct_type| blk: {624 .struct_type => |struct_type| blk: {
591 const extra = try self.addExtra(spv, Tag.SimpleStructType{625 const extra = try self.addExtra(spv, Tag.SimpleStructType{
626 .name = struct_type.name,
592 .members_len = @intCast(u32, struct_type.member_types.len),627 .members_len = @intCast(u32, struct_type.member_types.len),
593 });628 });
594 try self.extra.appendSlice(spv.gpa, @ptrCast([]const u32, struct_type.member_types));629 try self.extra.appendSlice(spv.gpa, @ptrCast([]const u32, struct_type.member_types));
595630
596 break :blk Item{631 if (struct_type.member_names) |member_names| {
597 .tag = .type_struct_simple,632 try self.extra.appendSlice(spv.gpa, @ptrCast([]const u32, member_names));
598 .result_id = result_id,633 break :blk Item{
599 .data = extra,634 .tag = .type_struct_simple_with_member_names,
600 };635 .result_id = result_id,
636 .data = extra,
637 };
638 } else {
639 break :blk Item{
640 .tag = .type_struct_simple,
641 .result_id = result_id,
642 .data = extra,
643 };
644 }
601 },645 },
602 .int => |int| blk: {646 .int => |int| blk: {
603 const int_type = self.lookup(int.ty).int_type;647 const int_type = self.lookup(int.ty).int_type;
...@@ -739,7 +783,22 @@ pub fn lookup(self: *const Self, ref: Ref) Key {...@@ -739,7 +783,22 @@ pub fn lookup(self: *const Self, ref: Ref) Key {
739 const member_types = @ptrCast([]const Ref, self.extra.items[payload.trail..][0..payload.data.members_len]);783 const member_types = @ptrCast([]const Ref, self.extra.items[payload.trail..][0..payload.data.members_len]);
740 return .{784 return .{
741 .struct_type = .{785 .struct_type = .{
786 .name = payload.data.name,
742 .member_types = member_types,787 .member_types = member_types,
788 .member_names = null,
789 },
790 };
791 },
792 .type_struct_simple_with_member_names => {
793 const payload = self.extraDataTrail(Tag.SimpleStructType, data);
794 const trailing = self.extra.items[payload.trail..];
795 const member_types = @ptrCast([]const Ref, trailing[0..payload.data.members_len]);
796 const member_names = @ptrCast([]const String, trailing[payload.data.members_len..][0..payload.data.members_len]);
797 return .{
798 .struct_type = .{
799 .name = payload.data.name,
800 .member_types = member_types,
801 .member_names = member_names,
743 },802 },
744 };803 };
745 },804 },
...@@ -822,6 +881,7 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) !u32 {...@@ -822,6 +881,7 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) !u32 {
822 i32 => @bitCast(u32, field_val),881 i32 => @bitCast(u32, field_val),
823 Ref => @enumToInt(field_val),882 Ref => @enumToInt(field_val),
824 StorageClass => @enumToInt(field_val),883 StorageClass => @enumToInt(field_val),
884 String => @enumToInt(field_val),
825 else => @compileError("Invalid type: " ++ @typeName(field.type)),885 else => @compileError("Invalid type: " ++ @typeName(field.type)),
826 };886 };
827 self.extra.appendAssumeCapacity(word);887 self.extra.appendAssumeCapacity(word);
...@@ -843,6 +903,7 @@ fn extraDataTrail(self: Self, comptime T: type, offset: u32) struct { data: T, t...@@ -843,6 +903,7 @@ fn extraDataTrail(self: Self, comptime T: type, offset: u32) struct { data: T, t
843 i32 => @bitCast(i32, word),903 i32 => @bitCast(i32, word),
844 Ref => @intToEnum(Ref, word),904 Ref => @intToEnum(Ref, word),
845 StorageClass => @intToEnum(StorageClass, word),905 StorageClass => @intToEnum(StorageClass, word),
906 String => @intToEnum(String, word),
846 else => @compileError("Invalid type: " ++ @typeName(field.type)),907 else => @compileError("Invalid type: " ++ @typeName(field.type)),
847 };908 };
848 }909 }
...@@ -851,3 +912,49 @@ fn extraDataTrail(self: Self, comptime T: type, offset: u32) struct { data: T, t...@@ -851,3 +912,49 @@ fn extraDataTrail(self: Self, comptime T: type, offset: u32) struct { data: T, t
851 .trail = offset + @intCast(u32, fields.len),912 .trail = offset + @intCast(u32, fields.len),
852 };913 };
853}914}
915
916/// Represents a reference to some null-terminated string.
917pub const String = enum(u32) {
918 none = std.math.maxInt(u32),
919 _,
920
921 pub const Adapter = struct {
922 self: *const Self,
923
924 pub fn eql(ctx: @This(), a: []const u8, _: void, b_index: usize) bool {
925 const offset = ctx.self.string_map.values()[b_index];
926 const b = std.mem.sliceTo(ctx.self.string_bytes.items[offset..], 0);
927 return std.mem.eql(u8, a, b);
928 }
929
930 pub fn hash(ctx: @This(), a: []const u8) u32 {
931 _ = ctx;
932 const hasher = std.hash.Wyhash.init(0);
933 hasher.update(a);
934 return @truncate(u32, hasher.final());
935 }
936 };
937};
938
939/// Add a string to the cache. Must not contain any 0 values.
940pub fn addString(self: *Self, spv: *Module, str: []const u8) String {
941 assert(std.mem.indexOfScalar(u8, str, 0) == null);
942 const adapter = String.Adapter{ .self = self };
943 const entry = try self.strings.getOrPutAdapted(spv.gpa, str, adapter);
944 if (!entry.found_existing) {
945 const offset = self.string_bytes.items.len;
946 try self.string_bytes.ensureUnusedCapacity(1 + str.len);
947 self.string_bytes.appendAssumeCapacity(str);
948 self.string_bytes.append(0);
949 entry.value_ptr.* = offset;
950 }
951
952 return @intToEnum(String, entry.index);
953}
954
955pub fn getString(self: *const Self, ref: String) ?[]const u8 {
956 return switch (ref) {
957 .none => null,
958 else => std.mem.sliceTo(self.string_bytes.items[self.strings.values()[@enumToInt(ref)]..], 0),
959 };
960}