spirv: basic setup for using new type constant cache

This commit is contained in:
Robin Voetter
2023-05-29 13:19:08 +02:00
parent 96a66d14a1
commit b2a984cda6
3 changed files with 229 additions and 103 deletions

View File

@@ -21,6 +21,7 @@ const IdResultType = spec.IdResultType;
const Section = @import("Section.zig");
const Type = @import("type.zig").Type;
pub const TypeConstantCache = @import("TypeConstantCache.zig");
const TypeCache = std.ArrayHashMapUnmanaged(Type, IdResultType, Type.ShallowHashContext32, true);
@@ -125,8 +126,16 @@ sections: struct {
// OpModuleProcessed - skip for now.
/// Annotation instructions (OpDecorate etc).
annotations: Section = .{},
/// Type and constant declarations that are generated by the TypeConstantCache.
types_and_constants: Section = .{},
/// Global variable declarations
/// From this section, OpLine and OpNoLine is allowed.
/// According to the SPIR-V documentation, this section normally
/// also holds type and constant instructions. These are managed
/// via the tc_cache instead, which is the sole structure that
/// manages that section. These will be inserted between this and
/// the previous section when emitting the final binary.
/// TODO: Do we need this section? Globals are also managed with another mechanism.
/// The only thing that needs to be kept here is OpUndef
globals: Section = .{},
/// Type declarations, constants, global variables
/// Below this section, OpLine and OpNoLine is allowed.
types_globals_constants: Section = .{},
@@ -143,11 +152,10 @@ next_result_id: Word,
/// just the ones for OpLine. Note that OpLine needs the result of OpString, and not that of OpSource.
source_file_names: std.StringHashMapUnmanaged(IdRef) = .{},
/// SPIR-V type cache. Note that according to SPIR-V spec section 2.8, Types and Variables, non-pointer
/// non-aggrerate types (which includes matrices and vectors) must have a _unique_ representation in
/// the final binary.
/// Note: Uses ArrayHashMap which is insertion ordered, so that we may refer to other types by index (Type.Ref).
type_cache: TypeCache = .{},
/// SPIR-V type- and constant cache. This structure is used to store information about these in a more
/// efficient manner.
tc_cache: TypeConstantCache = .{},
/// Set of Decls, referred to by Decl.Index.
decls: std.ArrayListUnmanaged(Decl) = .{},
@@ -165,7 +173,7 @@ globals: struct {
globals: std.AutoArrayHashMapUnmanaged(Decl.Index, Global) = .{},
/// This pseudo-section contains the initialization code for all the globals. Instructions from
/// here are reordered when flushing the module. Its contents should be part of the
/// `types_globals_constants` SPIR-V section.
/// `types_globals_constants` SPIR-V section when the module is emitted.
section: Section = .{},
} = .{},
@@ -184,12 +192,11 @@ pub fn deinit(self: *Module) void {
self.sections.debug_strings.deinit(self.gpa);
self.sections.debug_names.deinit(self.gpa);
self.sections.annotations.deinit(self.gpa);
self.sections.types_and_constants(self.gpa);
self.sections.types_globals_constants.deinit(self.gpa);
self.sections.globals.deinit(self.gpa);
self.sections.functions.deinit(self.gpa);
self.source_file_names.deinit(self.gpa);
self.type_cache.deinit(self.gpa);
self.tc_cache.deinit(self);
self.decls.deinit(self.gpa);
self.decl_deps.deinit(self.gpa);
@@ -216,6 +223,18 @@ pub fn idBound(self: Module) Word {
return self.next_result_id;
}
pub fn resolve(self: *Module, key: TypeConstantCache.Key) !TypeConstantCache.Ref {
return self.tc_cache.resolve(self, key);
}
pub fn resultId(self: *Module, ref: TypeConstantCache.Ref) IdResult {
return self.tc_cache.resultId(ref);
}
pub fn resolveId(self: *Module, key: TypeConstantCache.Key) !IdResult {
return self.resultId(try self.resolve(key));
}
fn orderGlobalsInto(
self: *Module,
decl_index: Decl.Index,
@@ -327,6 +346,9 @@ pub fn flush(self: *Module, file: std.fs.File) !void {
var entry_points = try self.entryPoints();
defer entry_points.deinit(self.gpa);
var types_constants = try self.tc_cache.materialize(self);
defer types_constants.deinit(self.gpa);
// Note: needs to be kept in order according to section 2.3!
const buffers = &[_][]const Word{
&header,
@@ -337,8 +359,8 @@ pub fn flush(self: *Module, file: std.fs.File) !void {
self.sections.debug_strings.toWords(),
self.sections.debug_names.toWords(),
self.sections.annotations.toWords(),
self.sections.types_constants.toWords(),
self.sections.types_globals_constants.toWords(),
types_constants.toWords(),
self.sections.globals.toWords(),
globals.toWords(),
self.sections.functions.toWords(),
};
@@ -891,8 +913,8 @@ pub fn declareEntryPoint(self: *Module, decl_index: Decl.Index, name: []const u8
pub fn debugName(self: *Module, target: IdResult, comptime fmt: []const u8, args: anytype) !void {
const name = try std.fmt.allocPrint(self.gpa, fmt, args);
defer self.gpa.free(name);
try debug.emit(self.gpa, .OpName, .{
.target = result_id,
try self.sections.debug_names.emit(self.gpa, .OpName, .{
.target = target,
.name = name,
});
}