| ... | @@ -28,6 +28,9 @@ map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, | ... | @@ -28,6 +28,9 @@ map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, |
| 28 | items: std.MultiArrayList(Item) = .{}, | 28 | items: std.MultiArrayList(Item) = .{}, |
| 29 | extra: std.ArrayListUnmanaged(u32) = .{}, | 29 | extra: std.ArrayListUnmanaged(u32) = .{}, |
| 30 | | 30 | |
| | 31 | string_bytes: std.ArrayListUnmanaged(u8) = .{}, |
| | 32 | strings: std.AutoArrayHashMapUnmanaged(void, u32) = .{}, |
| | 33 | |
| 31 | const Item = struct { | 34 | const 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 SimpleStructType | 78 | /// 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, |
| 77 | | 84 | |
| 78 | // -- Values | 85 | // -- Values |
| 79 | /// Value of type u8 | 86 | /// Value of type u8 |
| ... | @@ -124,7 +131,10 @@ const Tag = enum { | ... | @@ -124,7 +131,10 @@ const Tag = enum { |
| 124 | | 131 | |
| 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) { |
| 252 | | 262 | |
| 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 | }; |
| 258 | | 276 | |
| 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 | } |
| 385 | | 411 | |
| 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)); |
| 595 | | 630 | |
| 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. |
| | 917 | pub 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. |
| | 940 | pub 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 | |
| | 955 | pub 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 | } |