diff options
| author | Robin Voetter <robin@voetter.nl> | 2023-05-29 23:54:09 +0200 |
|---|---|---|
| committer | Robin Voetter <robin@voetter.nl> | 2023-05-30 19:43:37 +0200 |
| commit | 0552a8b11f973fc9621971e2130c25ad3a4af0ad (patch) | |
| tree | 5d9fd2ed5cdc4a8a00b1047dfb0721145d752a2c /src/codegen/spirv/Module.zig | |
| parent | fcb422585c1a9e91933ff998417eb8682a4ffbcc (diff) | |
| download | zig-0552a8b11f973fc9621971e2130c25ad3a4af0ad.tar.gz zig-0552a8b11f973fc9621971e2130c25ad3a4af0ad.zip | |
spirv: translate remaining types
Diffstat (limited to 'src/codegen/spirv/Module.zig')
| -rw-r--r-- | src/codegen/spirv/Module.zig | 447 |
1 files changed, 51 insertions, 396 deletions
diff --git a/src/codegen/spirv/Module.zig b/src/codegen/spirv/Module.zig index 85d0bbf78c..4c078f301b 100644 --- a/src/codegen/spirv/Module.zig +++ b/src/codegen/spirv/Module.zig @@ -20,12 +20,13 @@ const IdResult = spec.IdResult; 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); +const Cache = @import("TypeConstantCache.zig"); +pub const CacheKey = Cache.Key; +pub const CacheRef = Cache.Ref; +pub const CacheString = Cache.String; -/// This structure represents a function that is in-progress of being emitted. +/// This structure represents a function that isc in-progress of being emitted. /// Commonly, the contents of this structure will be merged with the appropriate /// sections of the module and re-used. Note that the SPIR-V module system makes /// no attempt of compacting result-id's, so any Fn instance should ultimately @@ -130,7 +131,7 @@ sections: struct { /// 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 + /// via the 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. @@ -152,10 +153,9 @@ 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) = .{}, -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 = .{}, +cache: Cache = .{}, /// Set of Decls, referred to by Decl.Index. decls: std.ArrayListUnmanaged(Decl) = .{}, @@ -196,7 +196,7 @@ pub fn deinit(self: *Module) void { self.sections.functions.deinit(self.gpa); self.source_file_names.deinit(self.gpa); - self.tc_cache.deinit(self); + self.cache.deinit(self); self.decls.deinit(self.gpa); self.decl_deps.deinit(self.gpa); @@ -223,20 +223,20 @@ 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 resolve(self: *Module, key: CacheKey) !CacheRef { + return self.cache.resolve(self, key); } -pub fn resultId(self: *Module, ref: TypeConstantCache.Ref) IdResult { - return self.tc_cache.resultId(ref); +pub fn resultId(self: *const Module, ref: CacheRef) IdResult { + return self.cache.resultId(ref); } -pub fn resolveId(self: *Module, key: TypeConstantCache.Key) !IdResult { +pub fn resolveId(self: *Module, key: CacheKey) !IdResult { return self.resultId(try self.resolve(key)); } -pub fn resolveString(self: *Module, str: []const u8) !TypeConstantCache.String { - return try self.tc_cache.addString(self, str); +pub fn resolveString(self: *Module, str: []const u8) !CacheString { + return try self.cache.addString(self, str); } fn orderGlobalsInto( @@ -350,7 +350,7 @@ 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); + var types_constants = try self.cache.materialize(self); defer types_constants.deinit(self.gpa); // Note: needs to be kept in order according to section 2.3! @@ -364,6 +364,7 @@ pub fn flush(self: *Module, file: std.fs.File) !void { self.sections.debug_names.toWords(), self.sections.annotations.toWords(), types_constants.toWords(), + self.sections.types_globals_constants.toWords(), self.sections.globals.toWords(), globals.toWords(), self.sections.functions.toWords(), @@ -416,364 +417,14 @@ pub fn resolveSourceFileName(self: *Module, decl: *ZigDecl) !IdRef { return result.value_ptr.*; } -/// Fetch a result-id for a spir-v type. This function deduplicates the type as appropriate, -/// and returns a cached version if that exists. -/// Note: This function does not attempt to perform any validation on the type. -/// The type is emitted in a shallow fashion; any child types should already -/// be emitted at this point. -pub fn resolveType(self: *Module, ty: Type) !Type.Ref { - const result = try self.type_cache.getOrPut(self.gpa, ty); - const index = @intToEnum(Type.Ref, result.index); - - if (!result.found_existing) { - const ref = try self.emitType(ty); - self.type_cache.values()[result.index] = ref; - } - - return index; -} - -pub fn resolveTypeId(self: *Module, ty: Type) !IdResultType { - const ty_ref = try self.resolveType(ty); - return self.typeId(ty_ref); -} - -pub fn typeRefType(self: Module, ty_ref: Type.Ref) Type { - return self.type_cache.keys()[@enumToInt(ty_ref)]; -} - -/// Get the result-id of a particular type, by reference. Asserts type_ref is valid. -pub fn typeId(self: Module, ty_ref: Type.Ref) IdResultType { - return self.type_cache.values()[@enumToInt(ty_ref)]; -} - -/// Unconditionally emit a spir-v type into the appropriate section. -/// Note: If this function is called with a type that is already generated, it may yield an invalid module -/// as non-pointer non-aggregrate types must me unique! -/// Note: This function does not attempt to perform any validation on the type. -/// The type is emitted in a shallow fashion; any child types should already -/// be emitted at this point. -pub fn emitType(self: *Module, ty: Type) error{OutOfMemory}!IdResultType { - const result_id = self.allocId(); - const ref_id = result_id; - const types = &self.sections.types_globals_constants; - const debug_names = &self.sections.debug_names; - const result_id_operand = .{ .id_result = result_id }; - - switch (ty.tag()) { - .void => { - try types.emit(self.gpa, .OpTypeVoid, result_id_operand); - try debug_names.emit(self.gpa, .OpName, .{ - .target = result_id, - .name = "void", - }); - }, - .bool => { - try types.emit(self.gpa, .OpTypeBool, result_id_operand); - try debug_names.emit(self.gpa, .OpName, .{ - .target = result_id, - .name = "bool", - }); - }, - .u8, - .u16, - .u32, - .u64, - .i8, - .i16, - .i32, - .i64, - .int, - => { - // TODO: Kernels do not support OpTypeInt that is signed. We can probably - // can get rid of the signedness all together, in Shaders also. - const bits = ty.intFloatBits(); - const signedness: spec.LiteralInteger = switch (ty.intSignedness()) { - .unsigned => 0, - .signed => 1, - }; - - try types.emit(self.gpa, .OpTypeInt, .{ - .id_result = result_id, - .width = bits, - .signedness = signedness, - }); - - const ui: []const u8 = switch (signedness) { - 0 => "u", - 1 => "i", - else => unreachable, - }; - const name = try std.fmt.allocPrint(self.gpa, "{s}{}", .{ ui, bits }); - defer self.gpa.free(name); - - try debug_names.emit(self.gpa, .OpName, .{ - .target = result_id, - .name = name, - }); - }, - .f16, .f32, .f64 => { - const bits = ty.intFloatBits(); - try types.emit(self.gpa, .OpTypeFloat, .{ - .id_result = result_id, - .width = bits, - }); - - const name = try std.fmt.allocPrint(self.gpa, "f{}", .{bits}); - defer self.gpa.free(name); - try debug_names.emit(self.gpa, .OpName, .{ - .target = result_id, - .name = name, - }); - }, - .vector => try types.emit(self.gpa, .OpTypeVector, .{ - .id_result = result_id, - .component_type = self.typeId(ty.childType()), - .component_count = ty.payload(.vector).component_count, - }), - .matrix => try types.emit(self.gpa, .OpTypeMatrix, .{ - .id_result = result_id, - .column_type = self.typeId(ty.childType()), - .column_count = ty.payload(.matrix).column_count, - }), - .image => { - const info = ty.payload(.image); - try types.emit(self.gpa, .OpTypeImage, .{ - .id_result = result_id, - .sampled_type = self.typeId(ty.childType()), - .dim = info.dim, - .depth = @enumToInt(info.depth), - .arrayed = @boolToInt(info.arrayed), - .ms = @boolToInt(info.multisampled), - .sampled = @enumToInt(info.sampled), - .image_format = info.format, - .access_qualifier = info.access_qualifier, - }); - }, - .sampler => try types.emit(self.gpa, .OpTypeSampler, result_id_operand), - .sampled_image => try types.emit(self.gpa, .OpTypeSampledImage, .{ - .id_result = result_id, - .image_type = self.typeId(ty.childType()), - }), - .array => { - const info = ty.payload(.array); - assert(info.length != 0); - - const size_type = Type.initTag(.u32); - const size_type_id = try self.resolveTypeId(size_type); - const length_id = self.allocId(); - try self.emitConstant(size_type_id, length_id, .{ .uint32 = info.length }); - - try types.emit(self.gpa, .OpTypeArray, .{ - .id_result = result_id, - .element_type = self.typeId(ty.childType()), - .length = length_id, - }); - if (info.array_stride != 0) { - try self.decorate(ref_id, .{ .ArrayStride = .{ .array_stride = info.array_stride } }); - } - }, - .runtime_array => { - const info = ty.payload(.runtime_array); - try types.emit(self.gpa, .OpTypeRuntimeArray, .{ - .id_result = result_id, - .element_type = self.typeId(ty.childType()), - }); - if (info.array_stride != 0) { - try self.decorate(ref_id, .{ .ArrayStride = .{ .array_stride = info.array_stride } }); - } - }, - .@"struct" => { - const info = ty.payload(.@"struct"); - try types.emitRaw(self.gpa, .OpTypeStruct, 1 + info.members.len); - types.writeOperand(IdResult, result_id); - for (info.members) |member| { - types.writeOperand(IdRef, self.typeId(member.ty)); - } - try self.decorateStruct(ref_id, info); - }, - .@"opaque" => try types.emit(self.gpa, .OpTypeOpaque, .{ - .id_result = result_id, - .literal_string = ty.payload(.@"opaque").name, - }), - .pointer => { - const info = ty.payload(.pointer); - try types.emit(self.gpa, .OpTypePointer, .{ - .id_result = result_id, - .storage_class = info.storage_class, - .type = self.typeId(ty.childType()), - }); - if (info.array_stride != 0) { - try self.decorate(ref_id, .{ .ArrayStride = .{ .array_stride = info.array_stride } }); - } - if (info.alignment != 0) { - try self.decorate(ref_id, .{ .Alignment = .{ .alignment = info.alignment } }); - } - if (info.max_byte_offset) |max_byte_offset| { - try self.decorate(ref_id, .{ .MaxByteOffset = .{ .max_byte_offset = max_byte_offset } }); - } - }, - .function => { - const info = ty.payload(.function); - try types.emitRaw(self.gpa, .OpTypeFunction, 2 + info.parameters.len); - types.writeOperand(IdResult, result_id); - types.writeOperand(IdRef, self.typeId(info.return_type)); - for (info.parameters) |parameter_type| { - types.writeOperand(IdRef, self.typeId(parameter_type)); - } - }, - .event => try types.emit(self.gpa, .OpTypeEvent, result_id_operand), - .device_event => try types.emit(self.gpa, .OpTypeDeviceEvent, result_id_operand), - .reserve_id => try types.emit(self.gpa, .OpTypeReserveId, result_id_operand), - .queue => try types.emit(self.gpa, .OpTypeQueue, result_id_operand), - .pipe => try types.emit(self.gpa, .OpTypePipe, .{ - .id_result = result_id, - .qualifier = ty.payload(.pipe).qualifier, - }), - .pipe_storage => try types.emit(self.gpa, .OpTypePipeStorage, result_id_operand), - .named_barrier => try types.emit(self.gpa, .OpTypeNamedBarrier, result_id_operand), - } - - return result_id; -} - -fn decorateStruct(self: *Module, target: IdRef, info: *const Type.Payload.Struct) !void { - const debug_names = &self.sections.debug_names; - - if (info.name.len != 0) { - try debug_names.emit(self.gpa, .OpName, .{ - .target = target, - .name = info.name, - }); - } - - // Decorations for the struct type itself. - if (info.decorations.block) - try self.decorate(target, .Block); - if (info.decorations.buffer_block) - try self.decorate(target, .BufferBlock); - if (info.decorations.glsl_shared) - try self.decorate(target, .GLSLShared); - if (info.decorations.glsl_packed) - try self.decorate(target, .GLSLPacked); - if (info.decorations.c_packed) - try self.decorate(target, .CPacked); - - // Decorations for the struct members. - const extra = info.member_decoration_extra; - var extra_i: u32 = 0; - for (info.members, 0..) |member, i| { - const d = member.decorations; - const index = @intCast(Word, i); - - if (member.name.len != 0) { - try debug_names.emit(self.gpa, .OpMemberName, .{ - .type = target, - .member = index, - .name = member.name, - }); - } - - switch (member.offset) { - .none => {}, - else => try self.decorateMember( - target, - index, - .{ .Offset = .{ .byte_offset = @enumToInt(member.offset) } }, - ), - } - - switch (d.matrix_layout) { - .row_major => try self.decorateMember(target, index, .RowMajor), - .col_major => try self.decorateMember(target, index, .ColMajor), - .none => {}, - } - if (d.matrix_layout != .none) { - try self.decorateMember(target, index, .{ - .MatrixStride = .{ .matrix_stride = extra[extra_i] }, - }); - extra_i += 1; - } - - if (d.no_perspective) - try self.decorateMember(target, index, .NoPerspective); - if (d.flat) - try self.decorateMember(target, index, .Flat); - if (d.patch) - try self.decorateMember(target, index, .Patch); - if (d.centroid) - try self.decorateMember(target, index, .Centroid); - if (d.sample) - try self.decorateMember(target, index, .Sample); - if (d.invariant) - try self.decorateMember(target, index, .Invariant); - if (d.@"volatile") - try self.decorateMember(target, index, .Volatile); - if (d.coherent) - try self.decorateMember(target, index, .Coherent); - if (d.non_writable) - try self.decorateMember(target, index, .NonWritable); - if (d.non_readable) - try self.decorateMember(target, index, .NonReadable); - - if (d.builtin) { - try self.decorateMember(target, index, .{ - .BuiltIn = .{ .built_in = @intToEnum(spec.BuiltIn, extra[extra_i]) }, - }); - extra_i += 1; - } - if (d.stream) { - try self.decorateMember(target, index, .{ - .Stream = .{ .stream_number = extra[extra_i] }, - }); - extra_i += 1; - } - if (d.location) { - try self.decorateMember(target, index, .{ - .Location = .{ .location = extra[extra_i] }, - }); - extra_i += 1; - } - if (d.component) { - try self.decorateMember(target, index, .{ - .Component = .{ .component = extra[extra_i] }, - }); - extra_i += 1; - } - if (d.xfb_buffer) { - try self.decorateMember(target, index, .{ - .XfbBuffer = .{ .xfb_buffer_number = extra[extra_i] }, - }); - extra_i += 1; - } - if (d.xfb_stride) { - try self.decorateMember(target, index, .{ - .XfbStride = .{ .xfb_stride = extra[extra_i] }, - }); - extra_i += 1; - } - if (d.user_semantic) { - const len = extra[extra_i]; - extra_i += 1; - const semantic = @ptrCast([*]const u8, &extra[extra_i])[0..len]; - try self.decorateMember(target, index, .{ - .UserSemantic = .{ .semantic = semantic }, - }); - extra_i += std.math.divCeil(u32, extra_i, @sizeOf(u32)) catch unreachable; - } - } -} - -pub fn simpleStructType(self: *Module, members: []const Type.Payload.Struct.Member) !Type.Ref { - const payload = try self.arena.create(Type.Payload.Struct); - payload.* = .{ - .members = try self.arena.dupe(Type.Payload.Struct.Member, members), - .decorations = .{}, - }; - return try self.resolveType(Type.initPayload(&payload.base)); +pub fn intType(self: *Module, signedness: std.builtin.Signedness, bits: u16) !CacheRef { + return try self.resolve(.{ .int_type = .{ + .signedness = signedness, + .bits = bits, + } }); } -pub fn arrayType2(self: *Module, len: u32, elem_ty_ref: TypeConstantCache.Ref) !TypeConstantCache.Ref { +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, @@ -788,41 +439,45 @@ pub fn arrayType2(self: *Module, len: u32, elem_ty_ref: TypeConstantCache.Ref) ! } }); } -pub fn arrayType(self: *Module, len: u32, ty: Type.Ref) !Type.Ref { - const payload = try self.arena.create(Type.Payload.Array); - payload.* = .{ - .element_type = ty, - .length = len, - }; - return try self.resolveType(Type.initPayload(&payload.base)); -} - pub fn ptrType( self: *Module, - child: Type.Ref, + child: CacheRef, storage_class: spec.StorageClass, - alignment: u32, -) !Type.Ref { - const ptr_payload = try self.arena.create(Type.Payload.Pointer); - ptr_payload.* = .{ +) !CacheRef { + return try self.resolve(.{ .ptr_type = .{ .storage_class = storage_class, .child_type = child, - .alignment = alignment, - }; - return try self.resolveType(Type.initPayload(&ptr_payload.base)); + } }); +} + +pub fn constInt(self: *Module, ty_ref: CacheRef, value: anytype) !IdRef { + const ty = self.cache.lookup(ty_ref).int_type; + const Value = Cache.Key.Int.Value; + return try self.resolveId(.{ .int = .{ + .ty = ty_ref, + .value = switch (ty.signedness) { + .signed => Value{ .int64 = @intCast(i64, value) }, + .unsigned => Value{ .uint64 = @intCast(u64, value) }, + }, + } }); +} + +pub fn constUndef(self: *Module, ty_ref: CacheRef) !IdRef { + return try self.resolveId(.{ .undef = .{ .ty = ty_ref } }); +} + +pub fn constNull(self: *Module, ty_ref: CacheRef) !IdRef { + return try self.resolveId(.{ .null = .{ .ty = ty_ref } }); } -pub fn changePtrStorageClass(self: *Module, ptr_ty_ref: Type.Ref, new_storage_class: spec.StorageClass) !Type.Ref { - const payload = try self.arena.create(Type.Payload.Pointer); - payload.* = self.typeRefType(ptr_ty_ref).payload(.pointer).*; - payload.storage_class = new_storage_class; - return try self.resolveType(Type.initPayload(&payload.base)); +pub fn constBool(self: *Module, ty_ref: CacheRef, value: bool) !IdRef { + return try self.resolveId(.{ .bool = .{ .ty = ty_ref, .value = value } }); } -pub fn constComposite(self: *Module, ty_ref: Type.Ref, members: []const IdRef) !IdRef { +pub fn constComposite(self: *Module, ty_ref: CacheRef, members: []const IdRef) !IdRef { const result_id = self.allocId(); try self.sections.types_globals_constants.emit(self.gpa, .OpSpecConstantComposite, .{ - .id_result_type = self.typeId(ty_ref), + .id_result_type = self.resultId(ty_ref), .id_result = result_id, .constituents = members, }); |
