Commit 112acb1bda
Changed files (1)
src
codegen
src/codegen/spirv/TypeConstantCache.zig
@@ -28,6 +28,9 @@ map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
items: std.MultiArrayList(Item) = .{},
extra: std.ArrayListUnmanaged(u32) = .{},
+string_bytes: std.ArrayListUnmanaged(u8) = .{},
+strings: std.AutoArrayHashMapUnmanaged(void, u32) = .{},
+
const Item = struct {
tag: Tag,
/// The result-id that this item uses.
@@ -74,6 +77,10 @@ const Tag = enum {
/// Simple structure type that does not have any decorations.
/// data is payload to SimpleStructType
type_struct_simple,
+ /// Simple structure type that does not have any decorations, but does
+ /// have member names trailing.
+ /// data is payload to SimpleStructType
+ type_struct_simple_with_member_names,
// -- Values
/// Value of type u8
@@ -124,7 +131,10 @@ const Tag = enum {
/// Trailing:
/// - [members_len]Ref: Member types.
+ /// - [members_len]String: Member names, -- ONLY if the tag is type_struct_simple_with_member_names
const SimpleStructType = struct {
+ /// (optional) The name of the struct.
+ name: String,
/// Number of members that this struct has.
members_len: u32,
};
@@ -252,8 +262,16 @@ pub const Key = union(enum) {
pub const StructType = struct {
// TODO: Decorations.
+ /// The name of the structure. Can be `.none`.
+ name: String,
/// The type of each member.
member_types: []const Ref,
+ /// Name for each member. May be omitted.
+ member_names: ?[]const String = null,
+
+ fn memberNames(self: @This()) []const String {
+ return if (self.member_names) |member_names| member_names else &.{};
+ }
};
pub const Int = struct {
@@ -323,9 +341,13 @@ pub const Key = union(enum) {
}
},
.struct_type => |struct_type| {
+ std.hash.autoHash(&hasher, struct_type.name);
for (struct_type.member_types) |member_type| {
std.hash.autoHash(&hasher, member_type);
}
+ for (struct_type.memberNames()) |member_name| {
+ std.hash.autoHash(&hasher, member_name);
+ }
},
inline else => |key| std.hash.autoHash(&hasher, key),
}
@@ -347,7 +369,9 @@ pub const Key = union(enum) {
},
.struct_type => |a_struct| {
const b_struct = b.struct_type;
- return std.mem.eql(Ref, a_struct.member_types, b_struct.member_types);
+ return a_struct.name == b_struct.name and
+ std.mem.eql(Ref, a_struct.member_types, b_struct.member_types) and
+ std.mem.eql(String, a_struct.memberNames(), b_struct.memberNames());
},
// TODO: Unroll?
else => std.meta.eql(a, b),
@@ -381,6 +405,8 @@ pub fn deinit(self: *Self, spv: *const Module) void {
self.map.deinit(spv.gpa);
self.items.deinit(spv.gpa);
self.extra.deinit(spv.gpa);
+ self.string_bytes.deinit(spv.gpa);
+ self.strings.deinit(spv.gpa);
}
/// Actually materialize the database into spir-v instructions.
@@ -475,6 +501,14 @@ fn emit(
for (struct_type.member_types) |member_type| {
section.writeOperand(IdResult, self.resultId(member_type));
}
+ if (self.getString(struct_type.name)) |name| {
+ try spv.debugName(result_id, "{s}", .{name});
+ }
+ for (struct_type.memberNames(), 0..) |member_name, i| {
+ if (self.getString(member_name)) |name| {
+ try spv.memberDebugName(result_id, @intCast(u32, i), "{s}", .{name});
+ }
+ }
// TODO: Decorations?
},
.int => |int| {
@@ -589,15 +623,25 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {
},
.struct_type => |struct_type| blk: {
const extra = try self.addExtra(spv, Tag.SimpleStructType{
+ .name = struct_type.name,
.members_len = @intCast(u32, struct_type.member_types.len),
});
try self.extra.appendSlice(spv.gpa, @ptrCast([]const u32, struct_type.member_types));
- break :blk Item{
- .tag = .type_struct_simple,
- .result_id = result_id,
- .data = extra,
- };
+ if (struct_type.member_names) |member_names| {
+ try self.extra.appendSlice(spv.gpa, @ptrCast([]const u32, member_names));
+ break :blk Item{
+ .tag = .type_struct_simple_with_member_names,
+ .result_id = result_id,
+ .data = extra,
+ };
+ } else {
+ break :blk Item{
+ .tag = .type_struct_simple,
+ .result_id = result_id,
+ .data = extra,
+ };
+ }
},
.int => |int| blk: {
const int_type = self.lookup(int.ty).int_type;
@@ -739,7 +783,22 @@ pub fn lookup(self: *const Self, ref: Ref) Key {
const member_types = @ptrCast([]const Ref, self.extra.items[payload.trail..][0..payload.data.members_len]);
return .{
.struct_type = .{
+ .name = payload.data.name,
.member_types = member_types,
+ .member_names = null,
+ },
+ };
+ },
+ .type_struct_simple_with_member_names => {
+ const payload = self.extraDataTrail(Tag.SimpleStructType, data);
+ const trailing = self.extra.items[payload.trail..];
+ const member_types = @ptrCast([]const Ref, trailing[0..payload.data.members_len]);
+ const member_names = @ptrCast([]const String, trailing[payload.data.members_len..][0..payload.data.members_len]);
+ return .{
+ .struct_type = .{
+ .name = payload.data.name,
+ .member_types = member_types,
+ .member_names = member_names,
},
};
},
@@ -822,6 +881,7 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) !u32 {
i32 => @bitCast(u32, field_val),
Ref => @enumToInt(field_val),
StorageClass => @enumToInt(field_val),
+ String => @enumToInt(field_val),
else => @compileError("Invalid type: " ++ @typeName(field.type)),
};
self.extra.appendAssumeCapacity(word);
@@ -843,6 +903,7 @@ fn extraDataTrail(self: Self, comptime T: type, offset: u32) struct { data: T, t
i32 => @bitCast(i32, word),
Ref => @intToEnum(Ref, word),
StorageClass => @intToEnum(StorageClass, word),
+ String => @intToEnum(String, word),
else => @compileError("Invalid type: " ++ @typeName(field.type)),
};
}
@@ -851,3 +912,49 @@ fn extraDataTrail(self: Self, comptime T: type, offset: u32) struct { data: T, t
.trail = offset + @intCast(u32, fields.len),
};
}
+
+/// Represents a reference to some null-terminated string.
+pub const String = enum(u32) {
+ none = std.math.maxInt(u32),
+ _,
+
+ pub const Adapter = struct {
+ self: *const Self,
+
+ pub fn eql(ctx: @This(), a: []const u8, _: void, b_index: usize) bool {
+ const offset = ctx.self.string_map.values()[b_index];
+ const b = std.mem.sliceTo(ctx.self.string_bytes.items[offset..], 0);
+ return std.mem.eql(u8, a, b);
+ }
+
+ pub fn hash(ctx: @This(), a: []const u8) u32 {
+ _ = ctx;
+ const hasher = std.hash.Wyhash.init(0);
+ hasher.update(a);
+ return @truncate(u32, hasher.final());
+ }
+ };
+};
+
+/// Add a string to the cache. Must not contain any 0 values.
+pub fn addString(self: *Self, spv: *Module, str: []const u8) String {
+ assert(std.mem.indexOfScalar(u8, str, 0) == null);
+ const adapter = String.Adapter{ .self = self };
+ const entry = try self.strings.getOrPutAdapted(spv.gpa, str, adapter);
+ if (!entry.found_existing) {
+ const offset = self.string_bytes.items.len;
+ try self.string_bytes.ensureUnusedCapacity(1 + str.len);
+ self.string_bytes.appendAssumeCapacity(str);
+ self.string_bytes.append(0);
+ entry.value_ptr.* = offset;
+ }
+
+ return @intToEnum(String, entry.index);
+}
+
+pub fn getString(self: *const Self, ref: String) ?[]const u8 {
+ return switch (ref) {
+ .none => null,
+ else => std.mem.sliceTo(self.string_bytes.items[self.strings.values()[@enumToInt(ref)]..], 0),
+ };
+}