aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/spirv/Module.zig
diff options
context:
space:
mode:
authorRobin Voetter <robin@voetter.nl>2023-05-29 23:54:09 +0200
committerRobin Voetter <robin@voetter.nl>2023-05-30 19:43:37 +0200
commit0552a8b11f973fc9621971e2130c25ad3a4af0ad (patch)
tree5d9fd2ed5cdc4a8a00b1047dfb0721145d752a2c /src/codegen/spirv/Module.zig
parentfcb422585c1a9e91933ff998417eb8682a4ffbcc (diff)
downloadzig-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.zig447
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,
});