diff options
| author | Robin Voetter <robin@voetter.nl> | 2024-04-05 00:30:06 +0200 |
|---|---|---|
| committer | Robin Voetter <robin@voetter.nl> | 2024-04-06 13:37:39 +0200 |
| commit | 97a67762ba1fcc363656a59af10a3031332cbd62 (patch) | |
| tree | 7e333b5d505b6886dae97ca1f1a734690c588712 /src/codegen/spirv/Module.zig | |
| parent | 188922a5448417d1939023b1eab7f70fa1953dde (diff) | |
| download | zig-97a67762ba1fcc363656a59af10a3031332cbd62.tar.gz zig-97a67762ba1fcc363656a59af10a3031332cbd62.zip | |
spirv: remove cache usage for types
Diffstat (limited to 'src/codegen/spirv/Module.zig')
| -rw-r--r-- | src/codegen/spirv/Module.zig | 173 |
1 files changed, 123 insertions, 50 deletions
diff --git a/src/codegen/spirv/Module.zig b/src/codegen/spirv/Module.zig index eb1b2d41a0..73374389b7 100644 --- a/src/codegen/spirv/Module.zig +++ b/src/codegen/spirv/Module.zig @@ -23,7 +23,6 @@ const Section = @import("Section.zig"); const Cache = @import("Cache.zig"); pub const CacheKey = Cache.Key; pub const CacheRef = Cache.Ref; -pub const CacheString = Cache.String; /// This structure represents a function that isc in-progress of being emitted. /// Commonly, the contents of this structure will be merged with the appropriate @@ -98,7 +97,7 @@ pub const EntryPoint = struct { /// The declaration that should be exported. decl_index: Decl.Index, /// The name of the kernel to be exported. - name: CacheString, + name: []const u8, /// Calling Convention execution_model: spec.ExecutionModel, }; @@ -106,6 +105,9 @@ pub const EntryPoint = struct { /// A general-purpose allocator which may be used to allocate resources for this module gpa: Allocator, +/// Arena for things that need to live for the length of this program. +arena: std.heap.ArenaAllocator, + /// Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module". sections: struct { /// Capability instructions @@ -143,15 +145,26 @@ sections: struct { /// SPIR-V instructions return result-ids. This variable holds the module-wide counter for these. next_result_id: Word, -/// Cache for results of OpString instructions for module file names fed to OpSource. -/// Since OpString is pretty much only used for those, we don't need to keep track of all strings, -/// just the ones for OpLine. Note that OpLine needs the result of OpString, and not that of OpSource. -source_file_names: std.AutoArrayHashMapUnmanaged(CacheString, IdRef) = .{}, +/// Cache for results of OpString instructions. +strings: std.StringArrayHashMapUnmanaged(IdRef) = .{}, /// SPIR-V type- and constant cache. This structure is used to store information about these in a more /// efficient manner. cache: Cache = .{}, +/// Some types shouldn't be emitted more than one time, but cannot be caught by +/// the `intern_map` during codegen. Sometimes, IDs are compared to check if +/// types are the same, so we can't delay until the dedup pass. Therefore, +/// this is an ad-hoc structure to cache types where required. +/// According to the SPIR-V specification, section 2.8, this includes all non-aggregate +/// non-pointer types. +cache2: struct { + bool_type: ?IdRef = null, + void_type: ?IdRef = null, + int_types: std.AutoHashMapUnmanaged(std.builtin.Type.Int, IdRef) = .{}, + float_types: std.AutoHashMapUnmanaged(std.builtin.Type.Float, IdRef) = .{}, +} = .{}, + /// Set of Decls, referred to by Decl.Index. decls: std.ArrayListUnmanaged(Decl) = .{}, @@ -168,6 +181,7 @@ extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, IdRef) = pub fn init(gpa: Allocator) Module { return .{ .gpa = gpa, + .arena = std.heap.ArenaAllocator.init(gpa), .next_result_id = 1, // 0 is an invalid SPIR-V result id, so start counting at 1. }; } @@ -184,15 +198,19 @@ pub fn deinit(self: *Module) void { self.sections.types_globals_constants.deinit(self.gpa); self.sections.functions.deinit(self.gpa); - self.source_file_names.deinit(self.gpa); + self.strings.deinit(self.gpa); self.cache.deinit(self); + self.cache2.int_types.deinit(self.gpa); + self.cache2.float_types.deinit(self.gpa); + self.decls.deinit(self.gpa); self.decl_deps.deinit(self.gpa); self.entry_points.deinit(self.gpa); self.extended_instruction_set.deinit(self.gpa); + self.arena.deinit(); self.* = undefined; } @@ -235,10 +253,6 @@ pub fn resolveId(self: *Module, key: CacheKey) !IdResult { return self.resultId(try self.resolve(key)); } -pub fn resolveString(self: *Module, str: []const u8) !CacheString { - return try self.cache.addString(self, str); -} - fn addEntryPointDeps( self: *Module, decl_index: Decl.Index, @@ -283,7 +297,7 @@ fn entryPoints(self: *Module) !Section { try entry_points.emit(self.gpa, .OpEntryPoint, .{ .execution_model = entry_point.execution_model, .entry_point = entry_point_id, - .name = self.cache.getString(entry_point.name).?, + .name = entry_point.name, .interface = interface.items, }); } @@ -388,51 +402,110 @@ pub fn importInstructionSet(self: *Module, set: spec.InstructionSet) !IdRef { return result_id; } -/// Fetch the result-id of an OpString instruction that encodes the path of the source -/// file of the decl. This function may also emit an OpSource with source-level information regarding -/// the decl. -pub fn resolveSourceFileName(self: *Module, path: []const u8) !IdRef { - const path_ref = try self.resolveString(path); - const result = try self.source_file_names.getOrPut(self.gpa, path_ref); - if (!result.found_existing) { - const file_result_id = self.allocId(); - result.value_ptr.* = file_result_id; - try self.sections.debug_strings.emit(self.gpa, .OpString, .{ - .id_result = file_result_id, - .string = path, - }); +/// Fetch the result-id of an instruction corresponding to a string. +pub fn resolveString(self: *Module, string: []const u8) !IdRef { + if (self.strings.get(string)) |id| { + return id; } - return result.value_ptr.*; + const id = self.allocId(); + try self.strings.put(self.gpa, try self.arena.allocator().dupe(u8, string), id); + + try self.sections.debug_strings.emit(self.gpa, .OpString, .{ + .id_result = id, + .string = string, + }); + + return id; } -pub fn intType(self: *Module, signedness: std.builtin.Signedness, bits: u16) !CacheRef { - return try self.resolve(.{ .int_type = .{ - .signedness = signedness, - .bits = bits, - } }); +pub fn structType(self: *Module, types: []const IdRef, maybe_names: ?[]const []const u8) !IdRef { + const result_id = self.allocId(); + + try self.sections.types_globals_constants.emit(self.gpa, .OpTypeStruct, .{ + .id_result = result_id, + .id_ref = types, + }); + + if (maybe_names) |names| { + assert(names.len == types.len); + for (names, 0..) |name, i| { + try self.memberDebugName(result_id, @intCast(i), name); + } + } + + return result_id; } -pub fn vectorType(self: *Module, len: u32, elem_ty_ref: CacheRef) !CacheRef { - return try self.resolve(.{ .vector_type = .{ - .component_type = elem_ty_ref, - .component_count = len, - } }); +pub fn boolType(self: *Module) !IdRef { + if (self.cache2.bool_type) |id| return id; + + const result_id = self.allocId(); + try self.sections.types_globals_constants.emit(self.gpa, .OpTypeBool, .{ + .id_result = result_id, + }); + self.cache2.bool_type = result_id; + return result_id; +} + +pub fn voidType(self: *Module) !IdRef { + if (self.cache2.void_type) |id| return id; + + const result_id = self.allocId(); + try self.sections.types_globals_constants.emit(self.gpa, .OpTypeVoid, .{ + .id_result = result_id, + }); + self.cache2.void_type = result_id; + try self.debugName(result_id, "void"); + return result_id; } -pub fn arrayType(self: *Module, len: u32, elem_ty_ref: CacheRef) !CacheRef { - const len_ty_ref = try self.resolve(.{ .int_type = .{ - .signedness = .unsigned, - .bits = 32, - } }); - const len_ref = try self.resolve(.{ .int = .{ - .ty = len_ty_ref, - .value = .{ .uint64 = len }, - } }); - return try self.resolve(.{ .array_type = .{ - .element_type = elem_ty_ref, - .length = len_ref, - } }); +pub fn intType(self: *Module, signedness: std.builtin.Signedness, bits: u16) !IdRef { + assert(bits > 0); + const entry = try self.cache2.int_types.getOrPut(self.gpa, .{ .signedness = signedness, .bits = bits }); + if (!entry.found_existing) { + const result_id = self.allocId(); + entry.value_ptr.* = result_id; + try self.sections.types_globals_constants.emit(self.gpa, .OpTypeInt, .{ + .id_result = result_id, + .width = bits, + .signedness = switch (signedness) { + .signed => 1, + .unsigned => 0, + }, + }); + + switch (signedness) { + .signed => try self.debugNameFmt(result_id, "i{}", .{bits}), + .unsigned => try self.debugNameFmt(result_id, "u{}", .{bits}), + } + } + return entry.value_ptr.*; +} + +pub fn floatType(self: *Module, bits: u16) !IdRef { + assert(bits > 0); + const entry = try self.cache2.float_types.getOrPut(self.gpa, .{ .bits = bits }); + if (!entry.found_existing) { + const result_id = self.allocId(); + entry.value_ptr.* = result_id; + try self.sections.types_globals_constants.emit(self.gpa, .OpTypeFloat, .{ + .id_result = result_id, + .width = bits, + }); + try self.debugNameFmt(result_id, "f{}", .{bits}); + } + return entry.value_ptr.*; +} + +pub fn vectorType(self: *Module, len: u32, child_id: IdRef) !IdRef { + const result_id = self.allocId(); + try self.sections.types_globals_constants.emit(self.gpa, .OpTypeVector, .{ + .id_result = result_id, + .component_type = child_id, + .component_count = len, + }); + return result_id; } pub fn constUndef(self: *Module, ty_id: IdRef) !IdRef { @@ -526,7 +599,7 @@ pub fn declareEntryPoint( ) !void { try self.entry_points.append(self.gpa, .{ .decl_index = decl_index, - .name = try self.resolveString(name), + .name = try self.arena.allocator().dupe(u8, name), .execution_model = execution_model, }); } |
