authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-04-06 13:03:22-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-04-06 13:03:22-07:00
logf45ba7d0c1489a439725a11e5e36aa69fe75e7c3
treefe5fea980d6ac7ecc3b1b7a45f82bbea4a0a460a
parentf668c8bfd65489d1d38716e2973e0ee1cf0e8c52
parentac165458959d9db9c9fd0362aeb35f8b983cdf6a
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19562 from Snektron/spirv-remove-cache

spirv: remove cache

16 files changed, 1089 insertions(+), 2078 deletions(-)

src/codegen/spirv.zig+777-773
...@@ -22,8 +22,6 @@ const IdResultType = spec.IdResultType;...@@ -22,8 +22,6 @@ const IdResultType = spec.IdResultType;
22const StorageClass = spec.StorageClass;22const StorageClass = spec.StorageClass;
2323
24const SpvModule = @import("spirv/Module.zig");24const SpvModule = @import("spirv/Module.zig");
25const CacheRef = SpvModule.CacheRef;
26const CacheString = SpvModule.CacheString;
2725
28const SpvSection = @import("spirv/Section.zig");26const SpvSection = @import("spirv/Section.zig");
29const SpvAssembler = @import("spirv/Assembler.zig");27const SpvAssembler = @import("spirv/Assembler.zig");
...@@ -32,14 +30,11 @@ const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef);...@@ -32,14 +30,11 @@ const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef);
3230
33pub const zig_call_abi_ver = 3;31pub const zig_call_abi_ver = 3;
3432
35/// We want to store some extra facts about types as mapped from Zig to SPIR-V.33const InternMap = std.AutoHashMapUnmanaged(struct { InternPool.Index, DeclGen.Repr }, IdResult);
36/// This structure is used to keep that extra information, as well as34const PtrTypeMap = std.AutoHashMapUnmanaged(
37/// the cached reference to the type.35 struct { InternPool.Index, StorageClass },
38const SpvTypeInfo = struct {36 struct { ty_id: IdRef, fwd_emitted: bool },
39 ty_ref: CacheRef,37);
40};
41
42const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, SpvTypeInfo);
4338
44const ControlFlow = union(enum) {39const ControlFlow = union(enum) {
45 const Structured = struct {40 const Structured = struct {
...@@ -162,14 +157,16 @@ pub const Object = struct {...@@ -162,14 +157,16 @@ pub const Object = struct {
162 /// A map of Zig InternPool indices for anonymous decls to SPIR-V decl indices.157 /// A map of Zig InternPool indices for anonymous decls to SPIR-V decl indices.
163 anon_decl_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, SpvModule.Decl.Index) = .{},158 anon_decl_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, SpvModule.Decl.Index) = .{},
164159
165 /// A map that maps AIR intern pool indices to SPIR-V cache references (which160 /// A map that maps AIR intern pool indices to SPIR-V result-ids.
166 /// is basically the same thing except for SPIR-V).161 intern_map: InternMap = .{},
167 /// This map is typically only used for structures that are deemed heavy enough162
168 /// that it is worth to store them here. The SPIR-V module also interns types,163 /// This map serves a dual purpose:
169 /// and so the main purpose of this map is to avoid recomputation and to164 /// - It keeps track of pointers that are currently being emitted, so that we can tell
170 /// cache extra information about the type rather than to aid in validity165 /// if they are recursive and need an OpTypeForwardPointer.
171 /// of the SPIR-V module.166 /// - It caches pointers by child-type. This is required because sometimes we rely on
172 type_map: TypeMap = .{},167 /// ID-equality for pointers, and pointers constructed via `ptrType()` aren't interned
168 /// via the usual `intern_map` mechanism.
169 ptr_types: PtrTypeMap = .{},
173170
174 pub fn init(gpa: Allocator) Object {171 pub fn init(gpa: Allocator) Object {
175 return .{172 return .{
...@@ -182,7 +179,8 @@ pub const Object = struct {...@@ -182,7 +179,8 @@ pub const Object = struct {
182 self.spv.deinit();179 self.spv.deinit();
183 self.decl_link.deinit(self.gpa);180 self.decl_link.deinit(self.gpa);
184 self.anon_decl_link.deinit(self.gpa);181 self.anon_decl_link.deinit(self.gpa);
185 self.type_map.deinit(self.gpa);182 self.intern_map.deinit(self.gpa);
183 self.ptr_types.deinit(self.gpa);
186 }184 }
187185
188 fn genDecl(186 fn genDecl(
...@@ -204,7 +202,8 @@ pub const Object = struct {...@@ -204,7 +202,8 @@ pub const Object = struct {
204 .decl_index = decl_index,202 .decl_index = decl_index,
205 .air = air,203 .air = air,
206 .liveness = liveness,204 .liveness = liveness,
207 .type_map = &self.type_map,205 .intern_map = &self.intern_map,
206 .ptr_types = &self.ptr_types,
208 .control_flow = switch (structured_cfg) {207 .control_flow = switch (structured_cfg) {
209 true => .{ .structured = .{} },208 true => .{ .structured = .{} },
210 false => .{ .unstructured = .{} },209 false => .{ .unstructured = .{} },
...@@ -309,13 +308,12 @@ const DeclGen = struct {...@@ -309,13 +308,12 @@ const DeclGen = struct {
309 /// A map keeping track of which instruction generated which result-id.308 /// A map keeping track of which instruction generated which result-id.
310 inst_results: InstMap = .{},309 inst_results: InstMap = .{},
311310
312 /// A map that maps AIR intern pool indices to SPIR-V cache references.311 /// A map that maps AIR intern pool indices to SPIR-V result-ids.
313 /// See Object.type_map312 /// See `Object.intern_map`.
314 type_map: *TypeMap,313 intern_map: *InternMap,
315314
316 /// Child types of pointers that are currently in progress of being resolved. If a pointer315 /// Module's pointer types, see `Object.ptr_types`.
317 /// is already in this map, its recursive.316 ptr_types: *PtrTypeMap,
318 wip_pointers: std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, CacheRef) = .{},
319317
320 /// This field keeps track of the current state wrt structured or unstructured control flow.318 /// This field keeps track of the current state wrt structured or unstructured control flow.
321 control_flow: ControlFlow,319 control_flow: ControlFlow,
...@@ -402,7 +400,6 @@ const DeclGen = struct {...@@ -402,7 +400,6 @@ const DeclGen = struct {
402 pub fn deinit(self: *DeclGen) void {400 pub fn deinit(self: *DeclGen) void {
403 self.args.deinit(self.gpa);401 self.args.deinit(self.gpa);
404 self.inst_results.deinit(self.gpa);402 self.inst_results.deinit(self.gpa);
405 self.wip_pointers.deinit(self.gpa);
406 self.control_flow.deinit(self.gpa);403 self.control_flow.deinit(self.gpa);
407 self.func.deinit(self.gpa);404 self.func.deinit(self.gpa);
408 }405 }
...@@ -452,7 +449,7 @@ const DeclGen = struct {...@@ -452,7 +449,7 @@ const DeclGen = struct {
452449
453 const mod = self.module;450 const mod = self.module;
454 const ty = Type.fromInterned(mod.intern_pool.typeOf(val));451 const ty = Type.fromInterned(mod.intern_pool.typeOf(val));
455 const decl_ptr_ty_ref = try self.ptrType(ty, .Generic);452 const decl_ptr_ty_id = try self.ptrType(ty, .Generic);
456453
457 const spv_decl_index = blk: {454 const spv_decl_index = blk: {
458 const entry = try self.object.anon_decl_link.getOrPut(self.object.gpa, .{ val, .Function });455 const entry = try self.object.anon_decl_link.getOrPut(self.object.gpa, .{ val, .Function });
...@@ -460,7 +457,7 @@ const DeclGen = struct {...@@ -460,7 +457,7 @@ const DeclGen = struct {
460 try self.addFunctionDep(entry.value_ptr.*, .Function);457 try self.addFunctionDep(entry.value_ptr.*, .Function);
461458
462 const result_id = self.spv.declPtr(entry.value_ptr.*).result_id;459 const result_id = self.spv.declPtr(entry.value_ptr.*).result_id;
463 return try self.castToGeneric(self.typeId(decl_ptr_ty_ref), result_id);460 return try self.castToGeneric(decl_ptr_ty_id, result_id);
464 }461 }
465462
466 const spv_decl_index = try self.spv.allocDecl(.invocation_global);463 const spv_decl_index = try self.spv.allocDecl(.invocation_global);
...@@ -488,19 +485,14 @@ const DeclGen = struct {...@@ -488,19 +485,14 @@ const DeclGen = struct {
488 self.func = .{};485 self.func = .{};
489 defer self.func.deinit(self.gpa);486 defer self.func.deinit(self.gpa);
490487
491 const void_ty_ref = try self.resolveType(Type.void, .direct);488 const initializer_proto_ty_id = try self.functionType(Type.void, &.{});
492 const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{
493 .return_type = void_ty_ref,
494 .parameters = &.{},
495 } });
496489
497 const initializer_id = self.spv.allocId();490 const initializer_id = self.spv.allocId();
498
499 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{491 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
500 .id_result_type = self.typeId(void_ty_ref),492 .id_result_type = try self.resolveType(Type.void, .direct),
501 .id_result = initializer_id,493 .id_result = initializer_id,
502 .function_control = .{},494 .function_control = .{},
503 .function_type = self.typeId(initializer_proto_ty_ref),495 .function_type = initializer_proto_ty_id,
504 });496 });
505 const root_block_id = self.spv.allocId();497 const root_block_id = self.spv.allocId();
506 try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{498 try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{
...@@ -520,9 +512,9 @@ const DeclGen = struct {...@@ -520,9 +512,9 @@ const DeclGen = struct {
520512
521 try self.spv.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});513 try self.spv.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});
522514
523 const fn_decl_ptr_ty_ref = try self.ptrType(ty, .Function);515 const fn_decl_ptr_ty_id = try self.ptrType(ty, .Function);
524 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{516 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{
525 .id_result_type = self.typeId(fn_decl_ptr_ty_ref),517 .id_result_type = fn_decl_ptr_ty_id,
526 .id_result = result_id,518 .id_result = result_id,
527 .set = try self.spv.importInstructionSet(.zig),519 .set = try self.spv.importInstructionSet(.zig),
528 .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere...520 .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere...
...@@ -530,7 +522,7 @@ const DeclGen = struct {...@@ -530,7 +522,7 @@ const DeclGen = struct {
530 });522 });
531 }523 }
532524
533 return try self.castToGeneric(self.typeId(decl_ptr_ty_ref), result_id);525 return try self.castToGeneric(decl_ptr_ty_id, result_id);
534 }526 }
535527
536 fn addFunctionDep(self: *DeclGen, decl_index: SpvModule.Decl.Index, storage_class: StorageClass) !void {528 fn addFunctionDep(self: *DeclGen, decl_index: SpvModule.Decl.Index, storage_class: StorageClass) !void {
...@@ -696,14 +688,25 @@ const DeclGen = struct {...@@ -696,14 +688,25 @@ const DeclGen = struct {
696688
697 /// Emits a bool constant in a particular representation.689 /// Emits a bool constant in a particular representation.
698 fn constBool(self: *DeclGen, value: bool, repr: Repr) !IdRef {690 fn constBool(self: *DeclGen, value: bool, repr: Repr) !IdRef {
691 // TODO: Cache?
692
693 const section = &self.spv.sections.types_globals_constants;
699 switch (repr) {694 switch (repr) {
700 .indirect => {695 .indirect => {
701 const int_ty_ref = try self.intType(.unsigned, 1);696 return try self.constInt(Type.u1, @intFromBool(value), .indirect);
702 return self.constInt(int_ty_ref, @intFromBool(value));
703 },697 },
704 .direct => {698 .direct => {
705 const bool_ty_ref = try self.resolveType(Type.bool, .direct);699 const result_ty_id = try self.resolveType(Type.bool, .direct);
706 return self.spv.constBool(bool_ty_ref, value);700 const result_id = self.spv.allocId();
701 const operands = .{
702 .id_result_type = result_ty_id,
703 .id_result = result_id,
704 };
705 switch (value) {
706 true => try section.emit(self.spv.gpa, .OpConstantTrue, operands),
707 false => try section.emit(self.spv.gpa, .OpConstantFalse, operands),
708 }
709 return result_id;
707 },710 },
708 }711 }
709 }712 }
...@@ -711,68 +714,63 @@ const DeclGen = struct {...@@ -711,68 +714,63 @@ const DeclGen = struct {
711 /// Emits an integer constant.714 /// Emits an integer constant.
712 /// This function, unlike SpvModule.constInt, takes care to bitcast715 /// This function, unlike SpvModule.constInt, takes care to bitcast
713 /// the value to an unsigned int first for Kernels.716 /// the value to an unsigned int first for Kernels.
714 fn constInt(self: *DeclGen, ty_ref: CacheRef, value: anytype) !IdRef {717 fn constInt(self: *DeclGen, ty: Type, value: anytype, repr: Repr) !IdRef {
715 switch (self.spv.cache.lookup(ty_ref)) {718 // TODO: Cache?
716 .vector_type => |vec_type| {719 const mod = self.module;
717 const elem_ids = try self.gpa.alloc(IdRef, vec_type.component_count);720 const scalar_ty = ty.scalarType(mod);
718 defer self.gpa.free(elem_ids);721 const int_info = scalar_ty.intInfo(mod);
719 const int_value = try self.constInt(vec_type.component_type, value);722 // Use backing bits so that negatives are sign extended
720 @memset(elem_ids, int_value);723 const backing_bits = self.backingIntBits(int_info.bits).?; // Assertion failure means big int
721724
722 const constituents_id = self.spv.allocId();725 const bits: u64 = switch (int_info.signedness) {
723 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{726 // Intcast needed to silence compile errors for when the wrong path is compiled.
724 .id_result_type = self.typeId(ty_ref),727 // Lazy fix.
725 .id_result = constituents_id,728 .signed => @bitCast(@as(i64, @intCast(value))),
726 .constituents = elem_ids,729 .unsigned => @as(u64, @intCast(value)),
727 });730 };
728 return constituents_id;
729 },
730 else => {},
731 }
732731
733 if (value < 0) {732 // Manually truncate the value to the right amount of bits.
734 const ty = self.spv.cache.lookup(ty_ref).int_type;733 const truncated_bits = if (backing_bits == 64)
735 // Manually truncate the value so that the resulting value734 bits
736 // fits within the unsigned type.735 else
737 const bits: u64 = @bitCast(@as(i64, @intCast(value)));736 bits & (@as(u64, 1) << @intCast(backing_bits)) - 1;
738 const truncated_bits = if (ty.bits == 64)737
739 bits738 const result_ty_id = try self.resolveType(scalar_ty, repr);
740 else739 const result_id = self.spv.allocId();
741 bits & (@as(u64, 1) << @intCast(ty.bits)) - 1;740
742 return try self.spv.constInt(ty_ref, truncated_bits);741 const section = &self.spv.sections.types_globals_constants;
743 } else {742 switch (backing_bits) {
744 return try self.spv.constInt(ty_ref, value);743 0 => unreachable, // u0 is comptime
744 1...32 => try section.emit(self.spv.gpa, .OpConstant, .{
745 .id_result_type = result_ty_id,
746 .id_result = result_id,
747 .value = .{ .uint32 = @truncate(truncated_bits) },
748 }),
749 33...64 => try section.emit(self.spv.gpa, .OpConstant, .{
750 .id_result_type = result_ty_id,
751 .id_result = result_id,
752 .value = .{ .uint64 = truncated_bits },
753 }),
754 else => unreachable, // TODO: Large integer constants
745 }755 }
746 }
747756
748 /// Emits a float constant757 if (!ty.isVector(mod)) {
749 fn constFloat(self: *DeclGen, ty_ref: CacheRef, value: f128) !IdRef {758 return result_id;
750 switch (self.spv.cache.lookup(ty_ref)) {
751 .vector_type => |vec_type| {
752 const elem_ids = try self.gpa.alloc(IdRef, vec_type.component_count);
753 defer self.gpa.free(elem_ids);
754 const int_value = try self.constFloat(vec_type.component_type, value);
755 @memset(elem_ids, int_value);
756
757 const constituents_id = self.spv.allocId();
758 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
759 .id_result_type = self.typeId(ty_ref),
760 .id_result = constituents_id,
761 .constituents = elem_ids,
762 });
763 return constituents_id;
764 },
765 else => {},
766 }759 }
767760
768 const ty = self.spv.cache.lookup(ty_ref).float_type;761 const n = ty.vectorLen(mod);
769 return switch (ty.bits) {762 const ids = try self.gpa.alloc(IdRef, n);
770 16 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float16 = @floatCast(value) } } }),763 defer self.gpa.free(ids);
771 32 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float32 = @floatCast(value) } } }),764 @memset(ids, result_id);
772 64 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float64 = @floatCast(value) } } }),765
773 80, 128 => unreachable, // TODO766 const vec_ty_id = try self.resolveType(ty, repr);
774 else => unreachable,767 const vec_result_id = self.spv.allocId();
775 };768 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
769 .id_result_type = vec_ty_id,
770 .id_result = vec_result_id,
771 .constituents = ids,
772 });
773 return vec_result_id;
776 }774 }
777775
778 /// Construct a struct at runtime.776 /// Construct a struct at runtime.
...@@ -788,8 +786,8 @@ const DeclGen = struct {...@@ -788,8 +786,8 @@ const DeclGen = struct {
788 // TODO: Make this OpCompositeConstruct when we can786 // TODO: Make this OpCompositeConstruct when we can
789 const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function });787 const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function });
790 for (constituents, types, 0..) |constitent_id, member_ty, index| {788 for (constituents, types, 0..) |constitent_id, member_ty, index| {
791 const ptr_member_ty_ref = try self.ptrType(member_ty, .Function);789 const ptr_member_ty_id = try self.ptrType(member_ty, .Function);
792 const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))});790 const ptr_id = try self.accessChain(ptr_member_ty_id, ptr_composite_id, &.{@as(u32, @intCast(index))});
793 try self.func.body.emit(self.spv.gpa, .OpStore, .{791 try self.func.body.emit(self.spv.gpa, .OpStore, .{
794 .pointer = ptr_id,792 .pointer = ptr_id,
795 .object = constitent_id,793 .object = constitent_id,
...@@ -810,9 +808,9 @@ const DeclGen = struct {...@@ -810,9 +808,9 @@ const DeclGen = struct {
810 // TODO: Make this OpCompositeConstruct when we can808 // TODO: Make this OpCompositeConstruct when we can
811 const mod = self.module;809 const mod = self.module;
812 const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function });810 const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function });
813 const ptr_elem_ty_ref = try self.ptrType(ty.elemType2(mod), .Function);811 const ptr_elem_ty_id = try self.ptrType(ty.elemType2(mod), .Function);
814 for (constituents, 0..) |constitent_id, index| {812 for (constituents, 0..) |constitent_id, index| {
815 const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))});813 const ptr_id = try self.accessChain(ptr_elem_ty_id, ptr_composite_id, &.{@as(u32, @intCast(index))});
816 try self.func.body.emit(self.spv.gpa, .OpStore, .{814 try self.func.body.emit(self.spv.gpa, .OpStore, .{
817 .pointer = ptr_id,815 .pointer = ptr_id,
818 .object = constitent_id,816 .object = constitent_id,
...@@ -834,9 +832,9 @@ const DeclGen = struct {...@@ -834,9 +832,9 @@ const DeclGen = struct {
834 // TODO: Make this OpCompositeConstruct when we can832 // TODO: Make this OpCompositeConstruct when we can
835 const mod = self.module;833 const mod = self.module;
836 const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function });834 const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function });
837 const ptr_elem_ty_ref = try self.ptrType(ty.elemType2(mod), .Function);835 const ptr_elem_ty_id = try self.ptrType(ty.elemType2(mod), .Function);
838 for (constituents, 0..) |constitent_id, index| {836 for (constituents, 0..) |constitent_id, index| {
839 const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))});837 const ptr_id = try self.accessChain(ptr_elem_ty_id, ptr_composite_id, &.{@as(u32, @intCast(index))});
840 try self.func.body.emit(self.spv.gpa, .OpStore, .{838 try self.func.body.emit(self.spv.gpa, .OpStore, .{
841 .pointer = ptr_id,839 .pointer = ptr_id,
842 .object = constitent_id,840 .object = constitent_id,
...@@ -852,258 +850,279 @@ const DeclGen = struct {...@@ -852,258 +850,279 @@ const DeclGen = struct {
852 /// is done by emitting a sequence of instructions that initialize the value.850 /// is done by emitting a sequence of instructions that initialize the value.
853 //851 //
854 /// This function should only be called during function code generation.852 /// This function should only be called during function code generation.
855 fn constant(self: *DeclGen, ty: Type, arg_val: Value, repr: Repr) !IdRef {853 fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef {
854 // Note: Using intern_map can only be used with constants that DO NOT generate any runtime code!!
855 // Ideally that should be all constants in the future, or it should be cleaned up somehow. For
856 // now, only use the intern_map on case-by-case basis by breaking to :cache.
857 if (self.intern_map.get(.{ val.toIntern(), repr })) |id| {
858 return id;
859 }
860
856 const mod = self.module;861 const mod = self.module;
857 const target = self.getTarget();862 const target = self.getTarget();
858 const result_ty_ref = try self.resolveType(ty, repr);863 const result_ty_id = try self.resolveType(ty, repr);
859 const ip = &mod.intern_pool;864 const ip = &mod.intern_pool;
860865
861 const val = arg_val;866 log.debug("lowering constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod) });
862
863 log.debug("constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod) });
864 if (val.isUndefDeep(mod)) {867 if (val.isUndefDeep(mod)) {
865 return self.spv.constUndef(result_ty_ref);868 return self.spv.constUndef(result_ty_id);
866 }869 }
867870
868 switch (ip.indexToKey(val.toIntern())) {871 const section = &self.spv.sections.types_globals_constants;
869 .int_type,872
870 .ptr_type,873 const cacheable_id = cache: {
871 .array_type,874 switch (ip.indexToKey(val.toIntern())) {
872 .vector_type,875 .int_type,
873 .opt_type,876 .ptr_type,
874 .anyframe_type,877 .array_type,
875 .error_union_type,878 .vector_type,
876 .simple_type,879 .opt_type,
877 .struct_type,880 .anyframe_type,
878 .anon_struct_type,881 .error_union_type,
879 .union_type,882 .simple_type,
880 .opaque_type,883 .struct_type,
881 .enum_type,884 .anon_struct_type,
882 .func_type,885 .union_type,
883 .error_set_type,886 .opaque_type,
884 .inferred_error_set_type,887 .enum_type,
885 => unreachable, // types, not values888 .func_type,
886889 .error_set_type,
887 .undef => unreachable, // handled above890 .inferred_error_set_type,
888891 => unreachable, // types, not values
889 .variable,892
890 .extern_func,893 .undef => unreachable, // handled above
891 .func,894
892 .enum_literal,895 .variable,
893 .empty_enum_value,896 .extern_func,
894 => unreachable, // non-runtime values897 .func,
895898 .enum_literal,
896 .simple_value => |simple_value| switch (simple_value) {899 .empty_enum_value,
897 .undefined,
898 .void,
899 .null,
900 .empty_struct,
901 .@"unreachable",
902 .generic_poison,
903 => unreachable, // non-runtime values900 => unreachable, // non-runtime values
904901
905 .false, .true => return try self.constBool(val.toBool(), repr),902 .simple_value => |simple_value| switch (simple_value) {
906 },903 .undefined,
904 .void,
905 .null,
906 .empty_struct,
907 .@"unreachable",
908 .generic_poison,
909 => unreachable, // non-runtime values
907910
908 .int => {911 .false, .true => break :cache try self.constBool(val.toBool(), repr),
909 if (ty.isSignedInt(mod)) {912 },
910 return try self.constInt(result_ty_ref, val.toSignedInt(mod));913 .int => {
911 } else {914 if (ty.isSignedInt(mod)) {
912 return try self.constInt(result_ty_ref, val.toUnsignedInt(mod));915 break :cache try self.constInt(ty, val.toSignedInt(mod), repr);
913 }
914 },
915 .float => return switch (ty.floatBits(target)) {
916 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16, mod) } } }),
917 32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32, mod) } } }),
918 64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64, mod) } } }),
919 80, 128 => unreachable, // TODO
920 else => unreachable,
921 },
922 .err => |err| {
923 const value = try mod.getErrorValue(err.name);
924 return try self.constInt(result_ty_ref, value);
925 },
926 .error_union => |error_union| {
927 // TODO: Error unions may be constructed with constant instructions if the payload type
928 // allows it. For now, just generate it here regardless.
929 const err_int_ty = try mod.errorIntType();
930 const err_ty = switch (error_union.val) {
931 .err_name => ty.errorUnionSet(mod),
932 .payload => err_int_ty,
933 };
934 const err_val = switch (error_union.val) {
935 .err_name => |err_name| Value.fromInterned((try mod.intern(.{ .err = .{
936 .ty = ty.errorUnionSet(mod).toIntern(),
937 .name = err_name,
938 } }))),
939 .payload => try mod.intValue(err_int_ty, 0),
940 };
941 const payload_ty = ty.errorUnionPayload(mod);
942 const eu_layout = self.errorUnionLayout(payload_ty);
943 if (!eu_layout.payload_has_bits) {
944 // We use the error type directly as the type.
945 return try self.constant(err_ty, err_val, .indirect);
946 }
947
948 const payload_val = Value.fromInterned(switch (error_union.val) {
949 .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }),
950 .payload => |payload| payload,
951 });
952
953 var constituents: [2]IdRef = undefined;
954 var types: [2]Type = undefined;
955 if (eu_layout.error_first) {
956 constituents[0] = try self.constant(err_ty, err_val, .indirect);
957 constituents[1] = try self.constant(payload_ty, payload_val, .indirect);
958 types = .{ err_ty, payload_ty };
959 } else {
960 constituents[0] = try self.constant(payload_ty, payload_val, .indirect);
961 constituents[1] = try self.constant(err_ty, err_val, .indirect);
962 types = .{ payload_ty, err_ty };
963 }
964
965 return try self.constructStruct(ty, &types, &constituents);
966 },
967 .enum_tag => {
968 const int_val = try val.intFromEnum(ty, mod);
969 const int_ty = ty.intTagType(mod);
970 return try self.constant(int_ty, int_val, repr);
971 },
972 .ptr => return self.constantPtr(ty, val),
973 .slice => |slice| {
974 const ptr_ty = ty.slicePtrFieldType(mod);
975 const ptr_id = try self.constantPtr(ptr_ty, Value.fromInterned(slice.ptr));
976 const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);
977 return self.constructStruct(
978 ty,
979 &.{ ptr_ty, Type.usize },
980 &.{ ptr_id, len_id },
981 );
982 },
983 .opt => {
984 const payload_ty = ty.optionalChild(mod);
985 const maybe_payload_val = val.optionalValue(mod);
986
987 if (!payload_ty.hasRuntimeBits(mod)) {
988 return try self.constBool(maybe_payload_val != null, .indirect);
989 } else if (ty.optionalReprIsPayload(mod)) {
990 // Optional representation is a nullable pointer or slice.
991 if (maybe_payload_val) |payload_val| {
992 return try self.constant(payload_ty, payload_val, .indirect);
993 } else {916 } else {
994 const ptr_ty_ref = try self.resolveType(ty, .indirect);917 break :cache try self.constInt(ty, val.toUnsignedInt(mod), repr);
995 return self.spv.constNull(ptr_ty_ref);918 }
919 },
920 .float => {
921 const lit: spec.LiteralContextDependentNumber = switch (ty.floatBits(target)) {
922 16 => .{ .uint32 = @as(u16, @bitCast(val.toFloat(f16, mod))) },
923 32 => .{ .float32 = val.toFloat(f32, mod) },
924 64 => .{ .float64 = val.toFloat(f64, mod) },
925 80, 128 => unreachable, // TODO
926 else => unreachable,
927 };
928 const result_id = self.spv.allocId();
929 try section.emit(self.spv.gpa, .OpConstant, .{
930 .id_result_type = result_ty_id,
931 .id_result = result_id,
932 .value = lit,
933 });
934 break :cache result_id;
935 },
936 .err => |err| {
937 const value = try mod.getErrorValue(err.name);
938 break :cache try self.constInt(ty, value, repr);
939 },
940 .error_union => |error_union| {
941 // TODO: Error unions may be constructed with constant instructions if the payload type
942 // allows it. For now, just generate it here regardless.
943 const err_int_ty = try mod.errorIntType();
944 const err_ty = switch (error_union.val) {
945 .err_name => ty.errorUnionSet(mod),
946 .payload => err_int_ty,
947 };
948 const err_val = switch (error_union.val) {
949 .err_name => |err_name| Value.fromInterned((try mod.intern(.{ .err = .{
950 .ty = ty.errorUnionSet(mod).toIntern(),
951 .name = err_name,
952 } }))),
953 .payload => try mod.intValue(err_int_ty, 0),
954 };
955 const payload_ty = ty.errorUnionPayload(mod);
956 const eu_layout = self.errorUnionLayout(payload_ty);
957 if (!eu_layout.payload_has_bits) {
958 // We use the error type directly as the type.
959 break :cache try self.constant(err_ty, err_val, .indirect);
996 }960 }
997 }
998
999 // Optional representation is a structure.
1000 // { Payload, Bool }
1001961
1002 const has_pl_id = try self.constBool(maybe_payload_val != null, .indirect);962 const payload_val = Value.fromInterned(switch (error_union.val) {
1003 const payload_id = if (maybe_payload_val) |payload_val|963 .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }),
1004 try self.constant(payload_ty, payload_val, .indirect)964 .payload => |payload| payload,
1005 else965 });
1006 try self.spv.constUndef(try self.resolveType(payload_ty, .indirect));
1007966
1008 return try self.constructStruct(967 var constituents: [2]IdRef = undefined;
1009 ty,968 var types: [2]Type = undefined;
1010 &.{ payload_ty, Type.bool },969 if (eu_layout.error_first) {
1011 &.{ payload_id, has_pl_id },970 constituents[0] = try self.constant(err_ty, err_val, .indirect);
1012 );971 constituents[1] = try self.constant(payload_ty, payload_val, .indirect);
1013 },972 types = .{ err_ty, payload_ty };
1014 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {973 } else {
1015 inline .array_type, .vector_type => |array_type, tag| {974 constituents[0] = try self.constant(payload_ty, payload_val, .indirect);
1016 const elem_ty = Type.fromInterned(array_type.child);975 constituents[1] = try self.constant(err_ty, err_val, .indirect);
1017 const elem_ty_ref = try self.resolveType(elem_ty, .indirect);976 types = .{ payload_ty, err_ty };
1018
1019 const constituents = try self.gpa.alloc(IdRef, @intCast(ty.arrayLenIncludingSentinel(mod)));
1020 defer self.gpa.free(constituents);
1021
1022 switch (aggregate.storage) {
1023 .bytes => |bytes| {
1024 // TODO: This is really space inefficient, perhaps there is a better
1025 // way to do it?
1026 for (bytes, 0..) |byte, i| {
1027 constituents[i] = try self.constInt(elem_ty_ref, byte);
1028 }
1029 },
1030 .elems => |elems| {
1031 for (0..@as(usize, @intCast(array_type.len))) |i| {
1032 constituents[i] = try self.constant(elem_ty, Value.fromInterned(elems[i]), .indirect);
1033 }
1034 },
1035 .repeated_elem => |elem| {
1036 const val_id = try self.constant(elem_ty, Value.fromInterned(elem), .indirect);
1037 for (0..@as(usize, @intCast(array_type.len))) |i| {
1038 constituents[i] = val_id;
1039 }
1040 },
1041 }977 }
1042978
1043 switch (tag) {979 return try self.constructStruct(ty, &types, &constituents);
1044 inline .array_type => {980 },
1045 if (array_type.sentinel != .none) {981 .enum_tag => {
1046 const sentinel = Value.fromInterned(array_type.sentinel);982 const int_val = try val.intFromEnum(ty, mod);
1047 constituents[constituents.len - 1] = try self.constant(elem_ty, sentinel, .indirect);983 const int_ty = ty.intTagType(mod);
1048 }984 break :cache try self.constant(int_ty, int_val, repr);
1049 return self.constructArray(ty, constituents);
1050 },
1051 inline .vector_type => return self.constructVector(ty, constituents),
1052 else => unreachable,
1053 }
1054 },985 },
1055 .struct_type => {986 .ptr => return self.constantPtr(ty, val),
1056 const struct_type = mod.typeToStruct(ty).?;987 .slice => |slice| {
1057 if (struct_type.layout == .@"packed") {988 const ptr_ty = ty.slicePtrFieldType(mod);
1058 return self.todo("packed struct constants", .{});989 const ptr_id = try self.constantPtr(ptr_ty, Value.fromInterned(slice.ptr));
990 const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);
991 return self.constructStruct(
992 ty,
993 &.{ ptr_ty, Type.usize },
994 &.{ ptr_id, len_id },
995 );
996 },
997 .opt => {
998 const payload_ty = ty.optionalChild(mod);
999 const maybe_payload_val = val.optionalValue(mod);
1000
1001 if (!payload_ty.hasRuntimeBits(mod)) {
1002 break :cache try self.constBool(maybe_payload_val != null, .indirect);
1003 } else if (ty.optionalReprIsPayload(mod)) {
1004 // Optional representation is a nullable pointer or slice.
1005 if (maybe_payload_val) |payload_val| {
1006 return try self.constant(payload_ty, payload_val, .indirect);
1007 } else {
1008 break :cache try self.spv.constNull(result_ty_id);
1009 }
1059 }1010 }
10601011
1061 var types = std.ArrayList(Type).init(self.gpa);1012 // Optional representation is a structure.
1062 defer types.deinit();1013 // { Payload, Bool }
10631014
1064 var constituents = std.ArrayList(IdRef).init(self.gpa);1015 const has_pl_id = try self.constBool(maybe_payload_val != null, .indirect);
1065 defer constituents.deinit();1016 const payload_id = if (maybe_payload_val) |payload_val|
1017 try self.constant(payload_ty, payload_val, .indirect)
1018 else
1019 try self.spv.constUndef(try self.resolveType(payload_ty, .indirect));
1020
1021 return try self.constructStruct(
1022 ty,
1023 &.{ payload_ty, Type.bool },
1024 &.{ payload_id, has_pl_id },
1025 );
1026 },
1027 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {
1028 inline .array_type, .vector_type => |array_type, tag| {
1029 const elem_ty = Type.fromInterned(array_type.child);
1030
1031 const constituents = try self.gpa.alloc(IdRef, @as(u32, @intCast(ty.arrayLenIncludingSentinel(mod))));
1032 defer self.gpa.free(constituents);
1033
1034 switch (aggregate.storage) {
1035 .bytes => |bytes| {
1036 // TODO: This is really space inefficient, perhaps there is a better
1037 // way to do it?
1038 for (bytes, 0..) |byte, i| {
1039 constituents[i] = try self.constInt(elem_ty, byte, .indirect);
1040 }
1041 },
1042 .elems => |elems| {
1043 for (0..@as(usize, @intCast(array_type.len))) |i| {
1044 constituents[i] = try self.constant(elem_ty, Value.fromInterned(elems[i]), .indirect);
1045 }
1046 },
1047 .repeated_elem => |elem| {
1048 const val_id = try self.constant(elem_ty, Value.fromInterned(elem), .indirect);
1049 for (0..@as(usize, @intCast(array_type.len))) |i| {
1050 constituents[i] = val_id;
1051 }
1052 },
1053 }
10661054
1067 var it = struct_type.iterateRuntimeOrder(ip);1055 switch (tag) {
1068 while (it.next()) |field_index| {1056 inline .array_type => {
1069 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);1057 if (array_type.sentinel != .none) {
1070 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {1058 const sentinel = Value.fromInterned(array_type.sentinel);
1071 // This is a zero-bit field - we only needed it for the alignment.1059 constituents[constituents.len - 1] = try self.constant(elem_ty, sentinel, .indirect);
1072 continue;1060 }
1061 return self.constructArray(ty, constituents);
1062 },
1063 inline .vector_type => return self.constructVector(ty, constituents),
1064 else => unreachable,
1065 }
1066 },
1067 .struct_type => {
1068 const struct_type = mod.typeToStruct(ty).?;
1069 if (struct_type.layout == .@"packed") {
1070 return self.todo("packed struct constants", .{});
1073 }1071 }
10741072
1075 // TODO: Padding?1073 var types = std.ArrayList(Type).init(self.gpa);
1076 const field_val = try val.fieldValue(mod, field_index);1074 defer types.deinit();
1077 const field_id = try self.constant(field_ty, field_val, .indirect);
10781075
1079 try types.append(field_ty);1076 var constituents = std.ArrayList(IdRef).init(self.gpa);
1080 try constituents.append(field_id);1077 defer constituents.deinit();
1081 }
10821078
1083 return try self.constructStruct(ty, types.items, constituents.items);1079 var it = struct_type.iterateRuntimeOrder(ip);
1080 while (it.next()) |field_index| {
1081 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1082 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
1083 // This is a zero-bit field - we only needed it for the alignment.
1084 continue;
1085 }
1086
1087 // TODO: Padding?
1088 const field_val = try val.fieldValue(mod, field_index);
1089 const field_id = try self.constant(field_ty, field_val, .indirect);
1090
1091 try types.append(field_ty);
1092 try constituents.append(field_id);
1093 }
1094
1095 return try self.constructStruct(ty, types.items, constituents.items);
1096 },
1097 .anon_struct_type => unreachable, // TODO
1098 else => unreachable,
1084 },1099 },
1085 .anon_struct_type => unreachable, // TODO1100 .un => |un| {
1086 else => unreachable,1101 const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), mod).?;
1087 },1102 const union_obj = mod.typeToUnion(ty).?;
1088 .un => |un| {1103 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[active_field]);
1089 const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), mod).?;1104 const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod))
1090 const union_obj = mod.typeToUnion(ty).?;1105 try self.constant(field_ty, Value.fromInterned(un.val), .direct)
1091 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[active_field]);1106 else
1092 const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod))1107 null;
1093 try self.constant(field_ty, Value.fromInterned(un.val), .direct)1108 return try self.unionInit(ty, active_field, payload);
1094 else1109 },
1095 null;1110 .memoized_call => unreachable,
1096 return try self.unionInit(ty, active_field, payload);1111 }
1097 },1112 };
1098 .memoized_call => unreachable,1113
1099 }1114 try self.intern_map.putNoClobber(self.gpa, .{ val.toIntern(), repr }, cacheable_id);
1115
1116 return cacheable_id;
1100 }1117 }
11011118
1102 fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) Error!IdRef {1119 fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) Error!IdRef {
1103 const result_ty_ref = try self.resolveType(ptr_ty, .direct);1120 // TODO: Caching??
1121
1122 const result_ty_id = try self.resolveType(ptr_ty, .direct);
1104 const mod = self.module;1123 const mod = self.module;
11051124
1106 if (ptr_val.isUndef(mod)) return self.spv.constUndef(result_ty_ref);1125 if (ptr_val.isUndef(mod)) return self.spv.constUndef(result_ty_id);
11071126
1108 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {1127 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
1109 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),1128 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),
...@@ -1114,7 +1133,7 @@ const DeclGen = struct {...@@ -1114,7 +1133,7 @@ const DeclGen = struct {
1114 // that is not implemented by Mesa yet. Therefore, just generate it1133 // that is not implemented by Mesa yet. Therefore, just generate it
1115 // as a runtime operation.1134 // as a runtime operation.
1116 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{1135 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
1117 .id_result_type = self.typeId(result_ty_ref),1136 .id_result_type = result_ty_id,
1118 .id_result = ptr_id,1137 .id_result = ptr_id,
1119 .integer_value = try self.constant(Type.usize, Value.fromInterned(int), .direct),1138 .integer_value = try self.constant(Type.usize, Value.fromInterned(int), .direct),
1120 });1139 });
...@@ -1126,23 +1145,23 @@ const DeclGen = struct {...@@ -1126,23 +1145,23 @@ const DeclGen = struct {
1126 .elem => |elem_ptr| {1145 .elem => |elem_ptr| {
1127 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));1146 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));
1128 const parent_ptr_id = try self.constantPtr(parent_ptr_ty, Value.fromInterned(elem_ptr.base));1147 const parent_ptr_id = try self.constantPtr(parent_ptr_ty, Value.fromInterned(elem_ptr.base));
1129 const size_ty_ref = try self.sizeType();1148 const index_id = try self.constInt(Type.usize, elem_ptr.index, .direct);
1130 const index_id = try self.constInt(size_ty_ref, elem_ptr.index);
11311149
1132 const elem_ptr_id = try self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);1150 const elem_ptr_id = try self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);
11331151
1134 // TODO: Can we consolidate this in ptrElemPtr?1152 // TODO: Can we consolidate this in ptrElemPtr?
1135 const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T.1153 const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T.
1136 const elem_ptr_ty_ref = try self.ptrType(elem_ty, self.spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod)));1154 const elem_ptr_ty_id = try self.ptrType(elem_ty, self.spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod)));
11371155
1138 if (elem_ptr_ty_ref == result_ty_ref) {1156 // TODO: Can we remove this ID comparison?
1157 if (elem_ptr_ty_id == result_ty_id) {
1139 return elem_ptr_id;1158 return elem_ptr_id;
1140 }1159 }
1141 // This may happen when we have pointer-to-array and the result is1160 // This may happen when we have pointer-to-array and the result is
1142 // another pointer-to-array instead of a pointer-to-element.1161 // another pointer-to-array instead of a pointer-to-element.
1143 const result_id = self.spv.allocId();1162 const result_id = self.spv.allocId();
1144 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{1163 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
1145 .id_result_type = self.typeId(result_ty_ref),1164 .id_result_type = result_ty_id,
1146 .id_result = result_id,1165 .id_result = result_id,
1147 .operand = elem_ptr_id,1166 .operand = elem_ptr_id,
1148 });1167 });
...@@ -1166,7 +1185,7 @@ const DeclGen = struct {...@@ -1166,7 +1185,7 @@ const DeclGen = struct {
11661185
1167 const mod = self.module;1186 const mod = self.module;
1168 const ip = &mod.intern_pool;1187 const ip = &mod.intern_pool;
1169 const ty_ref = try self.resolveType(ty, .direct);1188 const ty_id = try self.resolveType(ty, .direct);
1170 const decl_val = anon_decl.val;1189 const decl_val = anon_decl.val;
1171 const decl_ty = Type.fromInterned(ip.typeOf(decl_val));1190 const decl_ty = Type.fromInterned(ip.typeOf(decl_val));
11721191
...@@ -1181,7 +1200,7 @@ const DeclGen = struct {...@@ -1181,7 +1200,7 @@ const DeclGen = struct {
1181 // const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;1200 // const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
1182 if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {1201 if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
1183 // Pointer to nothing - return undefoined1202 // Pointer to nothing - return undefoined
1184 return self.spv.constUndef(ty_ref);1203 return self.spv.constUndef(ty_id);
1185 }1204 }
11861205
1187 if (decl_ty.zigTypeTag(mod) == .Fn) {1206 if (decl_ty.zigTypeTag(mod) == .Fn) {
...@@ -1190,14 +1209,14 @@ const DeclGen = struct {...@@ -1190,14 +1209,14 @@ const DeclGen = struct {
11901209
1191 // Anon decl refs are always generic.1210 // Anon decl refs are always generic.
1192 assert(ty.ptrAddressSpace(mod) == .generic);1211 assert(ty.ptrAddressSpace(mod) == .generic);
1193 const decl_ptr_ty_ref = try self.ptrType(decl_ty, .Generic);1212 const decl_ptr_ty_id = try self.ptrType(decl_ty, .Generic);
1194 const ptr_id = try self.resolveAnonDecl(decl_val);1213 const ptr_id = try self.resolveAnonDecl(decl_val);
11951214
1196 if (decl_ptr_ty_ref != ty_ref) {1215 if (decl_ptr_ty_id != ty_id) {
1197 // Differing pointer types, insert a cast.1216 // Differing pointer types, insert a cast.
1198 const casted_ptr_id = self.spv.allocId();1217 const casted_ptr_id = self.spv.allocId();
1199 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{1218 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
1200 .id_result_type = self.typeId(ty_ref),1219 .id_result_type = ty_id,
1201 .id_result = casted_ptr_id,1220 .id_result = casted_ptr_id,
1202 .operand = ptr_id,1221 .operand = ptr_id,
1203 });1222 });
...@@ -1209,15 +1228,14 @@ const DeclGen = struct {...@@ -1209,15 +1228,14 @@ const DeclGen = struct {
12091228
1210 fn constantDeclRef(self: *DeclGen, ty: Type, decl_index: InternPool.DeclIndex) !IdRef {1229 fn constantDeclRef(self: *DeclGen, ty: Type, decl_index: InternPool.DeclIndex) !IdRef {
1211 const mod = self.module;1230 const mod = self.module;
1212 const ty_ref = try self.resolveType(ty, .direct);1231 const ty_id = try self.resolveType(ty, .direct);
1213 const ty_id = self.typeId(ty_ref);
1214 const decl = mod.declPtr(decl_index);1232 const decl = mod.declPtr(decl_index);
12151233
1216 switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {1234 switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {
1217 .func => {1235 .func => {
1218 // TODO: Properly lower function pointers. For now we are going to hack around it and1236 // TODO: Properly lower function pointers. For now we are going to hack around it and
1219 // just generate an empty pointer. Function pointers are represented by a pointer to usize.1237 // just generate an empty pointer. Function pointers are represented by a pointer to usize.
1220 return try self.spv.constUndef(ty_ref);1238 return try self.spv.constUndef(ty_id);
1221 },1239 },
1222 .extern_func => unreachable, // TODO1240 .extern_func => unreachable, // TODO
1223 else => {},1241 else => {},
...@@ -1225,7 +1243,7 @@ const DeclGen = struct {...@@ -1225,7 +1243,7 @@ const DeclGen = struct {
12251243
1226 if (!decl.typeOf(mod).isFnOrHasRuntimeBitsIgnoreComptime(mod)) {1244 if (!decl.typeOf(mod).isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
1227 // Pointer to nothing - return undefined.1245 // Pointer to nothing - return undefined.
1228 return self.spv.constUndef(ty_ref);1246 return self.spv.constUndef(ty_id);
1229 }1247 }
12301248
1231 const spv_decl_index = try self.object.resolveDecl(mod, decl_index);1249 const spv_decl_index = try self.object.resolveDecl(mod, decl_index);
...@@ -1239,14 +1257,14 @@ const DeclGen = struct {...@@ -1239,14 +1257,14 @@ const DeclGen = struct {
1239 const final_storage_class = self.spvStorageClass(decl.@"addrspace");1257 const final_storage_class = self.spvStorageClass(decl.@"addrspace");
1240 try self.addFunctionDep(spv_decl_index, final_storage_class);1258 try self.addFunctionDep(spv_decl_index, final_storage_class);
12411259
1242 const decl_ptr_ty_ref = try self.ptrType(decl.typeOf(mod), final_storage_class);1260 const decl_ptr_ty_id = try self.ptrType(decl.typeOf(mod), final_storage_class);
12431261
1244 const ptr_id = switch (final_storage_class) {1262 const ptr_id = switch (final_storage_class) {
1245 .Generic => try self.castToGeneric(self.typeId(decl_ptr_ty_ref), decl_id),1263 .Generic => try self.castToGeneric(decl_ptr_ty_id, decl_id),
1246 else => decl_id,1264 else => decl_id,
1247 };1265 };
12481266
1249 if (decl_ptr_ty_ref != ty_ref) {1267 if (decl_ptr_ty_id != ty_id) {
1250 // Differing pointer types, insert a cast.1268 // Differing pointer types, insert a cast.
1251 const casted_ptr_id = self.spv.allocId();1269 const casted_ptr_id = self.spv.allocId();
1252 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{1270 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
...@@ -1261,28 +1279,18 @@ const DeclGen = struct {...@@ -1261,28 +1279,18 @@ const DeclGen = struct {
1261 }1279 }
12621280
1263 // Turn a Zig type's name into a cache reference.1281 // Turn a Zig type's name into a cache reference.
1264 fn resolveTypeName(self: *DeclGen, ty: Type) !CacheString {1282 fn resolveTypeName(self: *DeclGen, ty: Type) ![]const u8 {
1265 var name = std.ArrayList(u8).init(self.gpa);1283 var name = std.ArrayList(u8).init(self.gpa);
1266 defer name.deinit();1284 defer name.deinit();
1267 try ty.print(name.writer(), self.module);1285 try ty.print(name.writer(), self.module);
1268 return try self.spv.resolveString(name.items);1286 return try name.toOwnedSlice();
1269 }
1270
1271 /// Turn a Zig type into a SPIR-V Type, and return its type result-id.
1272 fn resolveTypeId(self: *DeclGen, ty: Type) !IdResultType {
1273 const type_ref = try self.resolveType(ty, .direct);
1274 return self.spv.resultId(type_ref);
1275 }
1276
1277 fn typeId(self: *DeclGen, ty_ref: CacheRef) IdRef {
1278 return self.spv.resultId(ty_ref);
1279 }1287 }
12801288
1281 /// Create an integer type suitable for storing at least 'bits' bits.1289 /// Create an integer type suitable for storing at least 'bits' bits.
1282 /// The integer type that is returned by this function is the type that is used to perform1290 /// The integer type that is returned by this function is the type that is used to perform
1283 /// actual operations (as well as store) a Zig type of a particular number of bits. To create1291 /// actual operations (as well as store) a Zig type of a particular number of bits. To create
1284 /// a type with an exact size, use SpvModule.intType.1292 /// a type with an exact size, use SpvModule.intType.
1285 fn intType(self: *DeclGen, signedness: std.builtin.Signedness, bits: u16) !CacheRef {1293 fn intType(self: *DeclGen, signedness: std.builtin.Signedness, bits: u16) !IdRef {
1286 const backing_bits = self.backingIntBits(bits) orelse {1294 const backing_bits = self.backingIntBits(bits) orelse {
1287 // TODO: Integers too big for any native type are represented as "composite integers":1295 // TODO: Integers too big for any native type are represented as "composite integers":
1288 // An array of largestSupportedIntBits.1296 // An array of largestSupportedIntBits.
...@@ -1297,36 +1305,69 @@ const DeclGen = struct {...@@ -1297,36 +1305,69 @@ const DeclGen = struct {
1297 return self.spv.intType(.unsigned, backing_bits);1305 return self.spv.intType(.unsigned, backing_bits);
1298 }1306 }
12991307
1300 /// Create an integer type that represents 'usize'.1308 fn arrayType(self: *DeclGen, len: u32, child_ty: IdRef) !IdRef {
1301 fn sizeType(self: *DeclGen) !CacheRef {1309 // TODO: Cache??
1302 return try self.intType(.unsigned, self.getTarget().ptrBitWidth());1310 const len_id = try self.constInt(Type.u32, len, .direct);
1311 const result_id = self.spv.allocId();
1312
1313 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypeArray, .{
1314 .id_result = result_id,
1315 .element_type = child_ty,
1316 .length = len_id,
1317 });
1318 return result_id;
1303 }1319 }
13041320
1305 fn ptrType(self: *DeclGen, child_ty: Type, storage_class: StorageClass) !CacheRef {1321 fn ptrType(self: *DeclGen, child_ty: Type, storage_class: StorageClass) !IdRef {
1306 const key = .{ child_ty.toIntern(), storage_class };1322 const key = .{ child_ty.toIntern(), storage_class };
1307 const entry = try self.wip_pointers.getOrPut(self.gpa, key);1323 const entry = try self.ptr_types.getOrPut(self.gpa, key);
1308 if (entry.found_existing) {1324 if (entry.found_existing) {
1309 const fwd_ref = entry.value_ptr.*;1325 const fwd_id = entry.value_ptr.ty_id;
1310 try self.spv.cache.recursive_ptrs.put(self.spv.gpa, fwd_ref, {});1326 if (!entry.value_ptr.fwd_emitted) {
1311 return fwd_ref;1327 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypeForwardPointer, .{
1328 .pointer_type = fwd_id,
1329 .storage_class = storage_class,
1330 });
1331 entry.value_ptr.fwd_emitted = true;
1332 }
1333 return fwd_id;
1312 }1334 }
13131335
1314 const fwd_ref = try self.spv.resolve(.{ .fwd_ptr_type = .{1336 const result_id = self.spv.allocId();
1315 .zig_child_type = child_ty.toIntern(),1337 entry.value_ptr.* = .{
1316 .storage_class = storage_class,1338 .ty_id = result_id,
1317 } });1339 .fwd_emitted = false,
1318 entry.value_ptr.* = fwd_ref;1340 };
13191341
1320 const child_ty_ref = try self.resolveType(child_ty, .indirect);1342 const child_ty_id = try self.resolveType(child_ty, .indirect);
1321 _ = try self.spv.resolve(.{ .ptr_type = .{1343
1344 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypePointer, .{
1345 .id_result = result_id,
1322 .storage_class = storage_class,1346 .storage_class = storage_class,
1323 .child_type = child_ty_ref,1347 .type = child_ty_id,
1324 .fwd = fwd_ref,1348 });
1325 } });1349
1350 return result_id;
1351 }
1352
1353 fn functionType(self: *DeclGen, return_ty: Type, param_types: []const Type) !IdRef {
1354 // TODO: Cache??
13261355
1327 assert(self.wip_pointers.remove(key));1356 const param_ids = try self.gpa.alloc(IdRef, param_types.len);
1357 defer self.gpa.free(param_ids);
13281358
1329 return fwd_ref;1359 for (param_types, param_ids) |param_ty, *param_id| {
1360 param_id.* = try self.resolveType(param_ty, .direct);
1361 }
1362
1363 const ty_id = self.spv.allocId();
1364 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypeFunction, .{
1365 .id_result = ty_id,
1366 .return_type = try self.resolveFnReturnType(return_ty),
1367 .id_ref_2 = param_ids,
1368 });
1369
1370 return ty_id;
1330 }1371 }
13311372
1332 /// Generate a union type. Union types are always generated with the1373 /// Generate a union type. Union types are always generated with the
...@@ -1347,7 +1388,7 @@ const DeclGen = struct {...@@ -1347,7 +1388,7 @@ const DeclGen = struct {
1347 /// padding: [padding_size]u8,1388 /// padding: [padding_size]u8,
1348 /// }1389 /// }
1349 /// If any of the fields' size is 0, it will be omitted.1390 /// If any of the fields' size is 0, it will be omitted.
1350 fn resolveUnionType(self: *DeclGen, ty: Type) !CacheRef {1391 fn resolveUnionType(self: *DeclGen, ty: Type) !IdRef {
1351 const mod = self.module;1392 const mod = self.module;
1352 const ip = &mod.intern_pool;1393 const ip = &mod.intern_pool;
1353 const union_obj = mod.typeToUnion(ty).?;1394 const union_obj = mod.typeToUnion(ty).?;
...@@ -1362,48 +1403,43 @@ const DeclGen = struct {...@@ -1362,48 +1403,43 @@ const DeclGen = struct {
1362 return try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect);1403 return try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect);
1363 }1404 }
13641405
1365 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;1406 var member_types: [4]IdRef = undefined;
1407 var member_names: [4][]const u8 = undefined;
13661408
1367 var member_types: [4]CacheRef = undefined;1409 const u8_ty_id = try self.resolveType(Type.u8, .direct); // TODO: What if Int8Type is not enabled?
1368 var member_names: [4]CacheString = undefined;
1369
1370 const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled?
13711410
1372 if (layout.tag_size != 0) {1411 if (layout.tag_size != 0) {
1373 const tag_ty_ref = try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect);1412 const tag_ty_id = try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect);
1374 member_types[layout.tag_index] = tag_ty_ref;1413 member_types[layout.tag_index] = tag_ty_id;
1375 member_names[layout.tag_index] = try self.spv.resolveString("(tag)");1414 member_names[layout.tag_index] = "(tag)";
1376 }1415 }
13771416
1378 if (layout.payload_size != 0) {1417 if (layout.payload_size != 0) {
1379 const payload_ty_ref = try self.resolveType(layout.payload_ty, .indirect);1418 const payload_ty_id = try self.resolveType(layout.payload_ty, .indirect);
1380 member_types[layout.payload_index] = payload_ty_ref;1419 member_types[layout.payload_index] = payload_ty_id;
1381 member_names[layout.payload_index] = try self.spv.resolveString("(payload)");1420 member_names[layout.payload_index] = "(payload)";
1382 }1421 }
13831422
1384 if (layout.payload_padding_size != 0) {1423 if (layout.payload_padding_size != 0) {
1385 const payload_padding_ty_ref = try self.spv.arrayType(@intCast(layout.payload_padding_size), u8_ty_ref);1424 const payload_padding_ty_id = try self.arrayType(@intCast(layout.payload_padding_size), u8_ty_id);
1386 member_types[layout.payload_padding_index] = payload_padding_ty_ref;1425 member_types[layout.payload_padding_index] = payload_padding_ty_id;
1387 member_names[layout.payload_padding_index] = try self.spv.resolveString("(payload padding)");1426 member_names[layout.payload_padding_index] = "(payload padding)";
1388 }1427 }
13891428
1390 if (layout.padding_size != 0) {1429 if (layout.padding_size != 0) {
1391 const padding_ty_ref = try self.spv.arrayType(@intCast(layout.padding_size), u8_ty_ref);1430 const padding_ty_id = try self.arrayType(@intCast(layout.padding_size), u8_ty_id);
1392 member_types[layout.padding_index] = padding_ty_ref;1431 member_types[layout.padding_index] = padding_ty_id;
1393 member_names[layout.padding_index] = try self.spv.resolveString("(padding)");1432 member_names[layout.padding_index] = "(padding)";
1394 }1433 }
13951434
1396 const ty_ref = try self.spv.resolve(.{ .struct_type = .{1435 const result_id = try self.spv.structType(member_types[0..layout.total_fields], member_names[0..layout.total_fields]);
1397 .name = try self.resolveTypeName(ty),1436 const type_name = try self.resolveTypeName(ty);
1398 .member_types = member_types[0..layout.total_fields],1437 defer self.gpa.free(type_name);
1399 .member_names = member_names[0..layout.total_fields],1438 try self.spv.debugName(result_id, type_name);
1400 } });1439 return result_id;
1401
1402 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
1403 return ty_ref;
1404 }1440 }
14051441
1406 fn resolveFnReturnType(self: *DeclGen, ret_ty: Type) !CacheRef {1442 fn resolveFnReturnType(self: *DeclGen, ret_ty: Type) !IdRef {
1407 const mod = self.module;1443 const mod = self.module;
1408 if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {1444 if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {
1409 // If the return type is an error set or an error union, then we make this1445 // If the return type is an error set or an error union, then we make this
...@@ -1420,26 +1456,46 @@ const DeclGen = struct {...@@ -1420,26 +1456,46 @@ const DeclGen = struct {
1420 }1456 }
14211457
1422 /// Turn a Zig type into a SPIR-V Type, and return a reference to it.1458 /// Turn a Zig type into a SPIR-V Type, and return a reference to it.
1423 fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!CacheRef {1459 fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!IdRef {
1460 if (self.intern_map.get(.{ ty.toIntern(), repr })) |id| {
1461 return id;
1462 }
1463
1464 const id = try self.resolveTypeInner(ty, repr);
1465 try self.intern_map.put(self.gpa, .{ ty.toIntern(), repr }, id);
1466 return id;
1467 }
1468
1469 fn resolveTypeInner(self: *DeclGen, ty: Type, repr: Repr) Error!IdRef {
1424 const mod = self.module;1470 const mod = self.module;
1425 const ip = &mod.intern_pool;1471 const ip = &mod.intern_pool;
1426 log.debug("resolveType: ty = {}", .{ty.fmt(mod)});1472 log.debug("resolveType: ty = {}", .{ty.fmt(mod)});
1427 const target = self.getTarget();1473 const target = self.getTarget();
1474
1475 const section = &self.spv.sections.types_globals_constants;
1476
1428 switch (ty.zigTypeTag(mod)) {1477 switch (ty.zigTypeTag(mod)) {
1429 .NoReturn => {1478 .NoReturn => {
1430 assert(repr == .direct);1479 assert(repr == .direct);
1431 return try self.spv.resolve(.void_type);1480 return try self.spv.voidType();
1432 },1481 },
1433 .Void => switch (repr) {1482 .Void => switch (repr) {
1434 .direct => return try self.spv.resolve(.void_type),1483 .direct => {
1484 return try self.spv.voidType();
1485 },
1435 // Pointers to void1486 // Pointers to void
1436 .indirect => return try self.spv.resolve(.{ .opaque_type = .{1487 .indirect => {
1437 .name = try self.spv.resolveString("void"),1488 const result_id = self.spv.allocId();
1438 } }),1489 try section.emit(self.spv.gpa, .OpTypeOpaque, .{
1490 .id_result = result_id,
1491 .literal_string = "void",
1492 });
1493 return result_id;
1494 },
1439 },1495 },
1440 .Bool => switch (repr) {1496 .Bool => switch (repr) {
1441 .direct => return try self.spv.resolve(.bool_type),1497 .direct => return try self.spv.boolType(),
1442 .indirect => return try self.intType(.unsigned, 1),1498 .indirect => return try self.resolveType(Type.u1, .indirect),
1443 },1499 },
1444 .Int => {1500 .Int => {
1445 const int_info = ty.intInfo(mod);1501 const int_info = ty.intInfo(mod);
...@@ -1447,15 +1503,18 @@ const DeclGen = struct {...@@ -1447,15 +1503,18 @@ const DeclGen = struct {
1447 // Some times, the backend will be asked to generate a pointer to i0. OpTypeInt1503 // Some times, the backend will be asked to generate a pointer to i0. OpTypeInt
1448 // with 0 bits is invalid, so return an opaque type in this case.1504 // with 0 bits is invalid, so return an opaque type in this case.
1449 assert(repr == .indirect);1505 assert(repr == .indirect);
1450 return try self.spv.resolve(.{ .opaque_type = .{1506 const result_id = self.spv.allocId();
1451 .name = try self.spv.resolveString("u0"),1507 try section.emit(self.spv.gpa, .OpTypeOpaque, .{
1452 } });1508 .id_result = result_id,
1509 .literal_string = "u0",
1510 });
1511 return result_id;
1453 }1512 }
1454 return try self.intType(int_info.signedness, int_info.bits);1513 return try self.intType(int_info.signedness, int_info.bits);
1455 },1514 },
1456 .Enum => {1515 .Enum => {
1457 const tag_ty = ty.intTagType(mod);1516 const tag_ty = ty.intTagType(mod);
1458 return self.resolveType(tag_ty, repr);1517 return try self.resolveType(tag_ty, repr);
1459 },1518 },
1460 .Float => {1519 .Float => {
1461 // We can (and want) not really emulate floating points with other floating point types like with the integer types,1520 // We can (and want) not really emulate floating points with other floating point types like with the integer types,
...@@ -1473,27 +1532,29 @@ const DeclGen = struct {...@@ -1473,27 +1532,29 @@ const DeclGen = struct {
1473 return self.fail("Floating point width of {} bits is not supported for the current SPIR-V feature set", .{bits});1532 return self.fail("Floating point width of {} bits is not supported for the current SPIR-V feature set", .{bits});
1474 }1533 }
14751534
1476 return try self.spv.resolve(.{ .float_type = .{ .bits = bits } });1535 return try self.spv.floatType(bits);
1477 },1536 },
1478 .Array => {1537 .Array => {
1479 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;
1480
1481 const elem_ty = ty.childType(mod);1538 const elem_ty = ty.childType(mod);
1482 const elem_ty_ref = try self.resolveType(elem_ty, .indirect);1539 const elem_ty_id = try self.resolveType(elem_ty, .indirect);
1483 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse {1540 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse {
1484 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)});1541 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)});
1485 };1542 };
1486 const ty_ref = if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {1543
1544 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) {
1487 // The size of the array would be 0, but that is not allowed in SPIR-V.1545 // The size of the array would be 0, but that is not allowed in SPIR-V.
1488 // This path can be reached when the backend is asked to generate a pointer to1546 // This path can be reached when the backend is asked to generate a pointer to
1489 // an array of some zero-bit type. This should always be an indirect path.1547 // an array of some zero-bit type. This should always be an indirect path.
1490 assert(repr == .indirect);1548 assert(repr == .indirect);
14911549
1492 // We cannot use the child type here, so just use an opaque type.1550 // We cannot use the child type here, so just use an opaque type.
1493 break :blk try self.spv.resolve(.{ .opaque_type = .{1551 const result_id = self.spv.allocId();
1494 .name = try self.spv.resolveString("zero-sized array"),1552 try section.emit(self.spv.gpa, .OpTypeOpaque, .{
1495 } });1553 .id_result = result_id,
1496 } else if (total_len == 0) blk: {1554 .literal_string = "zero-sized array",
1555 });
1556 return result_id;
1557 } else if (total_len == 0) {
1497 // The size of the array would be 0, but that is not allowed in SPIR-V.1558 // The size of the array would be 0, but that is not allowed in SPIR-V.
1498 // This path can be reached for example when there is a slicing of a pointer1559 // This path can be reached for example when there is a slicing of a pointer
1499 // that produces a zero-length array. In all cases where this type can be generated,1560 // that produces a zero-length array. In all cases where this type can be generated,
...@@ -1503,16 +1564,13 @@ const DeclGen = struct {...@@ -1503,16 +1564,13 @@ const DeclGen = struct {
1503 // In this case, we have an array of a non-zero sized type. In this case,1564 // In this case, we have an array of a non-zero sized type. In this case,
1504 // generate an array of 1 element instead, so that ptr_elem_ptr instructions1565 // generate an array of 1 element instead, so that ptr_elem_ptr instructions
1505 // can be lowered to ptrAccessChain instead of manually performing the math.1566 // can be lowered to ptrAccessChain instead of manually performing the math.
1506 break :blk try self.spv.arrayType(1, elem_ty_ref);1567 return try self.arrayType(1, elem_ty_id);
1507 } else try self.spv.arrayType(total_len, elem_ty_ref);1568 } else {
15081569 return try self.arrayType(total_len, elem_ty_id);
1509 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });1570 }
1510 return ty_ref;
1511 },1571 },
1512 .Fn => switch (repr) {1572 .Fn => switch (repr) {
1513 .direct => {1573 .direct => {
1514 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;
1515
1516 const fn_info = mod.typeToFunc(ty).?;1574 const fn_info = mod.typeToFunc(ty).?;
15171575
1518 comptime assert(zig_call_abi_ver == 3);1576 comptime assert(zig_call_abi_ver == 3);
...@@ -1525,75 +1583,67 @@ const DeclGen = struct {...@@ -1525,75 +1583,67 @@ const DeclGen = struct {
1525 if (fn_info.is_var_args)1583 if (fn_info.is_var_args)
1526 return self.fail("VarArgs functions are unsupported for SPIR-V", .{});1584 return self.fail("VarArgs functions are unsupported for SPIR-V", .{});
15271585
1528 const param_ty_refs = try self.gpa.alloc(CacheRef, fn_info.param_types.len);1586 // Note: Logic is different from functionType().
1529 defer self.gpa.free(param_ty_refs);1587 const param_ty_ids = try self.gpa.alloc(IdRef, fn_info.param_types.len);
1588 defer self.gpa.free(param_ty_ids);
1530 var param_index: usize = 0;1589 var param_index: usize = 0;
1531 for (fn_info.param_types.get(ip)) |param_ty_index| {1590 for (fn_info.param_types.get(ip)) |param_ty_index| {
1532 const param_ty = Type.fromInterned(param_ty_index);1591 const param_ty = Type.fromInterned(param_ty_index);
1533 if (!param_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;1592 if (!param_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
15341593
1535 param_ty_refs[param_index] = try self.resolveType(param_ty, .direct);1594 param_ty_ids[param_index] = try self.resolveType(param_ty, .direct);
1536 param_index += 1;1595 param_index += 1;
1537 }1596 }
1538 const return_ty_ref = try self.resolveFnReturnType(Type.fromInterned(fn_info.return_type));
15391597
1540 const ty_ref = try self.spv.resolve(.{ .function_type = .{1598 const return_ty_id = try self.resolveFnReturnType(Type.fromInterned(fn_info.return_type));
1541 .return_type = return_ty_ref,1599
1542 .parameters = param_ty_refs[0..param_index],1600 const result_id = self.spv.allocId();
1543 } });1601 try section.emit(self.spv.gpa, .OpTypeFunction, .{
1602 .id_result = result_id,
1603 .return_type = return_ty_id,
1604 .id_ref_2 = param_ty_ids[0..param_index],
1605 });
15441606
1545 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });1607 return result_id;
1546 return ty_ref;
1547 },1608 },
1548 .indirect => {1609 .indirect => {
1549 // TODO: Represent function pointers properly.1610 // TODO: Represent function pointers properly.
1550 // For now, just use an usize type.1611 // For now, just use an usize type.
1551 return try self.sizeType();1612 return try self.resolveType(Type.usize, .indirect);
1552 },1613 },
1553 },1614 },
1554 .Pointer => {1615 .Pointer => {
1555 const ptr_info = ty.ptrInfo(mod);1616 const ptr_info = ty.ptrInfo(mod);
15561617
1557 // Note: Don't cache this pointer type, it would mess up the recursive pointer functionality
1558 // in ptrType()!
1559
1560 const storage_class = self.spvStorageClass(ptr_info.flags.address_space);1618 const storage_class = self.spvStorageClass(ptr_info.flags.address_space);
1561 const ptr_ty_ref = try self.ptrType(Type.fromInterned(ptr_info.child), storage_class);1619 const ptr_ty_id = try self.ptrType(Type.fromInterned(ptr_info.child), storage_class);
15621620
1563 if (ptr_info.flags.size != .Slice) {1621 if (ptr_info.flags.size != .Slice) {
1564 return ptr_ty_ref;1622 return ptr_ty_id;
1565 }1623 }
15661624
1567 const size_ty_ref = try self.sizeType();1625 const size_ty_id = try self.resolveType(Type.usize, .direct);
1568 return self.spv.resolve(.{ .struct_type = .{1626 return self.spv.structType(
1569 .member_types = &.{ ptr_ty_ref, size_ty_ref },1627 &.{ ptr_ty_id, size_ty_id },
1570 .member_names = &.{1628 &.{ "ptr", "len" },
1571 try self.spv.resolveString("ptr"),1629 );
1572 try self.spv.resolveString("len"),
1573 },
1574 } });
1575 },1630 },
1576 .Vector => {1631 .Vector => {
1577 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;
1578
1579 const elem_ty = ty.childType(mod);1632 const elem_ty = ty.childType(mod);
1580 const elem_ty_ref = try self.resolveType(elem_ty, .indirect);1633 // TODO: Make `.direct`.
1634 const elem_ty_id = try self.resolveType(elem_ty, .indirect);
1581 const len = ty.vectorLen(mod);1635 const len = ty.vectorLen(mod);
15821636
1583 const ty_ref = if (self.isVector(ty))1637 if (self.isVector(ty)) {
1584 try self.spv.vectorType(len, elem_ty_ref)1638 return try self.spv.vectorType(len, elem_ty_id);
1585 else1639 } else {
1586 try self.spv.arrayType(len, elem_ty_ref);1640 return try self.arrayType(len, elem_ty_id);
15871641 }
1588 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
1589 return ty_ref;
1590 },1642 },
1591 .Struct => {1643 .Struct => {
1592 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;
1593
1594 const struct_type = switch (ip.indexToKey(ty.toIntern())) {1644 const struct_type = switch (ip.indexToKey(ty.toIntern())) {
1595 .anon_struct_type => |tuple| {1645 .anon_struct_type => |tuple| {
1596 const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);1646 const member_types = try self.gpa.alloc(IdRef, tuple.values.len);
1597 defer self.gpa.free(member_types);1647 defer self.gpa.free(member_types);
15981648
1599 var member_index: usize = 0;1649 var member_index: usize = 0;
...@@ -1604,13 +1654,11 @@ const DeclGen = struct {...@@ -1604,13 +1654,11 @@ const DeclGen = struct {
1604 member_index += 1;1654 member_index += 1;
1605 }1655 }
16061656
1607 const ty_ref = try self.spv.resolve(.{ .struct_type = .{1657 const result_id = try self.spv.structType(member_types[0..member_index], null);
1608 .name = try self.resolveTypeName(ty),1658 const type_name = try self.resolveTypeName(ty);
1609 .member_types = member_types[0..member_index],1659 defer self.gpa.free(type_name);
1610 } });1660 try self.spv.debugName(result_id, type_name);
16111661 return result_id;
1612 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
1613 return ty_ref;
1614 },1662 },
1615 .struct_type => ip.loadStructType(ty.toIntern()),1663 .struct_type => ip.loadStructType(ty.toIntern()),
1616 else => unreachable,1664 else => unreachable,
...@@ -1620,10 +1668,10 @@ const DeclGen = struct {...@@ -1620,10 +1668,10 @@ const DeclGen = struct {
1620 return try self.resolveType(Type.fromInterned(struct_type.backingIntType(ip).*), .direct);1668 return try self.resolveType(Type.fromInterned(struct_type.backingIntType(ip).*), .direct);
1621 }1669 }
16221670
1623 var member_types = std.ArrayList(CacheRef).init(self.gpa);1671 var member_types = std.ArrayList(IdRef).init(self.gpa);
1624 defer member_types.deinit();1672 defer member_types.deinit();
16251673
1626 var member_names = std.ArrayList(CacheString).init(self.gpa);1674 var member_names = std.ArrayList([]const u8).init(self.gpa);
1627 defer member_names.deinit();1675 defer member_names.deinit();
16281676
1629 var it = struct_type.iterateRuntimeOrder(ip);1677 var it = struct_type.iterateRuntimeOrder(ip);
...@@ -1637,17 +1685,14 @@ const DeclGen = struct {...@@ -1637,17 +1685,14 @@ const DeclGen = struct {
1637 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse1685 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
1638 try ip.getOrPutStringFmt(mod.gpa, "{d}", .{field_index});1686 try ip.getOrPutStringFmt(mod.gpa, "{d}", .{field_index});
1639 try member_types.append(try self.resolveType(field_ty, .indirect));1687 try member_types.append(try self.resolveType(field_ty, .indirect));
1640 try member_names.append(try self.spv.resolveString(ip.stringToSlice(field_name)));1688 try member_names.append(ip.stringToSlice(field_name));
1641 }1689 }
16421690
1643 const ty_ref = try self.spv.resolve(.{ .struct_type = .{1691 const result_id = try self.spv.structType(member_types.items, member_names.items);
1644 .name = try self.resolveTypeName(ty),1692 const type_name = try self.resolveTypeName(ty);
1645 .member_types = member_types.items,1693 defer self.gpa.free(type_name);
1646 .member_names = member_names.items,1694 try self.spv.debugName(result_id, type_name);
1647 } });1695 return result_id;
1648
1649 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
1650 return ty_ref;
1651 },1696 },
1652 .Optional => {1697 .Optional => {
1653 const payload_ty = ty.optionalChild(mod);1698 const payload_ty = ty.optionalChild(mod);
...@@ -1658,77 +1703,58 @@ const DeclGen = struct {...@@ -1658,77 +1703,58 @@ const DeclGen = struct {
1658 return try self.resolveType(Type.bool, .indirect);1703 return try self.resolveType(Type.bool, .indirect);
1659 }1704 }
16601705
1661 const payload_ty_ref = try self.resolveType(payload_ty, .indirect);1706 const payload_ty_id = try self.resolveType(payload_ty, .indirect);
1662 if (ty.optionalReprIsPayload(mod)) {1707 if (ty.optionalReprIsPayload(mod)) {
1663 // Optional is actually a pointer or a slice.1708 // Optional is actually a pointer or a slice.
1664 return payload_ty_ref;1709 return payload_ty_id;
1665 }1710 }
16661711
1667 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;1712 const bool_ty_id = try self.resolveType(Type.bool, .indirect);
1668
1669 const bool_ty_ref = try self.resolveType(Type.bool, .indirect);
16701713
1671 const ty_ref = try self.spv.resolve(.{ .struct_type = .{1714 return try self.spv.structType(
1672 .member_types = &.{ payload_ty_ref, bool_ty_ref },1715 &.{ payload_ty_id, bool_ty_id },
1673 .member_names = &.{1716 &.{ "payload", "valid" },
1674 try self.spv.resolveString("payload"),1717 );
1675 try self.spv.resolveString("valid"),
1676 },
1677 } });
1678
1679 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
1680 return ty_ref;
1681 },1718 },
1682 .Union => return try self.resolveUnionType(ty),1719 .Union => return try self.resolveUnionType(ty),
1683 .ErrorSet => return try self.intType(.unsigned, 16),1720 .ErrorSet => return try self.resolveType(Type.u16, repr),
1684 .ErrorUnion => {1721 .ErrorUnion => {
1685 const payload_ty = ty.errorUnionPayload(mod);1722 const payload_ty = ty.errorUnionPayload(mod);
1686 const error_ty_ref = try self.resolveType(Type.anyerror, .indirect);1723 const error_ty_id = try self.resolveType(Type.anyerror, .indirect);
16871724
1688 const eu_layout = self.errorUnionLayout(payload_ty);1725 const eu_layout = self.errorUnionLayout(payload_ty);
1689 if (!eu_layout.payload_has_bits) {1726 if (!eu_layout.payload_has_bits) {
1690 return error_ty_ref;1727 return error_ty_id;
1691 }1728 }
16921729
1693 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;1730 const payload_ty_id = try self.resolveType(payload_ty, .indirect);
16941731
1695 const payload_ty_ref = try self.resolveType(payload_ty, .indirect);1732 var member_types: [2]IdRef = undefined;
16961733 var member_names: [2][]const u8 = undefined;
1697 var member_types: [2]CacheRef = undefined;
1698 var member_names: [2]CacheString = undefined;
1699 if (eu_layout.error_first) {1734 if (eu_layout.error_first) {
1700 // Put the error first1735 // Put the error first
1701 member_types = .{ error_ty_ref, payload_ty_ref };1736 member_types = .{ error_ty_id, payload_ty_id };
1702 member_names = .{1737 member_names = .{ "error", "payload" };
1703 try self.spv.resolveString("error"),
1704 try self.spv.resolveString("payload"),
1705 };
1706 // TODO: ABI padding?1738 // TODO: ABI padding?
1707 } else {1739 } else {
1708 // Put the payload first.1740 // Put the payload first.
1709 member_types = .{ payload_ty_ref, error_ty_ref };1741 member_types = .{ payload_ty_id, error_ty_id };
1710 member_names = .{1742 member_names = .{ "payload", "error" };
1711 try self.spv.resolveString("payload"),
1712 try self.spv.resolveString("error"),
1713 };
1714 // TODO: ABI padding?1743 // TODO: ABI padding?
1715 }1744 }
17161745
1717 const ty_ref = try self.spv.resolve(.{ .struct_type = .{1746 return try self.spv.structType(&member_types, &member_names);
1718 .name = try self.resolveTypeName(ty),
1719 .member_types = &member_types,
1720 .member_names = &member_names,
1721 } });
1722
1723 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
1724 return ty_ref;
1725 },1747 },
1726 .Opaque => {1748 .Opaque => {
1727 return try self.spv.resolve(.{1749 const type_name = try self.resolveTypeName(ty);
1728 .opaque_type = .{1750 defer self.gpa.free(type_name);
1729 .name = .none, // TODO1751
1730 },1752 const result_id = self.spv.allocId();
1753 try section.emit(self.spv.gpa, .OpTypeOpaque, .{
1754 .id_result = result_id,
1755 .literal_string = type_name,
1731 });1756 });
1757 return result_id;
1732 },1758 },
17331759
1734 .Null,1760 .Null,
...@@ -1736,9 +1762,10 @@ const DeclGen = struct {...@@ -1736,9 +1762,10 @@ const DeclGen = struct {
1736 .EnumLiteral,1762 .EnumLiteral,
1737 .ComptimeFloat,1763 .ComptimeFloat,
1738 .ComptimeInt,1764 .ComptimeInt,
1765 .Type,
1739 => unreachable, // Must be comptime.1766 => unreachable, // Must be comptime.
17401767
1741 else => |tag| return self.todo("Implement zig type '{}'", .{tag}),1768 .Frame, .AnyFrame => unreachable, // TODO
1742 }1769 }
1743 }1770 }
17441771
...@@ -1887,7 +1914,6 @@ const DeclGen = struct {...@@ -1887,7 +1914,6 @@ const DeclGen = struct {
1887 result_ty: Type,1914 result_ty: Type,
1888 ty: Type,1915 ty: Type,
1889 /// Always in direct representation.1916 /// Always in direct representation.
1890 ty_ref: CacheRef,
1891 ty_id: IdRef,1917 ty_id: IdRef,
1892 /// True if the input is an array type.1918 /// True if the input is an array type.
1893 is_array: bool,1919 is_array: bool,
...@@ -1947,14 +1973,13 @@ const DeclGen = struct {...@@ -1947,14 +1973,13 @@ const DeclGen = struct {
1947 @memset(results, undefined);1973 @memset(results, undefined);
19481974
1949 const ty = if (is_array) result_ty.scalarType(mod) else result_ty;1975 const ty = if (is_array) result_ty.scalarType(mod) else result_ty;
1950 const ty_ref = try self.resolveType(ty, .direct);1976 const ty_id = try self.resolveType(ty, .direct);
19511977
1952 return .{1978 return .{
1953 .dg = self,1979 .dg = self,
1954 .result_ty = result_ty,1980 .result_ty = result_ty,
1955 .ty = ty,1981 .ty = ty,
1956 .ty_ref = ty_ref,1982 .ty_id = ty_id,
1957 .ty_id = self.typeId(ty_ref),
1958 .is_array = is_array,1983 .is_array = is_array,
1959 .results = results,1984 .results = results,
1960 };1985 };
...@@ -1981,16 +2006,13 @@ const DeclGen = struct {...@@ -1981,16 +2006,13 @@ const DeclGen = struct {
1981 /// TODO is to also write out the error as a function call parameter, and to somehow fetch2006 /// TODO is to also write out the error as a function call parameter, and to somehow fetch
1982 /// the name of an error in the text executor.2007 /// the name of an error in the text executor.
1983 fn generateTestEntryPoint(self: *DeclGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void {2008 fn generateTestEntryPoint(self: *DeclGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void {
1984 const anyerror_ty_ref = try self.resolveType(Type.anyerror, .direct);2009 const anyerror_ty_id = try self.resolveType(Type.anyerror, .direct);
1985 const ptr_anyerror_ty_ref = try self.ptrType(Type.anyerror, .CrossWorkgroup);2010 const ptr_anyerror_ty = try self.module.ptrType(.{
1986 const void_ty_ref = try self.resolveType(Type.void, .direct);2011 .child = Type.anyerror.toIntern(),
19872012 .flags = .{ .address_space = .global },
1988 const kernel_proto_ty_ref = try self.spv.resolve(.{
1989 .function_type = .{
1990 .return_type = void_ty_ref,
1991 .parameters = &.{ptr_anyerror_ty_ref},
1992 },
1993 });2013 });
2014 const ptr_anyerror_ty_id = try self.resolveType(ptr_anyerror_ty, .direct);
2015 const kernel_proto_ty_id = try self.functionType(Type.void, &.{ptr_anyerror_ty});
19942016
1995 const test_id = self.spv.declPtr(spv_test_decl_index).result_id;2017 const test_id = self.spv.declPtr(spv_test_decl_index).result_id;
19962018
...@@ -2002,20 +2024,20 @@ const DeclGen = struct {...@@ -2002,20 +2024,20 @@ const DeclGen = struct {
20022024
2003 const section = &self.spv.sections.functions;2025 const section = &self.spv.sections.functions;
2004 try section.emit(self.spv.gpa, .OpFunction, .{2026 try section.emit(self.spv.gpa, .OpFunction, .{
2005 .id_result_type = self.typeId(void_ty_ref),2027 .id_result_type = try self.resolveType(Type.void, .direct),
2006 .id_result = kernel_id,2028 .id_result = kernel_id,
2007 .function_control = .{},2029 .function_control = .{},
2008 .function_type = self.typeId(kernel_proto_ty_ref),2030 .function_type = kernel_proto_ty_id,
2009 });2031 });
2010 try section.emit(self.spv.gpa, .OpFunctionParameter, .{2032 try section.emit(self.spv.gpa, .OpFunctionParameter, .{
2011 .id_result_type = self.typeId(ptr_anyerror_ty_ref),2033 .id_result_type = ptr_anyerror_ty_id,
2012 .id_result = p_error_id,2034 .id_result = p_error_id,
2013 });2035 });
2014 try section.emit(self.spv.gpa, .OpLabel, .{2036 try section.emit(self.spv.gpa, .OpLabel, .{
2015 .id_result = self.spv.allocId(),2037 .id_result = self.spv.allocId(),
2016 });2038 });
2017 try section.emit(self.spv.gpa, .OpFunctionCall, .{2039 try section.emit(self.spv.gpa, .OpFunctionCall, .{
2018 .id_result_type = self.typeId(anyerror_ty_ref),2040 .id_result_type = anyerror_ty_id,
2019 .id_result = error_id,2041 .id_result = error_id,
2020 .function = test_id,2042 .function = test_id,
2021 });2043 });
...@@ -2047,17 +2069,17 @@ const DeclGen = struct {...@@ -2047,17 +2069,17 @@ const DeclGen = struct {
2047 .func => {2069 .func => {
2048 assert(decl.typeOf(mod).zigTypeTag(mod) == .Fn);2070 assert(decl.typeOf(mod).zigTypeTag(mod) == .Fn);
2049 const fn_info = mod.typeToFunc(decl.typeOf(mod)).?;2071 const fn_info = mod.typeToFunc(decl.typeOf(mod)).?;
2050 const return_ty_ref = try self.resolveFnReturnType(Type.fromInterned(fn_info.return_type));2072 const return_ty_id = try self.resolveFnReturnType(Type.fromInterned(fn_info.return_type));
20512073
2052 const prototype_ty_ref = try self.resolveType(decl.typeOf(mod), .direct);2074 const prototype_ty_id = try self.resolveType(decl.typeOf(mod), .direct);
2053 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{2075 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
2054 .id_result_type = self.typeId(return_ty_ref),2076 .id_result_type = return_ty_id,
2055 .id_result = result_id,2077 .id_result = result_id,
2056 .function_control = switch (fn_info.cc) {2078 .function_control = switch (fn_info.cc) {
2057 .Inline => .{ .Inline = true },2079 .Inline => .{ .Inline = true },
2058 else => .{},2080 else => .{},
2059 },2081 },
2060 .function_type = self.typeId(prototype_ty_ref),2082 .function_type = prototype_ty_id,
2061 });2083 });
20622084
2063 comptime assert(zig_call_abi_ver == 3);2085 comptime assert(zig_call_abi_ver == 3);
...@@ -2066,7 +2088,7 @@ const DeclGen = struct {...@@ -2066,7 +2088,7 @@ const DeclGen = struct {
2066 const param_ty = Type.fromInterned(param_ty_index);2088 const param_ty = Type.fromInterned(param_ty_index);
2067 if (!param_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;2089 if (!param_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
20682090
2069 const param_type_id = try self.resolveTypeId(param_ty);2091 const param_type_id = try self.resolveType(param_ty, .direct);
2070 const arg_result_id = self.spv.allocId();2092 const arg_result_id = self.spv.allocId();
2071 try self.func.prologue.emit(self.spv.gpa, .OpFunctionParameter, .{2093 try self.func.prologue.emit(self.spv.gpa, .OpFunctionParameter, .{
2072 .id_result_type = param_type_id,2094 .id_result_type = param_type_id,
...@@ -2122,10 +2144,10 @@ const DeclGen = struct {...@@ -2122,10 +2144,10 @@ const DeclGen = struct {
2122 const final_storage_class = self.spvStorageClass(decl.@"addrspace");2144 const final_storage_class = self.spvStorageClass(decl.@"addrspace");
2123 assert(final_storage_class != .Generic); // These should be instance globals2145 assert(final_storage_class != .Generic); // These should be instance globals
21242146
2125 const ptr_ty_ref = try self.ptrType(decl.typeOf(mod), final_storage_class);2147 const ptr_ty_id = try self.ptrType(decl.typeOf(mod), final_storage_class);
21262148
2127 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpVariable, .{2149 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpVariable, .{
2128 .id_result_type = self.typeId(ptr_ty_ref),2150 .id_result_type = ptr_ty_id,
2129 .id_result = result_id,2151 .id_result = result_id,
2130 .storage_class = final_storage_class,2152 .storage_class = final_storage_class,
2131 });2153 });
...@@ -2145,22 +2167,18 @@ const DeclGen = struct {...@@ -2145,22 +2167,18 @@ const DeclGen = struct {
21452167
2146 try self.spv.declareDeclDeps(spv_decl_index, &.{});2168 try self.spv.declareDeclDeps(spv_decl_index, &.{});
21472169
2148 const ptr_ty_ref = try self.ptrType(decl.typeOf(mod), .Function);2170 const ptr_ty_id = try self.ptrType(decl.typeOf(mod), .Function);
21492171
2150 if (maybe_init_val) |init_val| {2172 if (maybe_init_val) |init_val| {
2151 // TODO: Combine with resolveAnonDecl?2173 // TODO: Combine with resolveAnonDecl?
2152 const void_ty_ref = try self.resolveType(Type.void, .direct);2174 const initializer_proto_ty_id = try self.functionType(Type.void, &.{});
2153 const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{
2154 .return_type = void_ty_ref,
2155 .parameters = &.{},
2156 } });
21572175
2158 const initializer_id = self.spv.allocId();2176 const initializer_id = self.spv.allocId();
2159 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{2177 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
2160 .id_result_type = self.typeId(void_ty_ref),2178 .id_result_type = try self.resolveType(Type.void, .direct),
2161 .id_result = initializer_id,2179 .id_result = initializer_id,
2162 .function_control = .{},2180 .function_control = .{},
2163 .function_type = self.typeId(initializer_proto_ty_ref),2181 .function_type = initializer_proto_ty_id,
2164 });2182 });
21652183
2166 const root_block_id = self.spv.allocId();2184 const root_block_id = self.spv.allocId();
...@@ -2183,7 +2201,7 @@ const DeclGen = struct {...@@ -2183,7 +2201,7 @@ const DeclGen = struct {
2183 try self.spv.debugNameFmt(initializer_id, "initializer of {s}", .{fqn});2201 try self.spv.debugNameFmt(initializer_id, "initializer of {s}", .{fqn});
21842202
2185 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{2203 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{
2186 .id_result_type = self.typeId(ptr_ty_ref),2204 .id_result_type = ptr_ty_id,
2187 .id_result = result_id,2205 .id_result = result_id,
2188 .set = try self.spv.importInstructionSet(.zig),2206 .set = try self.spv.importInstructionSet(.zig),
2189 .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere...2207 .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere...
...@@ -2191,7 +2209,7 @@ const DeclGen = struct {...@@ -2191,7 +2209,7 @@ const DeclGen = struct {
2191 });2209 });
2192 } else {2210 } else {
2193 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{2211 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{
2194 .id_result_type = self.typeId(ptr_ty_ref),2212 .id_result_type = ptr_ty_id,
2195 .id_result = result_id,2213 .id_result = result_id,
2196 .set = try self.spv.importInstructionSet(.zig),2214 .set = try self.spv.importInstructionSet(.zig),
2197 .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere...2215 .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere...
...@@ -2202,12 +2220,12 @@ const DeclGen = struct {...@@ -2202,12 +2220,12 @@ const DeclGen = struct {
2202 }2220 }
2203 }2221 }
22042222
2205 fn intFromBool(self: *DeclGen, result_ty_ref: CacheRef, condition_id: IdRef) !IdRef {2223 fn intFromBool(self: *DeclGen, ty: Type, condition_id: IdRef) !IdRef {
2206 const zero_id = try self.constInt(result_ty_ref, 0);2224 const zero_id = try self.constInt(ty, 0, .direct);
2207 const one_id = try self.constInt(result_ty_ref, 1);2225 const one_id = try self.constInt(ty, 1, .direct);
2208 const result_id = self.spv.allocId();2226 const result_id = self.spv.allocId();
2209 try self.func.body.emit(self.spv.gpa, .OpSelect, .{2227 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
2210 .id_result_type = self.typeId(result_ty_ref),2228 .id_result_type = try self.resolveType(ty, .direct),
2211 .id_result = result_id,2229 .id_result = result_id,
2212 .condition = condition_id,2230 .condition = condition_id,
2213 .object_1 = one_id,2231 .object_1 = one_id,
...@@ -2222,15 +2240,12 @@ const DeclGen = struct {...@@ -2222,15 +2240,12 @@ const DeclGen = struct {
2222 const mod = self.module;2240 const mod = self.module;
2223 return switch (ty.zigTypeTag(mod)) {2241 return switch (ty.zigTypeTag(mod)) {
2224 .Bool => blk: {2242 .Bool => blk: {
2225 const direct_bool_ty_ref = try self.resolveType(ty, .direct);
2226 const indirect_bool_ty_ref = try self.resolveType(ty, .indirect);
2227 const zero_id = try self.constInt(indirect_bool_ty_ref, 0);
2228 const result_id = self.spv.allocId();2243 const result_id = self.spv.allocId();
2229 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{2244 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
2230 .id_result_type = self.typeId(direct_bool_ty_ref),2245 .id_result_type = try self.resolveType(Type.bool, .direct),
2231 .id_result = result_id,2246 .id_result = result_id,
2232 .operand_1 = operand_id,2247 .operand_1 = operand_id,
2233 .operand_2 = zero_id,2248 .operand_2 = try self.constBool(false, .indirect),
2234 });2249 });
2235 break :blk result_id;2250 break :blk result_id;
2236 },2251 },
...@@ -2243,20 +2258,17 @@ const DeclGen = struct {...@@ -2243,20 +2258,17 @@ const DeclGen = struct {
2243 fn convertToIndirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef {2258 fn convertToIndirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef {
2244 const mod = self.module;2259 const mod = self.module;
2245 return switch (ty.zigTypeTag(mod)) {2260 return switch (ty.zigTypeTag(mod)) {
2246 .Bool => blk: {2261 .Bool => try self.intFromBool(Type.u1, operand_id),
2247 const indirect_bool_ty_ref = try self.resolveType(ty, .indirect);
2248 break :blk self.intFromBool(indirect_bool_ty_ref, operand_id);
2249 },
2250 else => operand_id,2262 else => operand_id,
2251 };2263 };
2252 }2264 }
22532265
2254 fn extractField(self: *DeclGen, result_ty: Type, object: IdRef, field: u32) !IdRef {2266 fn extractField(self: *DeclGen, result_ty: Type, object: IdRef, field: u32) !IdRef {
2255 const result_ty_ref = try self.resolveType(result_ty, .indirect);2267 const result_ty_id = try self.resolveType(result_ty, .indirect);
2256 const result_id = self.spv.allocId();2268 const result_id = self.spv.allocId();
2257 const indexes = [_]u32{field};2269 const indexes = [_]u32{field};
2258 try self.func.body.emit(self.spv.gpa, .OpCompositeExtract, .{2270 try self.func.body.emit(self.spv.gpa, .OpCompositeExtract, .{
2259 .id_result_type = self.typeId(result_ty_ref),2271 .id_result_type = result_ty_id,
2260 .id_result = result_id,2272 .id_result = result_id,
2261 .composite = object,2273 .composite = object,
2262 .indexes = &indexes,2274 .indexes = &indexes,
...@@ -2270,13 +2282,13 @@ const DeclGen = struct {...@@ -2270,13 +2282,13 @@ const DeclGen = struct {
2270 };2282 };
22712283
2272 fn load(self: *DeclGen, value_ty: Type, ptr_id: IdRef, options: MemoryOptions) !IdRef {2284 fn load(self: *DeclGen, value_ty: Type, ptr_id: IdRef, options: MemoryOptions) !IdRef {
2273 const indirect_value_ty_ref = try self.resolveType(value_ty, .indirect);2285 const indirect_value_ty_id = try self.resolveType(value_ty, .indirect);
2274 const result_id = self.spv.allocId();2286 const result_id = self.spv.allocId();
2275 const access = spec.MemoryAccess.Extended{2287 const access = spec.MemoryAccess.Extended{
2276 .Volatile = options.is_volatile,2288 .Volatile = options.is_volatile,
2277 };2289 };
2278 try self.func.body.emit(self.spv.gpa, .OpLoad, .{2290 try self.func.body.emit(self.spv.gpa, .OpLoad, .{
2279 .id_result_type = self.typeId(indirect_value_ty_ref),2291 .id_result_type = indirect_value_ty_id,
2280 .id_result = result_id,2292 .id_result = result_id,
2281 .pointer = ptr_id,2293 .pointer = ptr_id,
2282 .memory_access = access,2294 .memory_access = access,
...@@ -2488,7 +2500,8 @@ const DeclGen = struct {...@@ -2488,7 +2500,8 @@ const DeclGen = struct {
24882500
2489 const result_ty = self.typeOfIndex(inst);2501 const result_ty = self.typeOfIndex(inst);
2490 const shift_ty = self.typeOf(bin_op.rhs);2502 const shift_ty = self.typeOf(bin_op.rhs);
2491 const shift_ty_ref = try self.resolveType(shift_ty, .direct);2503 const scalar_result_ty_id = try self.resolveType(result_ty.scalarType(mod), .direct);
2504 const scalar_shift_ty_id = try self.resolveType(shift_ty.scalarType(mod), .direct);
24922505
2493 const info = self.arithmeticTypeInfo(result_ty);2506 const info = self.arithmeticTypeInfo(result_ty);
2494 switch (info.class) {2507 switch (info.class) {
...@@ -2505,7 +2518,7 @@ const DeclGen = struct {...@@ -2505,7 +2518,7 @@ const DeclGen = struct {
25052518
2506 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,2519 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,
2507 // so just manually upcast it if required.2520 // so just manually upcast it if required.
2508 const shift_id = if (shift_ty_ref != wip.ty_ref) blk: {2521 const shift_id = if (scalar_shift_ty_id != scalar_result_ty_id) blk: {
2509 const shift_id = self.spv.allocId();2522 const shift_id = self.spv.allocId();
2510 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{2523 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{
2511 .id_result_type = wip.ty_id,2524 .id_result_type = wip.ty_id,
...@@ -2529,7 +2542,7 @@ const DeclGen = struct {...@@ -2529,7 +2542,7 @@ const DeclGen = struct {
2529 try self.func.body.emit(self.spv.gpa, unsigned, args);2542 try self.func.body.emit(self.spv.gpa, unsigned, args);
2530 }2543 }
25312544
2532 result_id.* = try self.normalize(wip.ty_ref, value_id, info);2545 result_id.* = try self.normalize(wip.ty, value_id, info);
2533 }2546 }
2534 return try wip.finalize();2547 return try wip.finalize();
2535 }2548 }
...@@ -2622,7 +2635,7 @@ const DeclGen = struct {...@@ -2622,7 +2635,7 @@ const DeclGen = struct {
2622 /// - Signed integers are also sign extended if they are negative.2635 /// - Signed integers are also sign extended if they are negative.
2623 /// All other values are returned unmodified (this makes strange integer2636 /// All other values are returned unmodified (this makes strange integer
2624 /// wrapping easier to use in generic operations).2637 /// wrapping easier to use in generic operations).
2625 fn normalize(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, info: ArithmeticTypeInfo) !IdRef {2638 fn normalize(self: *DeclGen, ty: Type, value_id: IdRef, info: ArithmeticTypeInfo) !IdRef {
2626 switch (info.class) {2639 switch (info.class) {
2627 .integer, .bool, .float => return value_id,2640 .integer, .bool, .float => return value_id,
2628 .composite_integer => unreachable, // TODO2641 .composite_integer => unreachable, // TODO
...@@ -2630,9 +2643,9 @@ const DeclGen = struct {...@@ -2630,9 +2643,9 @@ const DeclGen = struct {
2630 .unsigned => {2643 .unsigned => {
2631 const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1;2644 const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1;
2632 const result_id = self.spv.allocId();2645 const result_id = self.spv.allocId();
2633 const mask_id = try self.constInt(ty_ref, mask_value);2646 const mask_id = try self.constInt(ty, mask_value, .direct);
2634 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{2647 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{
2635 .id_result_type = self.typeId(ty_ref),2648 .id_result_type = try self.resolveType(ty, .direct),
2636 .id_result = result_id,2649 .id_result = result_id,
2637 .operand_1 = value_id,2650 .operand_1 = value_id,
2638 .operand_2 = mask_id,2651 .operand_2 = mask_id,
...@@ -2641,17 +2654,17 @@ const DeclGen = struct {...@@ -2641,17 +2654,17 @@ const DeclGen = struct {
2641 },2654 },
2642 .signed => {2655 .signed => {
2643 // Shift left and right so that we can copy the sight bit that way.2656 // Shift left and right so that we can copy the sight bit that way.
2644 const shift_amt_id = try self.constInt(ty_ref, info.backing_bits - info.bits);2657 const shift_amt_id = try self.constInt(ty, info.backing_bits - info.bits, .direct);
2645 const left_id = self.spv.allocId();2658 const left_id = self.spv.allocId();
2646 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{2659 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{
2647 .id_result_type = self.typeId(ty_ref),2660 .id_result_type = try self.resolveType(ty, .direct),
2648 .id_result = left_id,2661 .id_result = left_id,
2649 .base = value_id,2662 .base = value_id,
2650 .shift = shift_amt_id,2663 .shift = shift_amt_id,
2651 });2664 });
2652 const right_id = self.spv.allocId();2665 const right_id = self.spv.allocId();
2653 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{2666 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{
2654 .id_result_type = self.typeId(ty_ref),2667 .id_result_type = try self.resolveType(ty, .direct),
2655 .id_result = right_id,2668 .id_result = right_id,
2656 .base = left_id,2669 .base = left_id,
2657 .shift = shift_amt_id,2670 .shift = shift_amt_id,
...@@ -2667,13 +2680,13 @@ const DeclGen = struct {...@@ -2667,13 +2680,13 @@ const DeclGen = struct {
2667 const lhs_id = try self.resolve(bin_op.lhs);2680 const lhs_id = try self.resolve(bin_op.lhs);
2668 const rhs_id = try self.resolve(bin_op.rhs);2681 const rhs_id = try self.resolve(bin_op.rhs);
2669 const ty = self.typeOfIndex(inst);2682 const ty = self.typeOfIndex(inst);
2670 const ty_ref = try self.resolveType(ty, .direct);2683 const ty_id = try self.resolveType(ty, .direct);
2671 const info = self.arithmeticTypeInfo(ty);2684 const info = self.arithmeticTypeInfo(ty);
2672 switch (info.class) {2685 switch (info.class) {
2673 .composite_integer => unreachable, // TODO2686 .composite_integer => unreachable, // TODO
2674 .integer, .strange_integer => {2687 .integer, .strange_integer => {
2675 const zero_id = try self.constInt(ty_ref, 0);2688 const zero_id = try self.constInt(ty, 0, .direct);
2676 const one_id = try self.constInt(ty_ref, 1);2689 const one_id = try self.constInt(ty, 1, .direct);
26772690
2678 // (a ^ b) > 02691 // (a ^ b) > 0
2679 const bin_bitwise_id = try self.binOpSimple(ty, lhs_id, rhs_id, .OpBitwiseXor);2692 const bin_bitwise_id = try self.binOpSimple(ty, lhs_id, rhs_id, .OpBitwiseXor);
...@@ -2696,14 +2709,14 @@ const DeclGen = struct {...@@ -2696,14 +2709,14 @@ const DeclGen = struct {
2696 const negative_div_id = try self.arithOp(ty, negative_div_lhs, rhs_abs, .OpFDiv, .OpSDiv, .OpUDiv);2709 const negative_div_id = try self.arithOp(ty, negative_div_lhs, rhs_abs, .OpFDiv, .OpSDiv, .OpUDiv);
2697 const negated_negative_div_id = self.spv.allocId();2710 const negated_negative_div_id = self.spv.allocId();
2698 try self.func.body.emit(self.spv.gpa, .OpSNegate, .{2711 try self.func.body.emit(self.spv.gpa, .OpSNegate, .{
2699 .id_result_type = self.typeId(ty_ref),2712 .id_result_type = ty_id,
2700 .id_result = negated_negative_div_id,2713 .id_result = negated_negative_div_id,
2701 .operand = negative_div_id,2714 .operand = negative_div_id,
2702 });2715 });
27032716
2704 const result_id = self.spv.allocId();2717 const result_id = self.spv.allocId();
2705 try self.func.body.emit(self.spv.gpa, .OpSelect, .{2718 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
2706 .id_result_type = self.typeId(ty_ref),2719 .id_result_type = ty_id,
2707 .id_result = result_id,2720 .id_result = result_id,
2708 .condition = is_positive_id,2721 .condition = is_positive_id,
2709 .object_1 = positive_div_id,2722 .object_1 = positive_div_id,
...@@ -2728,7 +2741,7 @@ const DeclGen = struct {...@@ -2728,7 +2741,7 @@ const DeclGen = struct {
27282741
2729 fn floor(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef {2742 fn floor(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef {
2730 const target = self.getTarget();2743 const target = self.getTarget();
2731 const ty_ref = try self.resolveType(ty, .direct);2744 const ty_id = try self.resolveType(ty, .direct);
2732 const ext_inst: Word = switch (target.os.tag) {2745 const ext_inst: Word = switch (target.os.tag) {
2733 .opencl => 25,2746 .opencl => 25,
2734 .vulkan => 8,2747 .vulkan => 8,
...@@ -2742,7 +2755,7 @@ const DeclGen = struct {...@@ -2742,7 +2755,7 @@ const DeclGen = struct {
27422755
2743 const result_id = self.spv.allocId();2756 const result_id = self.spv.allocId();
2744 try self.func.body.emit(self.spv.gpa, .OpExtInst, .{2757 try self.func.body.emit(self.spv.gpa, .OpExtInst, .{
2745 .id_result_type = self.typeId(ty_ref),2758 .id_result_type = ty_id,
2746 .id_result = result_id,2759 .id_result = result_id,
2747 .set = set_id,2760 .set = set_id,
2748 .instruction = .{ .inst = ext_inst },2761 .instruction = .{ .inst = ext_inst },
...@@ -2819,7 +2832,7 @@ const DeclGen = struct {...@@ -2819,7 +2832,7 @@ const DeclGen = struct {
28192832
2820 // TODO: Trap on overflow? Probably going to be annoying.2833 // TODO: Trap on overflow? Probably going to be annoying.
2821 // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap.2834 // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap.
2822 result_id.* = try self.normalize(wip.ty_ref, value_id, info);2835 result_id.* = try self.normalize(wip.ty, value_id, info);
2823 }2836 }
28242837
2825 return try wip.finalize();2838 return try wip.finalize();
...@@ -2897,11 +2910,12 @@ const DeclGen = struct {...@@ -2897,11 +2910,12 @@ const DeclGen = struct {
2897 const operand_ty = self.typeOf(extra.lhs);2910 const operand_ty = self.typeOf(extra.lhs);
2898 const ov_ty = result_ty.structFieldType(1, self.module);2911 const ov_ty = result_ty.structFieldType(1, self.module);
28992912
2900 const bool_ty_ref = try self.resolveType(Type.bool, .direct);2913 const bool_ty_id = try self.resolveType(Type.bool, .direct);
2901 const cmp_ty_ref = if (self.isVector(operand_ty))2914 const cmp_ty_id = if (self.isVector(operand_ty))
2902 try self.spv.vectorType(operand_ty.vectorLen(mod), bool_ty_ref)2915 // TODO: Resolving a vector type with .direct should return a SPIR-V vector
2916 try self.spv.vectorType(operand_ty.vectorLen(mod), try self.resolveType(Type.bool, .direct))
2903 else2917 else
2904 bool_ty_ref;2918 bool_ty_id;
29052919
2906 const info = self.arithmeticTypeInfo(operand_ty);2920 const info = self.arithmeticTypeInfo(operand_ty);
2907 switch (info.class) {2921 switch (info.class) {
...@@ -2929,7 +2943,7 @@ const DeclGen = struct {...@@ -2929,7 +2943,7 @@ const DeclGen = struct {
2929 });2943 });
29302944
2931 // Normalize the result so that the comparisons go well2945 // Normalize the result so that the comparisons go well
2932 result_id.* = try self.normalize(wip_result.ty_ref, value_id, info);2946 result_id.* = try self.normalize(wip_result.ty, value_id, info);
29332947
2934 const overflowed_id = switch (info.signedness) {2948 const overflowed_id = switch (info.signedness) {
2935 .unsigned => blk: {2949 .unsigned => blk: {
...@@ -2937,7 +2951,7 @@ const DeclGen = struct {...@@ -2937,7 +2951,7 @@ const DeclGen = struct {
2937 // For subtraction the conditions need to be swapped.2951 // For subtraction the conditions need to be swapped.
2938 const overflowed_id = self.spv.allocId();2952 const overflowed_id = self.spv.allocId();
2939 try self.func.body.emit(self.spv.gpa, ucmp, .{2953 try self.func.body.emit(self.spv.gpa, ucmp, .{
2940 .id_result_type = self.typeId(cmp_ty_ref),2954 .id_result_type = cmp_ty_id,
2941 .id_result = overflowed_id,2955 .id_result = overflowed_id,
2942 .operand_1 = result_id.*,2956 .operand_1 = result_id.*,
2943 .operand_2 = lhs_elem_id,2957 .operand_2 = lhs_elem_id,
...@@ -2963,9 +2977,9 @@ const DeclGen = struct {...@@ -2963,9 +2977,9 @@ const DeclGen = struct {
2963 // = (rhs < 0) == (lhs > value)2977 // = (rhs < 0) == (lhs > value)
29642978
2965 const rhs_lt_zero_id = self.spv.allocId();2979 const rhs_lt_zero_id = self.spv.allocId();
2966 const zero_id = try self.constInt(wip_result.ty_ref, 0);2980 const zero_id = try self.constInt(wip_result.ty, 0, .direct);
2967 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{2981 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{
2968 .id_result_type = self.typeId(cmp_ty_ref),2982 .id_result_type = cmp_ty_id,
2969 .id_result = rhs_lt_zero_id,2983 .id_result = rhs_lt_zero_id,
2970 .operand_1 = rhs_elem_id,2984 .operand_1 = rhs_elem_id,
2971 .operand_2 = zero_id,2985 .operand_2 = zero_id,
...@@ -2973,7 +2987,7 @@ const DeclGen = struct {...@@ -2973,7 +2987,7 @@ const DeclGen = struct {
29732987
2974 const value_gt_lhs_id = self.spv.allocId();2988 const value_gt_lhs_id = self.spv.allocId();
2975 try self.func.body.emit(self.spv.gpa, scmp, .{2989 try self.func.body.emit(self.spv.gpa, scmp, .{
2976 .id_result_type = self.typeId(cmp_ty_ref),2990 .id_result_type = cmp_ty_id,
2977 .id_result = value_gt_lhs_id,2991 .id_result = value_gt_lhs_id,
2978 .operand_1 = lhs_elem_id,2992 .operand_1 = lhs_elem_id,
2979 .operand_2 = result_id.*,2993 .operand_2 = result_id.*,
...@@ -2981,7 +2995,7 @@ const DeclGen = struct {...@@ -2981,7 +2995,7 @@ const DeclGen = struct {
29812995
2982 const overflowed_id = self.spv.allocId();2996 const overflowed_id = self.spv.allocId();
2983 try self.func.body.emit(self.spv.gpa, .OpLogicalEqual, .{2997 try self.func.body.emit(self.spv.gpa, .OpLogicalEqual, .{
2984 .id_result_type = self.typeId(cmp_ty_ref),2998 .id_result_type = cmp_ty_id,
2985 .id_result = overflowed_id,2999 .id_result = overflowed_id,
2986 .operand_1 = rhs_lt_zero_id,3000 .operand_1 = rhs_lt_zero_id,
2987 .operand_2 = value_gt_lhs_id,3001 .operand_2 = value_gt_lhs_id,
...@@ -2990,7 +3004,7 @@ const DeclGen = struct {...@@ -2990,7 +3004,7 @@ const DeclGen = struct {
2990 },3004 },
2991 };3005 };
29923006
2993 ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id);3007 ov_id.* = try self.intFromBool(wip_ov.ty, overflowed_id);
2994 }3008 }
29953009
2996 return try self.constructStruct(3010 return try self.constructStruct(
...@@ -3022,9 +3036,9 @@ const DeclGen = struct {...@@ -3022,9 +3036,9 @@ const DeclGen = struct {
3022 var wip_ov = try self.elementWise(ov_ty, true);3036 var wip_ov = try self.elementWise(ov_ty, true);
3023 defer wip_ov.deinit();3037 defer wip_ov.deinit();
30243038
3025 const zero_id = try self.constInt(wip_result.ty_ref, 0);3039 const zero_id = try self.constInt(wip_result.ty, 0, .direct);
3026 const zero_ov_id = try self.constInt(wip_ov.ty_ref, 0);3040 const zero_ov_id = try self.constInt(wip_ov.ty, 0, .direct);
3027 const one_ov_id = try self.constInt(wip_ov.ty_ref, 1);3041 const one_ov_id = try self.constInt(wip_ov.ty, 1, .direct);
30283042
3029 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {3043 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {
3030 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);3044 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);
...@@ -3065,15 +3079,17 @@ const DeclGen = struct {...@@ -3065,15 +3079,17 @@ const DeclGen = struct {
3065 const result_ty = self.typeOfIndex(inst);3079 const result_ty = self.typeOfIndex(inst);
3066 const operand_ty = self.typeOf(extra.lhs);3080 const operand_ty = self.typeOf(extra.lhs);
3067 const shift_ty = self.typeOf(extra.rhs);3081 const shift_ty = self.typeOf(extra.rhs);
3068 const shift_ty_ref = try self.resolveType(shift_ty, .direct);3082 const scalar_shift_ty_id = try self.resolveType(shift_ty.scalarType(mod), .direct);
3083 const scalar_operand_ty_id = try self.resolveType(operand_ty.scalarType(mod), .direct);
30693084
3070 const ov_ty = result_ty.structFieldType(1, self.module);3085 const ov_ty = result_ty.structFieldType(1, self.module);
30713086
3072 const bool_ty_ref = try self.resolveType(Type.bool, .direct);3087 const bool_ty_id = try self.resolveType(Type.bool, .direct);
3073 const cmp_ty_ref = if (self.isVector(operand_ty))3088 const cmp_ty_id = if (self.isVector(operand_ty))
3074 try self.spv.vectorType(operand_ty.vectorLen(mod), bool_ty_ref)3089 // TODO: Resolving a vector type with .direct should return a SPIR-V vector
3090 try self.spv.vectorType(operand_ty.vectorLen(mod), try self.resolveType(Type.bool, .direct))
3075 else3091 else
3076 bool_ty_ref;3092 bool_ty_id;
30773093
3078 const info = self.arithmeticTypeInfo(operand_ty);3094 const info = self.arithmeticTypeInfo(operand_ty);
3079 switch (info.class) {3095 switch (info.class) {
...@@ -3092,7 +3108,7 @@ const DeclGen = struct {...@@ -3092,7 +3108,7 @@ const DeclGen = struct {
30923108
3093 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,3109 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,
3094 // so just manually upcast it if required.3110 // so just manually upcast it if required.
3095 const shift_id = if (shift_ty_ref != wip_result.ty_ref) blk: {3111 const shift_id = if (scalar_shift_ty_id != scalar_operand_ty_id) blk: {
3096 const shift_id = self.spv.allocId();3112 const shift_id = self.spv.allocId();
3097 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{3113 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{
3098 .id_result_type = wip_result.ty_id,3114 .id_result_type = wip_result.ty_id,
...@@ -3109,7 +3125,7 @@ const DeclGen = struct {...@@ -3109,7 +3125,7 @@ const DeclGen = struct {
3109 .base = lhs_elem_id,3125 .base = lhs_elem_id,
3110 .shift = shift_id,3126 .shift = shift_id,
3111 });3127 });
3112 result_id.* = try self.normalize(wip_result.ty_ref, value_id, info);3128 result_id.* = try self.normalize(wip_result.ty, value_id, info);
31133129
3114 const right_shift_id = self.spv.allocId();3130 const right_shift_id = self.spv.allocId();
3115 switch (info.signedness) {3131 switch (info.signedness) {
...@@ -3133,13 +3149,13 @@ const DeclGen = struct {...@@ -3133,13 +3149,13 @@ const DeclGen = struct {
31333149
3134 const overflowed_id = self.spv.allocId();3150 const overflowed_id = self.spv.allocId();
3135 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{3151 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
3136 .id_result_type = self.typeId(cmp_ty_ref),3152 .id_result_type = cmp_ty_id,
3137 .id_result = overflowed_id,3153 .id_result = overflowed_id,
3138 .operand_1 = lhs_elem_id,3154 .operand_1 = lhs_elem_id,
3139 .operand_2 = right_shift_id,3155 .operand_2 = right_shift_id,
3140 });3156 });
31413157
3142 ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id);3158 ov_id.* = try self.intFromBool(wip_ov.ty, overflowed_id);
3143 }3159 }
31443160
3145 return try self.constructStruct(3161 return try self.constructStruct(
...@@ -3204,8 +3220,7 @@ const DeclGen = struct {...@@ -3204,8 +3220,7 @@ const DeclGen = struct {
3204 defer wip.deinit();3220 defer wip.deinit();
32053221
3206 const elem_ty = if (wip.is_array) operand_ty.scalarType(mod) else operand_ty;3222 const elem_ty = if (wip.is_array) operand_ty.scalarType(mod) else operand_ty;
3207 const elem_ty_ref = try self.resolveType(elem_ty, .direct);3223 const elem_ty_id = try self.resolveType(elem_ty, .direct);
3208 const elem_ty_id = self.typeId(elem_ty_ref);
32093224
3210 for (wip.results, 0..) |*result_id, i| {3225 for (wip.results, 0..) |*result_id, i| {
3211 const elem = try wip.elementAt(operand_ty, operand, i);3226 const elem = try wip.elementAt(operand_ty, operand, i);
...@@ -3230,6 +3245,8 @@ const DeclGen = struct {...@@ -3230,6 +3245,8 @@ const DeclGen = struct {
3230 .id_ref_4 = &.{elem},3245 .id_ref_4 = &.{elem},
3231 });3246 });
32323247
3248 // TODO: Comparison should be removed..
3249 // Its valid because SpvModule caches numeric types
3233 if (wip.ty_id == elem_ty_id) {3250 if (wip.ty_id == elem_ty_id) {
3234 result_id.* = tmp;3251 result_id.* = tmp;
3235 continue;3252 continue;
...@@ -3276,8 +3293,7 @@ const DeclGen = struct {...@@ -3276,8 +3293,7 @@ const DeclGen = struct {
3276 const operand = try self.resolve(reduce.operand);3293 const operand = try self.resolve(reduce.operand);
3277 const operand_ty = self.typeOf(reduce.operand);3294 const operand_ty = self.typeOf(reduce.operand);
3278 const scalar_ty = operand_ty.scalarType(mod);3295 const scalar_ty = operand_ty.scalarType(mod);
3279 const scalar_ty_ref = try self.resolveType(scalar_ty, .direct);3296 const scalar_ty_id = try self.resolveType(scalar_ty, .direct);
3280 const scalar_ty_id = self.typeId(scalar_ty_ref);
32813297
3282 const info = self.arithmeticTypeInfo(operand_ty);3298 const info = self.arithmeticTypeInfo(operand_ty);
32833299
...@@ -3351,7 +3367,7 @@ const DeclGen = struct {...@@ -3351,7 +3367,7 @@ const DeclGen = struct {
3351 for (wip.results, 0..) |*result_id, i| {3367 for (wip.results, 0..) |*result_id, i| {
3352 const elem = try mask.elemValue(mod, i);3368 const elem = try mask.elemValue(mod, i);
3353 if (elem.isUndef(mod)) {3369 if (elem.isUndef(mod)) {
3354 result_id.* = try self.spv.constUndef(wip.ty_ref);3370 result_id.* = try self.spv.constUndef(wip.ty_id);
3355 continue;3371 continue;
3356 }3372 }
33573373
...@@ -3366,11 +3382,10 @@ const DeclGen = struct {...@@ -3366,11 +3382,10 @@ const DeclGen = struct {
3366 }3382 }
33673383
3368 fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef {3384 fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef {
3369 const index_ty_ref = try self.intType(.unsigned, 32);
3370 const ids = try self.gpa.alloc(IdRef, indices.len);3385 const ids = try self.gpa.alloc(IdRef, indices.len);
3371 errdefer self.gpa.free(ids);3386 errdefer self.gpa.free(ids);
3372 for (indices, ids) |index, *id| {3387 for (indices, ids) |index, *id| {
3373 id.* = try self.constInt(index_ty_ref, index);3388 id.* = try self.constInt(Type.u32, index, .direct);
3374 }3389 }
33753390
3376 return ids;3391 return ids;
...@@ -3378,13 +3393,13 @@ const DeclGen = struct {...@@ -3378,13 +3393,13 @@ const DeclGen = struct {
33783393
3379 fn accessChainId(3394 fn accessChainId(
3380 self: *DeclGen,3395 self: *DeclGen,
3381 result_ty_ref: CacheRef,3396 result_ty_id: IdRef,
3382 base: IdRef,3397 base: IdRef,
3383 indices: []const IdRef,3398 indices: []const IdRef,
3384 ) !IdRef {3399 ) !IdRef {
3385 const result_id = self.spv.allocId();3400 const result_id = self.spv.allocId();
3386 try self.func.body.emit(self.spv.gpa, .OpInBoundsAccessChain, .{3401 try self.func.body.emit(self.spv.gpa, .OpInBoundsAccessChain, .{
3387 .id_result_type = self.typeId(result_ty_ref),3402 .id_result_type = result_ty_id,
3388 .id_result = result_id,3403 .id_result = result_id,
3389 .base = base,3404 .base = base,
3390 .indexes = indices,3405 .indexes = indices,
...@@ -3398,18 +3413,18 @@ const DeclGen = struct {...@@ -3398,18 +3413,18 @@ const DeclGen = struct {
3398 /// is the latter and PtrAccessChain is the former.3413 /// is the latter and PtrAccessChain is the former.
3399 fn accessChain(3414 fn accessChain(
3400 self: *DeclGen,3415 self: *DeclGen,
3401 result_ty_ref: CacheRef,3416 result_ty_id: IdRef,
3402 base: IdRef,3417 base: IdRef,
3403 indices: []const u32,3418 indices: []const u32,
3404 ) !IdRef {3419 ) !IdRef {
3405 const ids = try self.indicesToIds(indices);3420 const ids = try self.indicesToIds(indices);
3406 defer self.gpa.free(ids);3421 defer self.gpa.free(ids);
3407 return try self.accessChainId(result_ty_ref, base, ids);3422 return try self.accessChainId(result_ty_id, base, ids);
3408 }3423 }
34093424
3410 fn ptrAccessChain(3425 fn ptrAccessChain(
3411 self: *DeclGen,3426 self: *DeclGen,
3412 result_ty_ref: CacheRef,3427 result_ty_id: IdRef,
3413 base: IdRef,3428 base: IdRef,
3414 element: IdRef,3429 element: IdRef,
3415 indices: []const u32,3430 indices: []const u32,
...@@ -3419,7 +3434,7 @@ const DeclGen = struct {...@@ -3419,7 +3434,7 @@ const DeclGen = struct {
34193434
3420 const result_id = self.spv.allocId();3435 const result_id = self.spv.allocId();
3421 try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{3436 try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{
3422 .id_result_type = self.typeId(result_ty_ref),3437 .id_result_type = result_ty_id,
3423 .id_result = result_id,3438 .id_result = result_id,
3424 .base = base,3439 .base = base,
3425 .element = element,3440 .element = element,
...@@ -3430,21 +3445,21 @@ const DeclGen = struct {...@@ -3430,21 +3445,21 @@ const DeclGen = struct {
34303445
3431 fn ptrAdd(self: *DeclGen, result_ty: Type, ptr_ty: Type, ptr_id: IdRef, offset_id: IdRef) !IdRef {3446 fn ptrAdd(self: *DeclGen, result_ty: Type, ptr_ty: Type, ptr_id: IdRef, offset_id: IdRef) !IdRef {
3432 const mod = self.module;3447 const mod = self.module;
3433 const result_ty_ref = try self.resolveType(result_ty, .direct);3448 const result_ty_id = try self.resolveType(result_ty, .direct);
34343449
3435 switch (ptr_ty.ptrSize(mod)) {3450 switch (ptr_ty.ptrSize(mod)) {
3436 .One => {3451 .One => {
3437 // Pointer to array3452 // Pointer to array
3438 // TODO: Is this correct?3453 // TODO: Is this correct?
3439 return try self.accessChainId(result_ty_ref, ptr_id, &.{offset_id});3454 return try self.accessChainId(result_ty_id, ptr_id, &.{offset_id});
3440 },3455 },
3441 .C, .Many => {3456 .C, .Many => {
3442 return try self.ptrAccessChain(result_ty_ref, ptr_id, offset_id, &.{});3457 return try self.ptrAccessChain(result_ty_id, ptr_id, offset_id, &.{});
3443 },3458 },
3444 .Slice => {3459 .Slice => {
3445 // TODO: This is probably incorrect. A slice should be returned here, though this is what llvm does.3460 // TODO: This is probably incorrect. A slice should be returned here, though this is what llvm does.
3446 const slice_ptr_id = try self.extractField(result_ty, ptr_id, 0);3461 const slice_ptr_id = try self.extractField(result_ty, ptr_id, 0);
3447 return try self.ptrAccessChain(result_ty_ref, slice_ptr_id, offset_id, &.{});3462 return try self.ptrAccessChain(result_ty_id, slice_ptr_id, offset_id, &.{});
3448 },3463 },
3449 }3464 }
3450 }3465 }
...@@ -3467,12 +3482,12 @@ const DeclGen = struct {...@@ -3467,12 +3482,12 @@ const DeclGen = struct {
3467 const ptr_ty = self.typeOf(bin_op.lhs);3482 const ptr_ty = self.typeOf(bin_op.lhs);
3468 const offset_id = try self.resolve(bin_op.rhs);3483 const offset_id = try self.resolve(bin_op.rhs);
3469 const offset_ty = self.typeOf(bin_op.rhs);3484 const offset_ty = self.typeOf(bin_op.rhs);
3470 const offset_ty_ref = try self.resolveType(offset_ty, .direct);3485 const offset_ty_id = try self.resolveType(offset_ty, .direct);
3471 const result_ty = self.typeOfIndex(inst);3486 const result_ty = self.typeOfIndex(inst);
34723487
3473 const negative_offset_id = self.spv.allocId();3488 const negative_offset_id = self.spv.allocId();
3474 try self.func.body.emit(self.spv.gpa, .OpSNegate, .{3489 try self.func.body.emit(self.spv.gpa, .OpSNegate, .{
3475 .id_result_type = self.typeId(offset_ty_ref),3490 .id_result_type = offset_ty_id,
3476 .id_result = negative_offset_id,3491 .id_result = negative_offset_id,
3477 .operand = offset_id,3492 .operand = offset_id,
3478 });3493 });
...@@ -3490,7 +3505,7 @@ const DeclGen = struct {...@@ -3490,7 +3505,7 @@ const DeclGen = struct {
3490 const mod = self.module;3505 const mod = self.module;
3491 var cmp_lhs_id = lhs_id;3506 var cmp_lhs_id = lhs_id;
3492 var cmp_rhs_id = rhs_id;3507 var cmp_rhs_id = rhs_id;
3493 const bool_ty_ref = try self.resolveType(Type.bool, .direct);3508 const bool_ty_id = try self.resolveType(Type.bool, .direct);
3494 const op_ty = switch (ty.zigTypeTag(mod)) {3509 const op_ty = switch (ty.zigTypeTag(mod)) {
3495 .Int, .Bool, .Float => ty,3510 .Int, .Bool, .Float => ty,
3496 .Enum => ty.intTagType(mod),3511 .Enum => ty.intTagType(mod),
...@@ -3502,7 +3517,7 @@ const DeclGen = struct {...@@ -3502,7 +3517,7 @@ const DeclGen = struct {
3502 cmp_lhs_id = self.spv.allocId();3517 cmp_lhs_id = self.spv.allocId();
3503 cmp_rhs_id = self.spv.allocId();3518 cmp_rhs_id = self.spv.allocId();
35043519
3505 const usize_ty_id = self.typeId(try self.sizeType());3520 const usize_ty_id = try self.resolveType(Type.usize, .direct);
35063521
3507 try self.func.body.emit(self.spv.gpa, .OpConvertPtrToU, .{3522 try self.func.body.emit(self.spv.gpa, .OpConvertPtrToU, .{
3508 .id_result_type = usize_ty_id,3523 .id_result_type = usize_ty_id,
...@@ -3564,20 +3579,20 @@ const DeclGen = struct {...@@ -3564,20 +3579,20 @@ const DeclGen = struct {
3564 const pl_eq_id = try self.cmp(op, Type.bool, payload_ty, lhs_pl_id, rhs_pl_id);3579 const pl_eq_id = try self.cmp(op, Type.bool, payload_ty, lhs_pl_id, rhs_pl_id);
3565 const lhs_not_valid_id = self.spv.allocId();3580 const lhs_not_valid_id = self.spv.allocId();
3566 try self.func.body.emit(self.spv.gpa, .OpLogicalNot, .{3581 try self.func.body.emit(self.spv.gpa, .OpLogicalNot, .{
3567 .id_result_type = self.typeId(bool_ty_ref),3582 .id_result_type = bool_ty_id,
3568 .id_result = lhs_not_valid_id,3583 .id_result = lhs_not_valid_id,
3569 .operand = lhs_valid_id,3584 .operand = lhs_valid_id,
3570 });3585 });
3571 const impl_id = self.spv.allocId();3586 const impl_id = self.spv.allocId();
3572 try self.func.body.emit(self.spv.gpa, .OpLogicalOr, .{3587 try self.func.body.emit(self.spv.gpa, .OpLogicalOr, .{
3573 .id_result_type = self.typeId(bool_ty_ref),3588 .id_result_type = bool_ty_id,
3574 .id_result = impl_id,3589 .id_result = impl_id,
3575 .operand_1 = lhs_not_valid_id,3590 .operand_1 = lhs_not_valid_id,
3576 .operand_2 = pl_eq_id,3591 .operand_2 = pl_eq_id,
3577 });3592 });
3578 const result_id = self.spv.allocId();3593 const result_id = self.spv.allocId();
3579 try self.func.body.emit(self.spv.gpa, .OpLogicalAnd, .{3594 try self.func.body.emit(self.spv.gpa, .OpLogicalAnd, .{
3580 .id_result_type = self.typeId(bool_ty_ref),3595 .id_result_type = bool_ty_id,
3581 .id_result = result_id,3596 .id_result = result_id,
3582 .operand_1 = valid_eq_id,3597 .operand_1 = valid_eq_id,
3583 .operand_2 = impl_id,3598 .operand_2 = impl_id,
...@@ -3590,14 +3605,14 @@ const DeclGen = struct {...@@ -3590,14 +3605,14 @@ const DeclGen = struct {
35903605
3591 const impl_id = self.spv.allocId();3606 const impl_id = self.spv.allocId();
3592 try self.func.body.emit(self.spv.gpa, .OpLogicalAnd, .{3607 try self.func.body.emit(self.spv.gpa, .OpLogicalAnd, .{
3593 .id_result_type = self.typeId(bool_ty_ref),3608 .id_result_type = bool_ty_id,
3594 .id_result = impl_id,3609 .id_result = impl_id,
3595 .operand_1 = lhs_valid_id,3610 .operand_1 = lhs_valid_id,
3596 .operand_2 = pl_neq_id,3611 .operand_2 = pl_neq_id,
3597 });3612 });
3598 const result_id = self.spv.allocId();3613 const result_id = self.spv.allocId();
3599 try self.func.body.emit(self.spv.gpa, .OpLogicalOr, .{3614 try self.func.body.emit(self.spv.gpa, .OpLogicalOr, .{
3600 .id_result_type = self.typeId(bool_ty_ref),3615 .id_result_type = bool_ty_id,
3601 .id_result = result_id,3616 .id_result = result_id,
3602 .operand_1 = valid_neq_id,3617 .operand_1 = valid_neq_id,
3603 .operand_2 = impl_id,3618 .operand_2 = impl_id,
...@@ -3665,7 +3680,7 @@ const DeclGen = struct {...@@ -3665,7 +3680,7 @@ const DeclGen = struct {
36653680
3666 const result_id = self.spv.allocId();3681 const result_id = self.spv.allocId();
3667 try self.func.body.emitRaw(self.spv.gpa, opcode, 4);3682 try self.func.body.emitRaw(self.spv.gpa, opcode, 4);
3668 self.func.body.writeOperand(spec.IdResultType, self.typeId(bool_ty_ref));3683 self.func.body.writeOperand(spec.IdResultType, bool_ty_id);
3669 self.func.body.writeOperand(spec.IdResult, result_id);3684 self.func.body.writeOperand(spec.IdResult, result_id);
3670 self.func.body.writeOperand(spec.IdResultType, cmp_lhs_id);3685 self.func.body.writeOperand(spec.IdResultType, cmp_lhs_id);
3671 self.func.body.writeOperand(spec.IdResultType, cmp_rhs_id);3686 self.func.body.writeOperand(spec.IdResultType, cmp_rhs_id);
...@@ -3698,6 +3713,7 @@ const DeclGen = struct {...@@ -3698,6 +3713,7 @@ const DeclGen = struct {
3698 return try self.cmp(op, result_ty, ty, lhs_id, rhs_id);3713 return try self.cmp(op, result_ty, ty, lhs_id, rhs_id);
3699 }3714 }
37003715
3716 /// Bitcast one type to another. Note: both types, input, output are expected in **direct** representation.
3701 fn bitCast(3717 fn bitCast(
3702 self: *DeclGen,3718 self: *DeclGen,
3703 dst_ty: Type,3719 dst_ty: Type,
...@@ -3705,13 +3721,11 @@ const DeclGen = struct {...@@ -3705,13 +3721,11 @@ const DeclGen = struct {
3705 src_id: IdRef,3721 src_id: IdRef,
3706 ) !IdRef {3722 ) !IdRef {
3707 const mod = self.module;3723 const mod = self.module;
3708 const src_ty_ref = try self.resolveType(src_ty, .direct);3724 const src_ty_id = try self.resolveType(src_ty, .direct);
3709 const dst_ty_ref = try self.resolveType(dst_ty, .direct);3725 const dst_ty_id = try self.resolveType(dst_ty, .direct);
3710 const src_key = self.spv.cache.lookup(src_ty_ref);
3711 const dst_key = self.spv.cache.lookup(dst_ty_ref);
37123726
3713 const result_id = blk: {3727 const result_id = blk: {
3714 if (src_ty_ref == dst_ty_ref) {3728 if (src_ty_id == dst_ty_id) {
3715 break :blk src_id;3729 break :blk src_id;
3716 }3730 }
37173731
...@@ -3721,7 +3735,7 @@ const DeclGen = struct {...@@ -3721,7 +3735,7 @@ const DeclGen = struct {
3721 if (src_ty.zigTypeTag(mod) == .Int and dst_ty.isPtrAtRuntime(mod)) {3735 if (src_ty.zigTypeTag(mod) == .Int and dst_ty.isPtrAtRuntime(mod)) {
3722 const result_id = self.spv.allocId();3736 const result_id = self.spv.allocId();
3723 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{3737 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
3724 .id_result_type = self.typeId(dst_ty_ref),3738 .id_result_type = dst_ty_id,
3725 .id_result = result_id,3739 .id_result = result_id,
3726 .integer_value = src_id,3740 .integer_value = src_id,
3727 });3741 });
...@@ -3731,10 +3745,11 @@ const DeclGen = struct {...@@ -3731,10 +3745,11 @@ const DeclGen = struct {
3731 // We can only use OpBitcast for specific conversions: between numerical types, and3745 // We can only use OpBitcast for specific conversions: between numerical types, and
3732 // between pointers. If the resolved spir-v types fall into this category then emit OpBitcast,3746 // between pointers. If the resolved spir-v types fall into this category then emit OpBitcast,
3733 // otherwise use a temporary and perform a pointer cast.3747 // otherwise use a temporary and perform a pointer cast.
3734 if ((src_key.isNumericalType() and dst_key.isNumericalType()) or (src_key == .ptr_type and dst_key == .ptr_type)) {3748 const can_bitcast = (src_ty.isNumeric(mod) and dst_ty.isNumeric(mod)) or (src_ty.isPtrAtRuntime(mod) and dst_ty.isPtrAtRuntime(mod));
3749 if (can_bitcast) {
3735 const result_id = self.spv.allocId();3750 const result_id = self.spv.allocId();
3736 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{3751 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
3737 .id_result_type = self.typeId(dst_ty_ref),3752 .id_result_type = dst_ty_id,
3738 .id_result = result_id,3753 .id_result = result_id,
3739 .operand = src_id,3754 .operand = src_id,
3740 });3755 });
...@@ -3742,13 +3757,13 @@ const DeclGen = struct {...@@ -3742,13 +3757,13 @@ const DeclGen = struct {
3742 break :blk result_id;3757 break :blk result_id;
3743 }3758 }
37443759
3745 const dst_ptr_ty_ref = try self.ptrType(dst_ty, .Function);3760 const dst_ptr_ty_id = try self.ptrType(dst_ty, .Function);
37463761
3747 const tmp_id = try self.alloc(src_ty, .{ .storage_class = .Function });3762 const tmp_id = try self.alloc(src_ty, .{ .storage_class = .Function });
3748 try self.store(src_ty, tmp_id, src_id, .{});3763 try self.store(src_ty, tmp_id, src_id, .{});
3749 const casted_ptr_id = self.spv.allocId();3764 const casted_ptr_id = self.spv.allocId();
3750 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{3765 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
3751 .id_result_type = self.typeId(dst_ptr_ty_ref),3766 .id_result_type = dst_ptr_ty_id,
3752 .id_result = casted_ptr_id,3767 .id_result = casted_ptr_id,
3753 .operand = tmp_id,3768 .operand = tmp_id,
3754 });3769 });
...@@ -3761,7 +3776,7 @@ const DeclGen = struct {...@@ -3761,7 +3776,7 @@ const DeclGen = struct {
3761 // should we change the representation of strange integers?3776 // should we change the representation of strange integers?
3762 if (dst_ty.zigTypeTag(mod) == .Int) {3777 if (dst_ty.zigTypeTag(mod) == .Int) {
3763 const info = self.arithmeticTypeInfo(dst_ty);3778 const info = self.arithmeticTypeInfo(dst_ty);
3764 return try self.normalize(dst_ty_ref, result_id, info);3779 return try self.normalize(dst_ty, result_id, info);
3765 }3780 }
37663781
3767 return result_id;3782 return result_id;
...@@ -3811,7 +3826,7 @@ const DeclGen = struct {...@@ -3811,7 +3826,7 @@ const DeclGen = struct {
3811 // type, we don't need to normalize when growing the type. The3826 // type, we don't need to normalize when growing the type. The
3812 // representation is already the same.3827 // representation is already the same.
3813 if (dst_info.bits < src_info.bits) {3828 if (dst_info.bits < src_info.bits) {
3814 result_id.* = try self.normalize(wip.ty_ref, value_id, dst_info);3829 result_id.* = try self.normalize(wip.ty, value_id, dst_info);
3815 } else {3830 } else {
3816 result_id.* = value_id;3831 result_id.* = value_id;
3817 }3832 }
...@@ -3820,7 +3835,7 @@ const DeclGen = struct {...@@ -3820,7 +3835,7 @@ const DeclGen = struct {
3820 }3835 }
38213836
3822 fn intFromPtr(self: *DeclGen, operand_id: IdRef) !IdRef {3837 fn intFromPtr(self: *DeclGen, operand_id: IdRef) !IdRef {
3823 const result_type_id = try self.resolveTypeId(Type.usize);3838 const result_type_id = try self.resolveType(Type.usize, .direct);
3824 const result_id = self.spv.allocId();3839 const result_id = self.spv.allocId();
3825 try self.func.body.emit(self.spv.gpa, .OpConvertPtrToU, .{3840 try self.func.body.emit(self.spv.gpa, .OpConvertPtrToU, .{
3826 .id_result_type = result_type_id,3841 .id_result_type = result_type_id,
...@@ -3841,21 +3856,21 @@ const DeclGen = struct {...@@ -3841,21 +3856,21 @@ const DeclGen = struct {
3841 const operand_ty = self.typeOf(ty_op.operand);3856 const operand_ty = self.typeOf(ty_op.operand);
3842 const operand_id = try self.resolve(ty_op.operand);3857 const operand_id = try self.resolve(ty_op.operand);
3843 const result_ty = self.typeOfIndex(inst);3858 const result_ty = self.typeOfIndex(inst);
3844 const result_ty_ref = try self.resolveType(result_ty, .direct);3859 return try self.floatFromInt(result_ty, operand_ty, operand_id);
3845 return try self.floatFromInt(result_ty_ref, operand_ty, operand_id);
3846 }3860 }
38473861
3848 fn floatFromInt(self: *DeclGen, result_ty_ref: CacheRef, operand_ty: Type, operand_id: IdRef) !IdRef {3862 fn floatFromInt(self: *DeclGen, result_ty: Type, operand_ty: Type, operand_id: IdRef) !IdRef {
3849 const operand_info = self.arithmeticTypeInfo(operand_ty);3863 const operand_info = self.arithmeticTypeInfo(operand_ty);
3850 const result_id = self.spv.allocId();3864 const result_id = self.spv.allocId();
3865 const result_ty_id = try self.resolveType(result_ty, .direct);
3851 switch (operand_info.signedness) {3866 switch (operand_info.signedness) {
3852 .signed => try self.func.body.emit(self.spv.gpa, .OpConvertSToF, .{3867 .signed => try self.func.body.emit(self.spv.gpa, .OpConvertSToF, .{
3853 .id_result_type = self.typeId(result_ty_ref),3868 .id_result_type = result_ty_id,
3854 .id_result = result_id,3869 .id_result = result_id,
3855 .signed_value = operand_id,3870 .signed_value = operand_id,
3856 }),3871 }),
3857 .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertUToF, .{3872 .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertUToF, .{
3858 .id_result_type = self.typeId(result_ty_ref),3873 .id_result_type = result_ty_id,
3859 .id_result = result_id,3874 .id_result = result_id,
3860 .unsigned_value = operand_id,3875 .unsigned_value = operand_id,
3861 }),3876 }),
...@@ -3872,16 +3887,16 @@ const DeclGen = struct {...@@ -3872,16 +3887,16 @@ const DeclGen = struct {
38723887
3873 fn intFromFloat(self: *DeclGen, result_ty: Type, operand_id: IdRef) !IdRef {3888 fn intFromFloat(self: *DeclGen, result_ty: Type, operand_id: IdRef) !IdRef {
3874 const result_info = self.arithmeticTypeInfo(result_ty);3889 const result_info = self.arithmeticTypeInfo(result_ty);
3875 const result_ty_ref = try self.resolveType(result_ty, .direct);3890 const result_ty_id = try self.resolveType(result_ty, .direct);
3876 const result_id = self.spv.allocId();3891 const result_id = self.spv.allocId();
3877 switch (result_info.signedness) {3892 switch (result_info.signedness) {
3878 .signed => try self.func.body.emit(self.spv.gpa, .OpConvertFToS, .{3893 .signed => try self.func.body.emit(self.spv.gpa, .OpConvertFToS, .{
3879 .id_result_type = self.typeId(result_ty_ref),3894 .id_result_type = result_ty_id,
3880 .id_result = result_id,3895 .id_result = result_id,
3881 .float_value = operand_id,3896 .float_value = operand_id,
3882 }),3897 }),
3883 .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertFToU, .{3898 .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertFToU, .{
3884 .id_result_type = self.typeId(result_ty_ref),3899 .id_result_type = result_ty_id,
3885 .id_result = result_id,3900 .id_result = result_id,
3886 .float_value = operand_id,3901 .float_value = operand_id,
3887 }),3902 }),
...@@ -3898,7 +3913,7 @@ const DeclGen = struct {...@@ -3898,7 +3913,7 @@ const DeclGen = struct {
3898 defer wip.deinit();3913 defer wip.deinit();
3899 for (wip.results, 0..) |*result_id, i| {3914 for (wip.results, 0..) |*result_id, i| {
3900 const elem_id = try wip.elementAt(Type.bool, operand_id, i);3915 const elem_id = try wip.elementAt(Type.bool, operand_id, i);
3901 result_id.* = try self.intFromBool(wip.ty_ref, elem_id);3916 result_id.* = try self.intFromBool(wip.ty, elem_id);
3902 }3917 }
3903 return try wip.finalize();3918 return try wip.finalize();
3904 }3919 }
...@@ -3907,7 +3922,7 @@ const DeclGen = struct {...@@ -3907,7 +3922,7 @@ const DeclGen = struct {
3907 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3922 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3908 const operand_id = try self.resolve(ty_op.operand);3923 const operand_id = try self.resolve(ty_op.operand);
3909 const dest_ty = self.typeOfIndex(inst);3924 const dest_ty = self.typeOfIndex(inst);
3910 const dest_ty_id = try self.resolveTypeId(dest_ty);3925 const dest_ty_id = try self.resolveType(dest_ty, .direct);
39113926
3912 const result_id = self.spv.allocId();3927 const result_id = self.spv.allocId();
3913 try self.func.body.emit(self.spv.gpa, .OpFConvert, .{3928 try self.func.body.emit(self.spv.gpa, .OpFConvert, .{
...@@ -3957,18 +3972,17 @@ const DeclGen = struct {...@@ -3957,18 +3972,17 @@ const DeclGen = struct {
3957 const slice_ty = self.typeOfIndex(inst);3972 const slice_ty = self.typeOfIndex(inst);
3958 const elem_ptr_ty = slice_ty.slicePtrFieldType(mod);3973 const elem_ptr_ty = slice_ty.slicePtrFieldType(mod);
39593974
3960 const elem_ptr_ty_ref = try self.resolveType(elem_ptr_ty, .direct);3975 const elem_ptr_ty_id = try self.resolveType(elem_ptr_ty, .direct);
3961 const size_ty_ref = try self.sizeType();
39623976
3963 const array_ptr_id = try self.resolve(ty_op.operand);3977 const array_ptr_id = try self.resolve(ty_op.operand);
3964 const len_id = try self.constInt(size_ty_ref, array_ty.arrayLen(mod));3978 const len_id = try self.constInt(Type.usize, array_ty.arrayLen(mod), .direct);
39653979
3966 const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))3980 const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))
3967 // Note: The pointer is something like *opaque{}, so we need to bitcast it to the element type.3981 // Note: The pointer is something like *opaque{}, so we need to bitcast it to the element type.
3968 try self.bitCast(elem_ptr_ty, array_ptr_ty, array_ptr_id)3982 try self.bitCast(elem_ptr_ty, array_ptr_ty, array_ptr_id)
3969 else3983 else
3970 // Convert the pointer-to-array to a pointer to the first element.3984 // Convert the pointer-to-array to a pointer to the first element.
3971 try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0});3985 try self.accessChain(elem_ptr_ty_id, array_ptr_id, &.{0});
39723986
3973 return try self.constructStruct(3987 return try self.constructStruct(
3974 slice_ty,3988 slice_ty,
...@@ -4092,8 +4106,8 @@ const DeclGen = struct {...@@ -4092,8 +4106,8 @@ const DeclGen = struct {
4092 const array_ty = ty.childType(mod);4106 const array_ty = ty.childType(mod);
4093 const elem_ty = array_ty.childType(mod);4107 const elem_ty = array_ty.childType(mod);
4094 const abi_size = elem_ty.abiSize(mod);4108 const abi_size = elem_ty.abiSize(mod);
4095 const usize_ty_ref = try self.resolveType(Type.usize, .direct);4109 const size = array_ty.arrayLenIncludingSentinel(mod) * abi_size;
4096 return self.spv.constInt(usize_ty_ref, array_ty.arrayLenIncludingSentinel(mod) * abi_size);4110 return try self.constInt(Type.usize, size, .direct);
4097 },4111 },
4098 .Many, .C => unreachable,4112 .Many, .C => unreachable,
4099 }4113 }
...@@ -4142,10 +4156,10 @@ const DeclGen = struct {...@@ -4142,10 +4156,10 @@ const DeclGen = struct {
4142 const index_id = try self.resolve(bin_op.rhs);4156 const index_id = try self.resolve(bin_op.rhs);
41434157
4144 const ptr_ty = self.typeOfIndex(inst);4158 const ptr_ty = self.typeOfIndex(inst);
4145 const ptr_ty_ref = try self.resolveType(ptr_ty, .direct);4159 const ptr_ty_id = try self.resolveType(ptr_ty, .direct);
41464160
4147 const slice_ptr = try self.extractField(ptr_ty, slice_id, 0);4161 const slice_ptr = try self.extractField(ptr_ty, slice_id, 0);
4148 return try self.ptrAccessChain(ptr_ty_ref, slice_ptr, index_id, &.{});4162 return try self.ptrAccessChain(ptr_ty_id, slice_ptr, index_id, &.{});
4149 }4163 }
41504164
4151 fn airSliceElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {4165 fn airSliceElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
...@@ -4158,10 +4172,10 @@ const DeclGen = struct {...@@ -4158,10 +4172,10 @@ const DeclGen = struct {
4158 const index_id = try self.resolve(bin_op.rhs);4172 const index_id = try self.resolve(bin_op.rhs);
41594173
4160 const ptr_ty = slice_ty.slicePtrFieldType(mod);4174 const ptr_ty = slice_ty.slicePtrFieldType(mod);
4161 const ptr_ty_ref = try self.resolveType(ptr_ty, .direct);4175 const ptr_ty_id = try self.resolveType(ptr_ty, .direct);
41624176
4163 const slice_ptr = try self.extractField(ptr_ty, slice_id, 0);4177 const slice_ptr = try self.extractField(ptr_ty, slice_id, 0);
4164 const elem_ptr = try self.ptrAccessChain(ptr_ty_ref, slice_ptr, index_id, &.{});4178 const elem_ptr = try self.ptrAccessChain(ptr_ty_id, slice_ptr, index_id, &.{});
4165 return try self.load(slice_ty.childType(mod), elem_ptr, .{ .is_volatile = slice_ty.isVolatilePtr(mod) });4179 return try self.load(slice_ty.childType(mod), elem_ptr, .{ .is_volatile = slice_ty.isVolatilePtr(mod) });
4166 }4180 }
41674181
...@@ -4169,14 +4183,14 @@ const DeclGen = struct {...@@ -4169,14 +4183,14 @@ const DeclGen = struct {
4169 const mod = self.module;4183 const mod = self.module;
4170 // Construct new pointer type for the resulting pointer4184 // Construct new pointer type for the resulting pointer
4171 const elem_ty = ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T.4185 const elem_ty = ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T.
4172 const elem_ptr_ty_ref = try self.ptrType(elem_ty, self.spvStorageClass(ptr_ty.ptrAddressSpace(mod)));4186 const elem_ptr_ty_id = try self.ptrType(elem_ty, self.spvStorageClass(ptr_ty.ptrAddressSpace(mod)));
4173 if (ptr_ty.isSinglePointer(mod)) {4187 if (ptr_ty.isSinglePointer(mod)) {
4174 // Pointer-to-array. In this case, the resulting pointer is not of the same type4188 // Pointer-to-array. In this case, the resulting pointer is not of the same type
4175 // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain.4189 // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain.
4176 return try self.accessChainId(elem_ptr_ty_ref, ptr_id, &.{index_id});4190 return try self.accessChainId(elem_ptr_ty_id, ptr_id, &.{index_id});
4177 } else {4191 } else {
4178 // Resulting pointer type is the same as the ptr_ty, so use ptrAccessChain4192 // Resulting pointer type is the same as the ptr_ty, so use ptrAccessChain
4179 return try self.ptrAccessChain(elem_ptr_ty_ref, ptr_id, index_id, &.{});4193 return try self.ptrAccessChain(elem_ptr_ty_id, ptr_id, index_id, &.{});
4180 }4194 }
4181 }4195 }
41824196
...@@ -4209,11 +4223,11 @@ const DeclGen = struct {...@@ -4209,11 +4223,11 @@ const DeclGen = struct {
4209 // For now, just generate a temporary and use that.4223 // For now, just generate a temporary and use that.
4210 // TODO: This backend probably also should use isByRef from llvm...4224 // TODO: This backend probably also should use isByRef from llvm...
42114225
4212 const elem_ptr_ty_ref = try self.ptrType(elem_ty, .Function);4226 const elem_ptr_ty_id = try self.ptrType(elem_ty, .Function);
42134227
4214 const tmp_id = try self.alloc(array_ty, .{ .storage_class = .Function });4228 const tmp_id = try self.alloc(array_ty, .{ .storage_class = .Function });
4215 try self.store(array_ty, tmp_id, array_id, .{});4229 try self.store(array_ty, tmp_id, array_id, .{});
4216 const elem_ptr_id = try self.accessChainId(elem_ptr_ty_ref, tmp_id, &.{index_id});4230 const elem_ptr_id = try self.accessChainId(elem_ptr_ty_id, tmp_id, &.{index_id});
4217 return try self.load(elem_ty, elem_ptr_id, .{});4231 return try self.load(elem_ty, elem_ptr_id, .{});
4218 }4232 }
42194233
...@@ -4238,13 +4252,13 @@ const DeclGen = struct {...@@ -4238,13 +4252,13 @@ const DeclGen = struct {
4238 const scalar_ty = vector_ty.scalarType(mod);4252 const scalar_ty = vector_ty.scalarType(mod);
42394253
4240 const storage_class = self.spvStorageClass(vector_ptr_ty.ptrAddressSpace(mod));4254 const storage_class = self.spvStorageClass(vector_ptr_ty.ptrAddressSpace(mod));
4241 const scalar_ptr_ty_ref = try self.ptrType(scalar_ty, storage_class);4255 const scalar_ptr_ty_id = try self.ptrType(scalar_ty, storage_class);
42424256
4243 const vector_ptr = try self.resolve(data.vector_ptr);4257 const vector_ptr = try self.resolve(data.vector_ptr);
4244 const index = try self.resolve(extra.lhs);4258 const index = try self.resolve(extra.lhs);
4245 const operand = try self.resolve(extra.rhs);4259 const operand = try self.resolve(extra.rhs);
42464260
4247 const elem_ptr_id = try self.accessChainId(scalar_ptr_ty_ref, vector_ptr, &.{index});4261 const elem_ptr_id = try self.accessChainId(scalar_ptr_ty_id, vector_ptr, &.{index});
4248 try self.store(scalar_ty, elem_ptr_id, operand, .{4262 try self.store(scalar_ty, elem_ptr_id, operand, .{
4249 .is_volatile = vector_ptr_ty.isVolatilePtr(mod),4263 .is_volatile = vector_ptr_ty.isVolatilePtr(mod),
4250 });4264 });
...@@ -4260,7 +4274,7 @@ const DeclGen = struct {...@@ -4260,7 +4274,7 @@ const DeclGen = struct {
4260 if (layout.tag_size == 0) return;4274 if (layout.tag_size == 0) return;
42614275
4262 const tag_ty = un_ty.unionTagTypeSafety(mod).?;4276 const tag_ty = un_ty.unionTagTypeSafety(mod).?;
4263 const tag_ptr_ty_ref = try self.ptrType(tag_ty, self.spvStorageClass(un_ptr_ty.ptrAddressSpace(mod)));4277 const tag_ptr_ty_id = try self.ptrType(tag_ty, self.spvStorageClass(un_ptr_ty.ptrAddressSpace(mod)));
42644278
4265 const union_ptr_id = try self.resolve(bin_op.lhs);4279 const union_ptr_id = try self.resolve(bin_op.lhs);
4266 const new_tag_id = try self.resolve(bin_op.rhs);4280 const new_tag_id = try self.resolve(bin_op.rhs);
...@@ -4268,7 +4282,7 @@ const DeclGen = struct {...@@ -4268,7 +4282,7 @@ const DeclGen = struct {
4268 if (!layout.has_payload) {4282 if (!layout.has_payload) {
4269 try self.store(tag_ty, union_ptr_id, new_tag_id, .{ .is_volatile = un_ptr_ty.isVolatilePtr(mod) });4283 try self.store(tag_ty, union_ptr_id, new_tag_id, .{ .is_volatile = un_ptr_ty.isVolatilePtr(mod) });
4270 } else {4284 } else {
4271 const ptr_id = try self.accessChain(tag_ptr_ty_ref, union_ptr_id, &.{layout.tag_index});4285 const ptr_id = try self.accessChain(tag_ptr_ty_id, union_ptr_id, &.{layout.tag_index});
4272 try self.store(tag_ty, ptr_id, new_tag_id, .{ .is_volatile = un_ptr_ty.isVolatilePtr(mod) });4286 try self.store(tag_ty, ptr_id, new_tag_id, .{ .is_volatile = un_ptr_ty.isVolatilePtr(mod) });
4273 }4287 }
4274 }4288 }
...@@ -4298,6 +4312,8 @@ const DeclGen = struct {...@@ -4298,6 +4312,8 @@ const DeclGen = struct {
4298 // union type, then get the field pointer and pointer-cast it to the4312 // union type, then get the field pointer and pointer-cast it to the
4299 // right type to store it. Finally load the entire union.4313 // right type to store it. Finally load the entire union.
43004314
4315 // Note: The result here is not cached, because it generates runtime code.
4316
4301 const mod = self.module;4317 const mod = self.module;
4302 const ip = &mod.intern_pool;4318 const ip = &mod.intern_pool;
4303 const union_ty = mod.typeToUnion(ty).?;4319 const union_ty = mod.typeToUnion(ty).?;
...@@ -4316,28 +4332,26 @@ const DeclGen = struct {...@@ -4316,28 +4332,26 @@ const DeclGen = struct {
4316 } else 0;4332 } else 0;
43174333
4318 if (!layout.has_payload) {4334 if (!layout.has_payload) {
4319 const tag_ty_ref = try self.resolveType(tag_ty, .direct);4335 return try self.constInt(tag_ty, tag_int, .direct);
4320 return try self.constInt(tag_ty_ref, tag_int);
4321 }4336 }
43224337
4323 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });4338 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });
43244339
4325 if (layout.tag_size != 0) {4340 if (layout.tag_size != 0) {
4326 const tag_ty_ref = try self.resolveType(tag_ty, .direct);4341 const tag_ptr_ty_id = try self.ptrType(tag_ty, .Function);
4327 const tag_ptr_ty_ref = try self.ptrType(tag_ty, .Function);4342 const ptr_id = try self.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});
4328 const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});4343 const tag_id = try self.constInt(tag_ty, tag_int, .direct);
4329 const tag_id = try self.constInt(tag_ty_ref, tag_int);
4330 try self.store(tag_ty, ptr_id, tag_id, .{});4344 try self.store(tag_ty, ptr_id, tag_id, .{});
4331 }4345 }
43324346
4333 const payload_ty = Type.fromInterned(union_ty.field_types.get(ip)[active_field]);4347 const payload_ty = Type.fromInterned(union_ty.field_types.get(ip)[active_field]);
4334 if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {4348 if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
4335 const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, .Function);4349 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, .Function);
4336 const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, tmp_id, &.{layout.payload_index});4350 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
4337 const active_pl_ptr_ty_ref = try self.ptrType(payload_ty, .Function);4351 const active_pl_ptr_ty_id = try self.ptrType(payload_ty, .Function);
4338 const active_pl_ptr_id = self.spv.allocId();4352 const active_pl_ptr_id = self.spv.allocId();
4339 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{4353 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
4340 .id_result_type = self.typeId(active_pl_ptr_ty_ref),4354 .id_result_type = active_pl_ptr_ty_id,
4341 .id_result = active_pl_ptr_id,4355 .id_result = active_pl_ptr_id,
4342 .operand = pl_ptr_id,4356 .operand = pl_ptr_id,
4343 });4357 });
...@@ -4396,13 +4410,13 @@ const DeclGen = struct {...@@ -4396,13 +4410,13 @@ const DeclGen = struct {
4396 const tmp_id = try self.alloc(object_ty, .{ .storage_class = .Function });4410 const tmp_id = try self.alloc(object_ty, .{ .storage_class = .Function });
4397 try self.store(object_ty, tmp_id, object_id, .{});4411 try self.store(object_ty, tmp_id, object_id, .{});
43984412
4399 const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, .Function);4413 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, .Function);
4400 const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, tmp_id, &.{layout.payload_index});4414 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
44014415
4402 const active_pl_ptr_ty_ref = try self.ptrType(field_ty, .Function);4416 const active_pl_ptr_ty_id = try self.ptrType(field_ty, .Function);
4403 const active_pl_ptr_id = self.spv.allocId();4417 const active_pl_ptr_id = self.spv.allocId();
4404 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{4418 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
4405 .id_result_type = self.typeId(active_pl_ptr_ty_ref),4419 .id_result_type = active_pl_ptr_ty_id,
4406 .id_result = active_pl_ptr_id,4420 .id_result = active_pl_ptr_id,
4407 .operand = pl_ptr_id,4421 .operand = pl_ptr_id,
4408 });4422 });
...@@ -4419,9 +4433,7 @@ const DeclGen = struct {...@@ -4419,9 +4433,7 @@ const DeclGen = struct {
4419 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;4433 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
44204434
4421 const parent_ty = ty_pl.ty.toType().childType(mod);4435 const parent_ty = ty_pl.ty.toType().childType(mod);
4422 const res_ty = try self.resolveType(ty_pl.ty.toType(), .indirect);4436 const result_ty_id = try self.resolveType(ty_pl.ty.toType(), .indirect);
4423 const usize_ty = Type.usize;
4424 const usize_ty_ref = try self.resolveType(usize_ty, .direct);
44254437
4426 const field_ptr = try self.resolve(extra.field_ptr);4438 const field_ptr = try self.resolve(extra.field_ptr);
4427 const field_ptr_int = try self.intFromPtr(field_ptr);4439 const field_ptr_int = try self.intFromPtr(field_ptr);
...@@ -4430,13 +4442,13 @@ const DeclGen = struct {...@@ -4430,13 +4442,13 @@ const DeclGen = struct {
4430 const base_ptr_int = base_ptr_int: {4442 const base_ptr_int = base_ptr_int: {
4431 if (field_offset == 0) break :base_ptr_int field_ptr_int;4443 if (field_offset == 0) break :base_ptr_int field_ptr_int;
44324444
4433 const field_offset_id = try self.constInt(usize_ty_ref, field_offset);4445 const field_offset_id = try self.constInt(Type.usize, field_offset, .direct);
4434 break :base_ptr_int try self.binOpSimple(usize_ty, field_ptr_int, field_offset_id, .OpISub);4446 break :base_ptr_int try self.binOpSimple(Type.usize, field_ptr_int, field_offset_id, .OpISub);
4435 };4447 };
44364448
4437 const base_ptr = self.spv.allocId();4449 const base_ptr = self.spv.allocId();
4438 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{4450 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
4439 .id_result_type = self.spv.resultId(res_ty),4451 .id_result_type = result_ty_id,
4440 .id_result = base_ptr,4452 .id_result = base_ptr,
4441 .integer_value = base_ptr_int,4453 .integer_value = base_ptr_int,
4442 });4454 });
...@@ -4451,7 +4463,7 @@ const DeclGen = struct {...@@ -4451,7 +4463,7 @@ const DeclGen = struct {
4451 object_ptr: IdRef,4463 object_ptr: IdRef,
4452 field_index: u32,4464 field_index: u32,
4453 ) !IdRef {4465 ) !IdRef {
4454 const result_ty_ref = try self.resolveType(result_ptr_ty, .direct);4466 const result_ty_id = try self.resolveType(result_ptr_ty, .direct);
44554467
4456 const mod = self.module;4468 const mod = self.module;
4457 const object_ty = object_ptr_ty.childType(mod);4469 const object_ty = object_ptr_ty.childType(mod);
...@@ -4459,7 +4471,7 @@ const DeclGen = struct {...@@ -4459,7 +4471,7 @@ const DeclGen = struct {
4459 .Struct => switch (object_ty.containerLayout(mod)) {4471 .Struct => switch (object_ty.containerLayout(mod)) {
4460 .@"packed" => unreachable, // TODO4472 .@"packed" => unreachable, // TODO
4461 else => {4473 else => {
4462 return try self.accessChain(result_ty_ref, object_ptr, &.{field_index});4474 return try self.accessChain(result_ty_id, object_ptr, &.{field_index});
4463 },4475 },
4464 },4476 },
4465 .Union => switch (object_ty.containerLayout(mod)) {4477 .Union => switch (object_ty.containerLayout(mod)) {
...@@ -4469,16 +4481,16 @@ const DeclGen = struct {...@@ -4469,16 +4481,16 @@ const DeclGen = struct {
4469 if (!layout.has_payload) {4481 if (!layout.has_payload) {
4470 // Asked to get a pointer to a zero-sized field. Just lower this4482 // Asked to get a pointer to a zero-sized field. Just lower this
4471 // to undefined, there is no reason to make it be a valid pointer.4483 // to undefined, there is no reason to make it be a valid pointer.
4472 return try self.spv.constUndef(result_ty_ref);4484 return try self.spv.constUndef(result_ty_id);
4473 }4485 }
44744486
4475 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(mod));4487 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(mod));
4476 const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, storage_class);4488 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, storage_class);
4477 const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, object_ptr, &.{layout.payload_index});4489 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
44784490
4479 const active_pl_ptr_id = self.spv.allocId();4491 const active_pl_ptr_id = self.spv.allocId();
4480 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{4492 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
4481 .id_result_type = self.typeId(result_ty_ref),4493 .id_result_type = result_ty_id,
4482 .id_result = active_pl_ptr_id,4494 .id_result = active_pl_ptr_id,
4483 .operand = pl_ptr_id,4495 .operand = pl_ptr_id,
4484 });4496 });
...@@ -4506,7 +4518,7 @@ const DeclGen = struct {...@@ -4506,7 +4518,7 @@ const DeclGen = struct {
4506 };4518 };
45074519
4508 // Allocate a function-local variable, with possible initializer.4520 // Allocate a function-local variable, with possible initializer.
4509 // This function returns a pointer to a variable of type `ty_ref`,4521 // This function returns a pointer to a variable of type `ty`,
4510 // which is in the Generic address space. The variable is actually4522 // which is in the Generic address space. The variable is actually
4511 // placed in the Function address space.4523 // placed in the Function address space.
4512 fn alloc(4524 fn alloc(
...@@ -4514,13 +4526,13 @@ const DeclGen = struct {...@@ -4514,13 +4526,13 @@ const DeclGen = struct {
4514 ty: Type,4526 ty: Type,
4515 options: AllocOptions,4527 options: AllocOptions,
4516 ) !IdRef {4528 ) !IdRef {
4517 const ptr_fn_ty_ref = try self.ptrType(ty, .Function);4529 const ptr_fn_ty_id = try self.ptrType(ty, .Function);
45184530
4519 // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to4531 // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to
4520 // directly generate them into func.prologue instead of the body.4532 // directly generate them into func.prologue instead of the body.
4521 const var_id = self.spv.allocId();4533 const var_id = self.spv.allocId();
4522 try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{4534 try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{
4523 .id_result_type = self.typeId(ptr_fn_ty_ref),4535 .id_result_type = ptr_fn_ty_id,
4524 .id_result = var_id,4536 .id_result = var_id,
4525 .storage_class = .Function,4537 .storage_class = .Function,
4526 .initializer = options.initializer,4538 .initializer = options.initializer,
...@@ -4533,9 +4545,9 @@ const DeclGen = struct {...@@ -4533,9 +4545,9 @@ const DeclGen = struct {
45334545
4534 switch (options.storage_class) {4546 switch (options.storage_class) {
4535 .Generic => {4547 .Generic => {
4536 const ptr_gn_ty_ref = try self.ptrType(ty, .Generic);4548 const ptr_gn_ty_id = try self.ptrType(ty, .Generic);
4537 // Convert to a generic pointer4549 // Convert to a generic pointer
4538 return self.castToGeneric(self.typeId(ptr_gn_ty_ref), var_id);4550 return self.castToGeneric(ptr_gn_ty_id, var_id);
4539 },4551 },
4540 .Function => return var_id,4552 .Function => return var_id,
4541 else => unreachable,4553 else => unreachable,
...@@ -4563,9 +4575,9 @@ const DeclGen = struct {...@@ -4563,9 +4575,9 @@ const DeclGen = struct {
4563 assert(self.control_flow == .structured);4575 assert(self.control_flow == .structured);
45644576
4565 const result_id = self.spv.allocId();4577 const result_id = self.spv.allocId();
4566 const block_id_ty_ref = try self.intType(.unsigned, 32);4578 const block_id_ty_id = try self.resolveType(Type.u32, .direct);
4567 try self.func.body.emitRaw(self.spv.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent...4579 try self.func.body.emitRaw(self.spv.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent...
4568 self.func.body.writeOperand(spec.IdResultType, self.typeId(block_id_ty_ref));4580 self.func.body.writeOperand(spec.IdResultType, block_id_ty_id);
4569 self.func.body.writeOperand(spec.IdRef, result_id);4581 self.func.body.writeOperand(spec.IdRef, result_id);
45704582
4571 for (incoming) |incoming_block| {4583 for (incoming) |incoming_block| {
...@@ -4663,8 +4675,8 @@ const DeclGen = struct {...@@ -4663,8 +4675,8 @@ const DeclGen = struct {
4663 // Make sure that we are still in a block when exiting the function.4675 // Make sure that we are still in a block when exiting the function.
4664 // TODO: Can we get rid of that?4676 // TODO: Can we get rid of that?
4665 try self.beginSpvBlock(self.spv.allocId());4677 try self.beginSpvBlock(self.spv.allocId());
4666 const block_id_ty_ref = try self.intType(.unsigned, 32);4678 const block_id_ty_id = try self.resolveType(Type.u32, .direct);
4667 return try self.spv.constUndef(block_id_ty_ref);4679 return try self.spv.constUndef(block_id_ty_id);
4668 }4680 }
46694681
4670 // The top-most merge actually only has a single source, the4682 // The top-most merge actually only has a single source, the
...@@ -4745,7 +4757,7 @@ const DeclGen = struct {...@@ -4745,7 +4757,7 @@ const DeclGen = struct {
47454757
4746 assert(block.label != null);4758 assert(block.label != null);
4747 const result_id = self.spv.allocId();4759 const result_id = self.spv.allocId();
4748 const result_type_id = try self.resolveTypeId(ty);4760 const result_type_id = try self.resolveType(ty, .direct);
47494761
4750 try self.func.body.emitRaw(4762 try self.func.body.emitRaw(
4751 self.spv.gpa,4763 self.spv.gpa,
...@@ -4781,12 +4793,11 @@ const DeclGen = struct {...@@ -4781,12 +4793,11 @@ const DeclGen = struct {
4781 assert(cf.block_stack.items.len > 0);4793 assert(cf.block_stack.items.len > 0);
47824794
4783 // Check if the target of the branch was this current block.4795 // Check if the target of the branch was this current block.
4784 const block_id_ty_ref = try self.intType(.unsigned, 32);4796 const this_block = try self.constInt(Type.u32, @intFromEnum(inst), .direct);
4785 const this_block = try self.constInt(block_id_ty_ref, @intFromEnum(inst));
4786 const jump_to_this_block_id = self.spv.allocId();4797 const jump_to_this_block_id = self.spv.allocId();
4787 const bool_ty_ref = try self.resolveType(Type.bool, .direct);4798 const bool_ty_id = try self.resolveType(Type.bool, .direct);
4788 try self.func.body.emit(self.spv.gpa, .OpIEqual, .{4799 try self.func.body.emit(self.spv.gpa, .OpIEqual, .{
4789 .id_result_type = self.typeId(bool_ty_ref),4800 .id_result_type = bool_ty_id,
4790 .id_result = jump_to_this_block_id,4801 .id_result = jump_to_this_block_id,
4791 .operand_1 = next_block,4802 .operand_1 = next_block,
4792 .operand_2 = this_block,4803 .operand_2 = this_block,
...@@ -4862,8 +4873,7 @@ const DeclGen = struct {...@@ -4862,8 +4873,7 @@ const DeclGen = struct {
4862 try self.store(operand_ty, block_result_var_id, operand_id, .{});4873 try self.store(operand_ty, block_result_var_id, operand_id, .{});
4863 }4874 }
48644875
4865 const block_id_ty_ref = try self.intType(.unsigned, 32);4876 const next_block = try self.constInt(Type.u32, @intFromEnum(br.block_inst), .direct);
4866 const next_block = try self.constInt(block_id_ty_ref, @intFromEnum(br.block_inst));
4867 try self.structuredBreak(next_block);4877 try self.structuredBreak(next_block);
4868 },4878 },
4869 .unstructured => |cf| {4879 .unstructured => |cf| {
...@@ -5026,8 +5036,7 @@ const DeclGen = struct {...@@ -5026,8 +5036,7 @@ const DeclGen = struct {
5026 // Functions with an empty error set are emitted with an error code5036 // Functions with an empty error set are emitted with an error code
5027 // return type and return zero so they can be function pointers coerced5037 // return type and return zero so they can be function pointers coerced
5028 // to functions that return anyerror.5038 // to functions that return anyerror.
5029 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);5039 const no_err_id = try self.constInt(Type.anyerror, 0, .direct);
5030 const no_err_id = try self.constInt(err_ty_ref, 0);
5031 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });5040 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });
5032 } else {5041 } else {
5033 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});5042 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});
...@@ -5051,8 +5060,7 @@ const DeclGen = struct {...@@ -5051,8 +5060,7 @@ const DeclGen = struct {
5051 // Functions with an empty error set are emitted with an error code5060 // Functions with an empty error set are emitted with an error code
5052 // return type and return zero so they can be function pointers coerced5061 // return type and return zero so they can be function pointers coerced
5053 // to functions that return anyerror.5062 // to functions that return anyerror.
5054 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);5063 const no_err_id = try self.constInt(Type.anyerror, 0, .direct);
5055 const no_err_id = try self.constInt(err_ty_ref, 0);
5056 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });5064 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });
5057 } else {5065 } else {
5058 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});5066 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});
...@@ -5076,8 +5084,7 @@ const DeclGen = struct {...@@ -5076,8 +5084,7 @@ const DeclGen = struct {
5076 const err_union_ty = self.typeOf(pl_op.operand);5084 const err_union_ty = self.typeOf(pl_op.operand);
5077 const payload_ty = self.typeOfIndex(inst);5085 const payload_ty = self.typeOfIndex(inst);
50785086
5079 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);5087 const bool_ty_id = try self.resolveType(Type.bool, .direct);
5080 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
50815088
5082 const eu_layout = self.errorUnionLayout(payload_ty);5089 const eu_layout = self.errorUnionLayout(payload_ty);
50835090
...@@ -5087,10 +5094,10 @@ const DeclGen = struct {...@@ -5087,10 +5094,10 @@ const DeclGen = struct {
5087 else5094 else
5088 err_union_id;5095 err_union_id;
50895096
5090 const zero_id = try self.constInt(err_ty_ref, 0);5097 const zero_id = try self.constInt(Type.anyerror, 0, .direct);
5091 const is_err_id = self.spv.allocId();5098 const is_err_id = self.spv.allocId();
5092 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{5099 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
5093 .id_result_type = self.typeId(bool_ty_ref),5100 .id_result_type = bool_ty_id,
5094 .id_result = is_err_id,5101 .id_result = is_err_id,
5095 .operand_1 = err_id,5102 .operand_1 = err_id,
5096 .operand_2 = zero_id,5103 .operand_2 = zero_id,
...@@ -5142,11 +5149,11 @@ const DeclGen = struct {...@@ -5142,11 +5149,11 @@ const DeclGen = struct {
5142 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5149 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5143 const operand_id = try self.resolve(ty_op.operand);5150 const operand_id = try self.resolve(ty_op.operand);
5144 const err_union_ty = self.typeOf(ty_op.operand);5151 const err_union_ty = self.typeOf(ty_op.operand);
5145 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);5152 const err_ty_id = try self.resolveType(Type.anyerror, .direct);
51465153
5147 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {5154 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
5148 // No error possible, so just return undefined.5155 // No error possible, so just return undefined.
5149 return try self.spv.constUndef(err_ty_ref);5156 return try self.spv.constUndef(err_ty_id);
5150 }5157 }
51515158
5152 const payload_ty = err_union_ty.errorUnionPayload(mod);5159 const payload_ty = err_union_ty.errorUnionPayload(mod);
...@@ -5185,11 +5192,11 @@ const DeclGen = struct {...@@ -5185,11 +5192,11 @@ const DeclGen = struct {
5185 return operand_id;5192 return operand_id;
5186 }5193 }
51875194
5188 const payload_ty_ref = try self.resolveType(payload_ty, .indirect);5195 const payload_ty_id = try self.resolveType(payload_ty, .indirect);
51895196
5190 var members: [2]IdRef = undefined;5197 var members: [2]IdRef = undefined;
5191 members[eu_layout.errorFieldIndex()] = operand_id;5198 members[eu_layout.errorFieldIndex()] = operand_id;
5192 members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref);5199 members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_id);
51935200
5194 var types: [2]Type = undefined;5201 var types: [2]Type = undefined;
5195 types[eu_layout.errorFieldIndex()] = Type.anyerror;5202 types[eu_layout.errorFieldIndex()] = Type.anyerror;
...@@ -5203,15 +5210,14 @@ const DeclGen = struct {...@@ -5203,15 +5210,14 @@ const DeclGen = struct {
5203 const err_union_ty = self.typeOfIndex(inst);5210 const err_union_ty = self.typeOfIndex(inst);
5204 const operand_id = try self.resolve(ty_op.operand);5211 const operand_id = try self.resolve(ty_op.operand);
5205 const payload_ty = self.typeOf(ty_op.operand);5212 const payload_ty = self.typeOf(ty_op.operand);
5206 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
5207 const eu_layout = self.errorUnionLayout(payload_ty);5213 const eu_layout = self.errorUnionLayout(payload_ty);
52085214
5209 if (!eu_layout.payload_has_bits) {5215 if (!eu_layout.payload_has_bits) {
5210 return try self.constInt(err_ty_ref, 0);5216 return try self.constInt(Type.anyerror, 0, .direct);
5211 }5217 }
52125218
5213 var members: [2]IdRef = undefined;5219 var members: [2]IdRef = undefined;
5214 members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0);5220 members[eu_layout.errorFieldIndex()] = try self.constInt(Type.anyerror, 0, .direct);
5215 members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id);5221 members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id);
52165222
5217 var types: [2]Type = undefined;5223 var types: [2]Type = undefined;
...@@ -5229,7 +5235,7 @@ const DeclGen = struct {...@@ -5229,7 +5235,7 @@ const DeclGen = struct {
5229 const optional_ty = if (is_pointer) operand_ty.childType(mod) else operand_ty;5235 const optional_ty = if (is_pointer) operand_ty.childType(mod) else operand_ty;
5230 const payload_ty = optional_ty.optionalChild(mod);5236 const payload_ty = optional_ty.optionalChild(mod);
52315237
5232 const bool_ty_ref = try self.resolveType(Type.bool, .direct);5238 const bool_ty_id = try self.resolveType(Type.bool, .direct);
52335239
5234 if (optional_ty.optionalReprIsPayload(mod)) {5240 if (optional_ty.optionalReprIsPayload(mod)) {
5235 // Pointer payload represents nullability: pointer or slice.5241 // Pointer payload represents nullability: pointer or slice.
...@@ -5248,8 +5254,8 @@ const DeclGen = struct {...@@ -5248,8 +5254,8 @@ const DeclGen = struct {
5248 else5254 else
5249 loaded_id;5255 loaded_id;
52505256
5251 const payload_ty_ref = try self.resolveType(ptr_ty, .direct);5257 const payload_ty_id = try self.resolveType(ptr_ty, .direct);
5252 const null_id = try self.spv.constNull(payload_ty_ref);5258 const null_id = try self.spv.constNull(payload_ty_id);
5253 const op: std.math.CompareOperator = switch (pred) {5259 const op: std.math.CompareOperator = switch (pred) {
5254 .is_null => .eq,5260 .is_null => .eq,
5255 .is_non_null => .neq,5261 .is_non_null => .neq,
...@@ -5261,8 +5267,8 @@ const DeclGen = struct {...@@ -5261,8 +5267,8 @@ const DeclGen = struct {
5261 if (is_pointer) {5267 if (is_pointer) {
5262 if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {5268 if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
5263 const storage_class = self.spvStorageClass(operand_ty.ptrAddressSpace(mod));5269 const storage_class = self.spvStorageClass(operand_ty.ptrAddressSpace(mod));
5264 const bool_ptr_ty = try self.ptrType(Type.bool, storage_class);5270 const bool_ptr_ty_id = try self.ptrType(Type.bool, storage_class);
5265 const tag_ptr_id = try self.accessChain(bool_ptr_ty, operand_id, &.{1});5271 const tag_ptr_id = try self.accessChain(bool_ptr_ty_id, operand_id, &.{1});
5266 break :blk try self.load(Type.bool, tag_ptr_id, .{});5272 break :blk try self.load(Type.bool, tag_ptr_id, .{});
5267 }5273 }
52685274
...@@ -5283,7 +5289,7 @@ const DeclGen = struct {...@@ -5283,7 +5289,7 @@ const DeclGen = struct {
5283 // Invert condition5289 // Invert condition
5284 const result_id = self.spv.allocId();5290 const result_id = self.spv.allocId();
5285 try self.func.body.emit(self.spv.gpa, .OpLogicalNot, .{5291 try self.func.body.emit(self.spv.gpa, .OpLogicalNot, .{
5286 .id_result_type = self.typeId(bool_ty_ref),5292 .id_result_type = bool_ty_id,
5287 .id_result = result_id,5293 .id_result = result_id,
5288 .operand = is_non_null_id,5294 .operand = is_non_null_id,
5289 });5295 });
...@@ -5305,8 +5311,7 @@ const DeclGen = struct {...@@ -5305,8 +5311,7 @@ const DeclGen = struct {
53055311
5306 const payload_ty = err_union_ty.errorUnionPayload(mod);5312 const payload_ty = err_union_ty.errorUnionPayload(mod);
5307 const eu_layout = self.errorUnionLayout(payload_ty);5313 const eu_layout = self.errorUnionLayout(payload_ty);
5308 const bool_ty_ref = try self.resolveType(Type.bool, .direct);5314 const bool_ty_id = try self.resolveType(Type.bool, .direct);
5309 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
53105315
5311 const error_id = if (!eu_layout.payload_has_bits)5316 const error_id = if (!eu_layout.payload_has_bits)
5312 operand_id5317 operand_id
...@@ -5315,10 +5320,10 @@ const DeclGen = struct {...@@ -5315,10 +5320,10 @@ const DeclGen = struct {
53155320
5316 const result_id = self.spv.allocId();5321 const result_id = self.spv.allocId();
5317 const operands = .{5322 const operands = .{
5318 .id_result_type = self.typeId(bool_ty_ref),5323 .id_result_type = bool_ty_id,
5319 .id_result = result_id,5324 .id_result = result_id,
5320 .operand_1 = error_id,5325 .operand_1 = error_id,
5321 .operand_2 = try self.constInt(err_ty_ref, 0),5326 .operand_2 = try self.constInt(Type.anyerror, 0, .direct),
5322 };5327 };
5323 switch (pred) {5328 switch (pred) {
5324 .is_err => try self.func.body.emit(self.spv.gpa, .OpINotEqual, operands),5329 .is_err => try self.func.body.emit(self.spv.gpa, .OpINotEqual, operands),
...@@ -5351,7 +5356,7 @@ const DeclGen = struct {...@@ -5351,7 +5356,7 @@ const DeclGen = struct {
5351 const optional_ty = operand_ty.childType(mod);5356 const optional_ty = operand_ty.childType(mod);
5352 const payload_ty = optional_ty.optionalChild(mod);5357 const payload_ty = optional_ty.optionalChild(mod);
5353 const result_ty = self.typeOfIndex(inst);5358 const result_ty = self.typeOfIndex(inst);
5354 const result_ty_ref = try self.resolveType(result_ty, .direct);5359 const result_ty_id = try self.resolveType(result_ty, .direct);
53555360
5356 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {5361 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
5357 // There is no payload, but we still need to return a valid pointer.5362 // There is no payload, but we still need to return a valid pointer.
...@@ -5364,7 +5369,7 @@ const DeclGen = struct {...@@ -5364,7 +5369,7 @@ const DeclGen = struct {
5364 return try self.bitCast(result_ty, operand_ty, operand_id);5369 return try self.bitCast(result_ty, operand_ty, operand_id);
5365 }5370 }
53665371
5367 return try self.accessChain(result_ty_ref, operand_id, &.{0});5372 return try self.accessChain(result_ty_id, operand_id, &.{0});
5368 }5373 }
53695374
5370 fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {5375 fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
...@@ -5440,7 +5445,7 @@ const DeclGen = struct {...@@ -5440,7 +5445,7 @@ const DeclGen = struct {
5440 };5445 };
54415446
5442 // First, pre-allocate the labels for the cases.5447 // First, pre-allocate the labels for the cases.
5443 const first_case_label = self.spv.allocIds(num_cases);5448 const case_labels = self.spv.allocIds(num_cases);
5444 // We always need the default case - if zig has none, we will generate unreachable there.5449 // We always need the default case - if zig has none, we will generate unreachable there.
5445 const default = self.spv.allocId();5450 const default = self.spv.allocId();
54465451
...@@ -5471,7 +5476,7 @@ const DeclGen = struct {...@@ -5471,7 +5476,7 @@ const DeclGen = struct {
5471 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];5476 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
5472 extra_index = case.end + case.data.items_len + case_body.len;5477 extra_index = case.end + case.data.items_len + case_body.len;
54735478
5474 const label: IdRef = @enumFromInt(@intFromEnum(first_case_label) + case_i);5479 const label = case_labels.at(case_i);
54755480
5476 for (items) |item| {5481 for (items) |item| {
5477 const value = (try self.air.value(item, mod)) orelse unreachable;5482 const value = (try self.air.value(item, mod)) orelse unreachable;
...@@ -5511,7 +5516,7 @@ const DeclGen = struct {...@@ -5511,7 +5516,7 @@ const DeclGen = struct {
5511 const case_body: []const Air.Inst.Index = @ptrCast(self.air.extra[case.end + items.len ..][0..case.data.body_len]);5516 const case_body: []const Air.Inst.Index = @ptrCast(self.air.extra[case.end + items.len ..][0..case.data.body_len]);
5512 extra_index = case.end + case.data.items_len + case_body.len;5517 extra_index = case.end + case.data.items_len + case_body.len;
55135518
5514 const label: IdResult = @enumFromInt(@intFromEnum(first_case_label) + case_i);5519 const label = case_labels.at(case_i);
55155520
5516 try self.beginSpvBlock(label);5521 try self.beginSpvBlock(label);
55175522
...@@ -5566,9 +5571,8 @@ const DeclGen = struct {...@@ -5566,9 +5571,8 @@ const DeclGen = struct {
5566 const mod = self.module;5571 const mod = self.module;
5567 const decl = mod.declPtr(self.decl_index);5572 const decl = mod.declPtr(self.decl_index);
5568 const path = decl.getFileScope(mod).sub_file_path;5573 const path = decl.getFileScope(mod).sub_file_path;
5569 const src_fname_id = try self.spv.resolveSourceFileName(path);
5570 try self.func.body.emit(self.spv.gpa, .OpLine, .{5574 try self.func.body.emit(self.spv.gpa, .OpLine, .{
5571 .file = src_fname_id,5575 .file = try self.spv.resolveString(path),
5572 .line = self.base_line + dbg_stmt.line + 1,5576 .line = self.base_line + dbg_stmt.line + 1,
5573 .column = dbg_stmt.column + 1,5577 .column = dbg_stmt.column + 1,
5574 });5578 });
...@@ -5737,7 +5741,7 @@ const DeclGen = struct {...@@ -5737,7 +5741,7 @@ const DeclGen = struct {
5737 const fn_info = mod.typeToFunc(zig_fn_ty).?;5741 const fn_info = mod.typeToFunc(zig_fn_ty).?;
5738 const return_type = fn_info.return_type;5742 const return_type = fn_info.return_type;
57395743
5740 const result_type_ref = try self.resolveFnReturnType(Type.fromInterned(return_type));5744 const result_type_id = try self.resolveFnReturnType(Type.fromInterned(return_type));
5741 const result_id = self.spv.allocId();5745 const result_id = self.spv.allocId();
5742 const callee_id = try self.resolve(pl_op.operand);5746 const callee_id = try self.resolve(pl_op.operand);
57435747
...@@ -5758,7 +5762,7 @@ const DeclGen = struct {...@@ -5758,7 +5762,7 @@ const DeclGen = struct {
5758 }5762 }
57595763
5760 try self.func.body.emit(self.spv.gpa, .OpFunctionCall, .{5764 try self.func.body.emit(self.spv.gpa, .OpFunctionCall, .{
5761 .id_result_type = self.typeId(result_type_ref),5765 .id_result_type = result_type_id,
5762 .id_result = result_id,5766 .id_result = result_id,
5763 .function = callee_id,5767 .function = callee_id,
5764 .id_ref_3 = params[0..n_params],5768 .id_ref_3 = params[0..n_params],
src/codegen/spirv/Assembler.zig+67-51
...@@ -9,10 +9,9 @@ const Opcode = spec.Opcode;...@@ -9,10 +9,9 @@ const Opcode = spec.Opcode;
9const Word = spec.Word;9const Word = spec.Word;
10const IdRef = spec.IdRef;10const IdRef = spec.IdRef;
11const IdResult = spec.IdResult;11const IdResult = spec.IdResult;
12const StorageClass = spec.StorageClass;
1213
13const SpvModule = @import("Module.zig");14const SpvModule = @import("Module.zig");
14const CacheRef = SpvModule.CacheRef;
15const CacheKey = SpvModule.CacheKey;
1615
17/// Represents a token in the assembly template.16/// Represents a token in the assembly template.
18const Token = struct {17const Token = struct {
...@@ -127,16 +126,16 @@ const AsmValue = union(enum) {...@@ -127,16 +126,16 @@ const AsmValue = union(enum) {
127 value: IdRef,126 value: IdRef,
128127
129 /// This result-value represents a type registered into the module's type system.128 /// This result-value represents a type registered into the module's type system.
130 ty: CacheRef,129 ty: IdRef,
131130
132 /// Retrieve the result-id of this AsmValue. Asserts that this AsmValue131 /// Retrieve the result-id of this AsmValue. Asserts that this AsmValue
133 /// is of a variant that allows the result to be obtained (not an unresolved132 /// is of a variant that allows the result to be obtained (not an unresolved
134 /// forward declaration, not in the process of being declared, etc).133 /// forward declaration, not in the process of being declared, etc).
135 pub fn resultId(self: AsmValue, spv: *const SpvModule) IdRef {134 pub fn resultId(self: AsmValue) IdRef {
136 return switch (self) {135 return switch (self) {
137 .just_declared, .unresolved_forward_reference => unreachable,136 .just_declared, .unresolved_forward_reference => unreachable,
138 .value => |result| result,137 .value => |result| result,
139 .ty => |ref| spv.resultId(ref),138 .ty => |result| result,
140 };139 };
141 }140 }
142};141};
...@@ -292,9 +291,10 @@ fn processInstruction(self: *Assembler) !void {...@@ -292,9 +291,10 @@ fn processInstruction(self: *Assembler) !void {
292/// refers to the result.291/// refers to the result.
293fn processTypeInstruction(self: *Assembler) !AsmValue {292fn processTypeInstruction(self: *Assembler) !AsmValue {
294 const operands = self.inst.operands.items;293 const operands = self.inst.operands.items;
295 const ref = switch (self.inst.opcode) {294 const section = &self.spv.sections.types_globals_constants;
296 .OpTypeVoid => try self.spv.resolve(.void_type),295 const id = switch (self.inst.opcode) {
297 .OpTypeBool => try self.spv.resolve(.bool_type),296 .OpTypeVoid => try self.spv.voidType(),
297 .OpTypeBool => try self.spv.boolType(),
298 .OpTypeInt => blk: {298 .OpTypeInt => blk: {
299 const signedness: std.builtin.Signedness = switch (operands[2].literal32) {299 const signedness: std.builtin.Signedness = switch (operands[2].literal32) {
300 0 => .unsigned,300 0 => .unsigned,
...@@ -317,43 +317,49 @@ fn processTypeInstruction(self: *Assembler) !AsmValue {...@@ -317,43 +317,49 @@ fn processTypeInstruction(self: *Assembler) !AsmValue {
317 return self.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits});317 return self.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits});
318 },318 },
319 }319 }
320 break :blk try self.spv.resolve(.{ .float_type = .{ .bits = @intCast(bits) } });320 break :blk try self.spv.floatType(@intCast(bits));
321 },
322 .OpTypeVector => blk: {
323 const child_type = try self.resolveRefId(operands[1].ref_id);
324 break :blk try self.spv.vectorType(operands[2].literal32, child_type);
321 },325 },
322 .OpTypeVector => try self.spv.resolve(.{ .vector_type = .{
323 .component_type = try self.resolveTypeRef(operands[1].ref_id),
324 .component_count = operands[2].literal32,
325 } }),
326 .OpTypeArray => {326 .OpTypeArray => {
327 // TODO: The length of an OpTypeArray is determined by a constant (which may be a spec constant),327 // TODO: The length of an OpTypeArray is determined by a constant (which may be a spec constant),
328 // and so some consideration must be taken when entering this in the type system.328 // and so some consideration must be taken when entering this in the type system.
329 return self.todo("process OpTypeArray", .{});329 return self.todo("process OpTypeArray", .{});
330 },330 },
331 .OpTypePointer => blk: {331 .OpTypePointer => blk: {
332 break :blk try self.spv.resolve(.{332 const storage_class: StorageClass = @enumFromInt(operands[1].value);
333 .ptr_type = .{333 const child_type = try self.resolveRefId(operands[2].ref_id);
334 .storage_class = @enumFromInt(operands[1].value),334 const result_id = self.spv.allocId();
335 .child_type = try self.resolveTypeRef(operands[2].ref_id),335 try section.emit(self.spv.gpa, .OpTypePointer, .{
336 // TODO: This should be a proper reference resolved via OpTypeForwardPointer336 .id_result = result_id,
337 .fwd = @enumFromInt(std.math.maxInt(u32)),337 .storage_class = storage_class,
338 },338 .type = child_type,
339 });339 });
340 break :blk result_id;
340 },341 },
341 .OpTypeFunction => blk: {342 .OpTypeFunction => blk: {
342 const param_operands = operands[2..];343 const param_operands = operands[2..];
343 const param_types = try self.spv.gpa.alloc(CacheRef, param_operands.len);344 const return_type = try self.resolveRefId(operands[1].ref_id);
345
346 const param_types = try self.spv.gpa.alloc(IdRef, param_operands.len);
344 defer self.spv.gpa.free(param_types);347 defer self.spv.gpa.free(param_types);
345 for (param_types, 0..) |*param, i| {348 for (param_types, param_operands) |*param, operand| {
346 param.* = try self.resolveTypeRef(param_operands[i].ref_id);349 param.* = try self.resolveRefId(operand.ref_id);
347 }350 }
348 break :blk try self.spv.resolve(.{ .function_type = .{351 const result_id = self.spv.allocId();
349 .return_type = try self.resolveTypeRef(operands[1].ref_id),352 try section.emit(self.spv.gpa, .OpTypeFunction, .{
350 .parameters = param_types,353 .id_result = result_id,
351 } });354 .return_type = return_type,
355 .id_ref_2 = param_types,
356 });
357 break :blk result_id;
352 },358 },
353 else => return self.todo("process type instruction {s}", .{@tagName(self.inst.opcode)}),359 else => return self.todo("process type instruction {s}", .{@tagName(self.inst.opcode)}),
354 };360 };
355361
356 return AsmValue{ .ty = ref };362 return AsmValue{ .ty = id };
357}363}
358364
359/// Emit `self.inst` into `self.spv` and `self.func`, and return the AsmValue365/// Emit `self.inst` into `self.spv` and `self.func`, and return the AsmValue
...@@ -410,7 +416,7 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {...@@ -410,7 +416,7 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {
410 .ref_id => |index| {416 .ref_id => |index| {
411 const result = try self.resolveRef(index);417 const result = try self.resolveRef(index);
412 try section.ensureUnusedCapacity(self.spv.gpa, 1);418 try section.ensureUnusedCapacity(self.spv.gpa, 1);
413 section.writeOperand(spec.IdRef, result.resultId(self.spv));419 section.writeOperand(spec.IdRef, result.resultId());
414 },420 },
415 .string => |offset| {421 .string => |offset| {
416 const text = std.mem.sliceTo(self.inst.string_bytes.items[offset..], 0);422 const text = std.mem.sliceTo(self.inst.string_bytes.items[offset..], 0);
...@@ -459,18 +465,9 @@ fn resolveRef(self: *Assembler, ref: AsmValue.Ref) !AsmValue {...@@ -459,18 +465,9 @@ fn resolveRef(self: *Assembler, ref: AsmValue.Ref) !AsmValue {
459 }465 }
460}466}
461467
462/// Resolve a value reference as type.468fn resolveRefId(self: *Assembler, ref: AsmValue.Ref) !IdRef {
463fn resolveTypeRef(self: *Assembler, ref: AsmValue.Ref) !CacheRef {
464 const value = try self.resolveRef(ref);469 const value = try self.resolveRef(ref);
465 switch (value) {470 return value.resultId();
466 .just_declared, .unresolved_forward_reference => unreachable,
467 .ty => |ty_ref| return ty_ref,
468 else => {
469 const name = self.value_map.keys()[ref];
470 // TODO: Improve source location.
471 return self.fail(0, "expected operand %{s} to refer to a type", .{name});
472 },
473 }
474}471}
475472
476/// Attempt to parse an instruction into `self.inst`.473/// Attempt to parse an instruction into `self.inst`.
...@@ -709,22 +706,41 @@ fn parseContextDependentNumber(self: *Assembler) !void {...@@ -709,22 +706,41 @@ fn parseContextDependentNumber(self: *Assembler) !void {
709 assert(self.inst.opcode == .OpConstant or self.inst.opcode == .OpSpecConstant);706 assert(self.inst.opcode == .OpConstant or self.inst.opcode == .OpSpecConstant);
710707
711 const tok = self.currentToken();708 const tok = self.currentToken();
712 const result_type_ref = try self.resolveTypeRef(self.inst.operands.items[0].ref_id);709 const result = try self.resolveRef(self.inst.operands.items[0].ref_id);
713 const result_type = self.spv.cache.lookup(result_type_ref);710 const result_id = result.resultId();
714 switch (result_type) {711 // We are going to cheat a little bit: The types we are interested in, int and float,
715 .int_type => |int| {712 // are added to the module and cached via self.spv.intType and self.spv.floatType. Therefore,
716 try self.parseContextDependentInt(int.signedness, int.bits);713 // we can determine the width of these types by directly checking the cache.
717 },714 // This only works if the Assembler and codegen both use spv.intType and spv.floatType though.
718 .float_type => |float| {715 // We don't expect there to be many of these types, so just look it up every time.
719 switch (float.bits) {716 // TODO: Count be improved to be a little bit more efficent.
717
718 {
719 var it = self.spv.cache.int_types.iterator();
720 while (it.next()) |entry| {
721 const id = entry.value_ptr.*;
722 if (id != result_id) continue;
723 const info = entry.key_ptr.*;
724 return try self.parseContextDependentInt(info.signedness, info.bits);
725 }
726 }
727
728 {
729 var it = self.spv.cache.float_types.iterator();
730 while (it.next()) |entry| {
731 const id = entry.value_ptr.*;
732 if (id != result_id) continue;
733 const info = entry.key_ptr.*;
734 switch (info.bits) {
720 16 => try self.parseContextDependentFloat(16),735 16 => try self.parseContextDependentFloat(16),
721 32 => try self.parseContextDependentFloat(32),736 32 => try self.parseContextDependentFloat(32),
722 64 => try self.parseContextDependentFloat(64),737 64 => try self.parseContextDependentFloat(64),
723 else => return self.fail(tok.start, "cannot parse {}-bit float literal", .{float.bits}),738 else => return self.fail(tok.start, "cannot parse {}-bit info literal", .{info.bits}),
724 }739 }
725 },740 }
726 else => return self.fail(tok.start, "cannot parse literal constant", .{}),
727 }741 }
742
743 return self.fail(tok.start, "cannot parse literal constant", .{});
728}744}
729745
730fn parseContextDependentInt(self: *Assembler, signedness: std.builtin.Signedness, width: u32) !void {746fn parseContextDependentInt(self: *Assembler, signedness: std.builtin.Signedness, width: u32) !void {
src/codegen/spirv/Cache.zig deleted-1125
...@@ -1,1125 +0,0 @@
1//! This file implements an InternPool-like structure that caches
2//! SPIR-V types and constants. Instead of generating type and
3//! constant instructions directly, we first keep a representation
4//! in a compressed database. This is then only later turned into
5//! actual SPIR-V instructions.
6//! Note: This cache is insertion-ordered. This means that we
7//! can materialize the SPIR-V instructions in the proper order,
8//! as SPIR-V requires that the type is emitted before use.
9//! Note: According to SPIR-V spec section 2.8, Types and Variables,
10//! non-pointer non-aggrerate types (which includes matrices and
11//! vectors) must have a _unique_ representation in the final binary.
12
13const std = @import("std");
14const assert = std.debug.assert;
15const Allocator = std.mem.Allocator;
16
17const Section = @import("Section.zig");
18const Module = @import("Module.zig");
19
20const spec = @import("spec.zig");
21const Opcode = spec.Opcode;
22const IdResult = spec.IdResult;
23const StorageClass = spec.StorageClass;
24
25const InternPool = @import("../../InternPool.zig");
26
27const Self = @This();
28
29map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
30items: std.MultiArrayList(Item) = .{},
31extra: std.ArrayListUnmanaged(u32) = .{},
32
33string_bytes: std.ArrayListUnmanaged(u8) = .{},
34strings: std.AutoArrayHashMapUnmanaged(void, u32) = .{},
35
36recursive_ptrs: std.AutoHashMapUnmanaged(Ref, void) = .{},
37
38const Item = struct {
39 tag: Tag,
40 /// The result-id that this item uses.
41 result_id: IdResult,
42 /// The Tag determines how this should be interpreted.
43 data: u32,
44};
45
46const Tag = enum {
47 // -- Types
48 /// Simple type that has no additional data.
49 /// data is SimpleType.
50 type_simple,
51 /// Signed integer type
52 /// data is number of bits
53 type_int_signed,
54 /// Unsigned integer type
55 /// data is number of bits
56 type_int_unsigned,
57 /// Floating point type
58 /// data is number of bits
59 type_float,
60 /// Vector type
61 /// data is payload to VectorType
62 type_vector,
63 /// Array type
64 /// data is payload to ArrayType
65 type_array,
66 /// Function (proto)type
67 /// data is payload to FunctionType
68 type_function,
69 // /// Pointer type in the CrossWorkgroup storage class
70 // /// data is child type
71 // type_ptr_generic,
72 // /// Pointer type in the CrossWorkgroup storage class
73 // /// data is child type
74 // type_ptr_crosswgp,
75 // /// Pointer type in the Function storage class
76 // /// data is child type
77 // type_ptr_function,
78 /// Simple pointer type that does not have any decorations.
79 /// data is payload to SimplePointerType
80 type_ptr_simple,
81 /// A forward declaration for a pointer.
82 /// data is ForwardPointerType
83 type_fwd_ptr,
84 /// Simple structure type that does not have any decorations.
85 /// data is payload to SimpleStructType
86 type_struct_simple,
87 /// Simple structure type that does not have any decorations, but does
88 /// have member names trailing.
89 /// data is payload to SimpleStructType
90 type_struct_simple_with_member_names,
91 /// Opaque type.
92 /// data is name string.
93 type_opaque,
94
95 // -- Values
96 /// Value of type u8
97 /// data is value
98 uint8,
99 /// Value of type u32
100 /// data is value
101 uint32,
102 // TODO: More specialized tags here.
103 /// Integer value for signed values that are smaller than 32 bits.
104 /// data is pointer to Int32
105 int_small,
106 /// Integer value for unsigned values that are smaller than 32 bits.
107 /// data is pointer to UInt32
108 uint_small,
109 /// Integer value for signed values that are beteen 32 and 64 bits.
110 /// data is pointer to Int64
111 int_large,
112 /// Integer value for unsinged values that are beteen 32 and 64 bits.
113 /// data is pointer to UInt64
114 uint_large,
115 /// Value of type f16
116 /// data is value
117 float16,
118 /// Value of type f32
119 /// data is value
120 float32,
121 /// Value of type f64
122 /// data is payload to Float16
123 float64,
124 /// Undefined value
125 /// data is type
126 undef,
127 /// Null value
128 /// data is type
129 null,
130 /// Bool value that is true
131 /// data is (bool) type
132 bool_true,
133 /// Bool value that is false
134 /// data is (bool) type
135 bool_false,
136
137 const SimpleType = enum {
138 void,
139 bool,
140 };
141
142 const VectorType = Key.VectorType;
143 const ArrayType = Key.ArrayType;
144
145 // Trailing:
146 // - [param_len]Ref: parameter types.
147 const FunctionType = struct {
148 param_len: u32,
149 return_type: Ref,
150 };
151
152 const SimplePointerType = struct {
153 storage_class: StorageClass,
154 child_type: Ref,
155 fwd: Ref,
156 };
157
158 const ForwardPointerType = struct {
159 storage_class: StorageClass,
160 zig_child_type: InternPool.Index,
161 };
162
163 /// Trailing:
164 /// - [members_len]Ref: Member types.
165 /// - [members_len]String: Member names, -- ONLY if the tag is type_struct_simple_with_member_names
166 const SimpleStructType = struct {
167 /// (optional) The name of the struct.
168 name: String,
169 /// Number of members that this struct has.
170 members_len: u32,
171 };
172
173 const Float64 = struct {
174 // Low-order 32 bits of the value.
175 low: u32,
176 // High-order 32 bits of the value.
177 high: u32,
178
179 fn encode(value: f64) Float64 {
180 const bits = @as(u64, @bitCast(value));
181 return .{
182 .low = @truncate(bits),
183 .high = @truncate(bits >> 32),
184 };
185 }
186
187 fn decode(self: Float64) f64 {
188 const bits = @as(u64, self.low) | (@as(u64, self.high) << 32);
189 return @bitCast(bits);
190 }
191 };
192
193 const Int32 = struct {
194 ty: Ref,
195 value: i32,
196 };
197
198 const UInt32 = struct {
199 ty: Ref,
200 value: u32,
201 };
202
203 const UInt64 = struct {
204 ty: Ref,
205 low: u32,
206 high: u32,
207
208 fn encode(ty: Ref, value: u64) Int64 {
209 return .{
210 .ty = ty,
211 .low = @truncate(value),
212 .high = @truncate(value >> 32),
213 };
214 }
215
216 fn decode(self: UInt64) u64 {
217 return @as(u64, self.low) | (@as(u64, self.high) << 32);
218 }
219 };
220
221 const Int64 = struct {
222 ty: Ref,
223 low: u32,
224 high: u32,
225
226 fn encode(ty: Ref, value: i64) Int64 {
227 return .{
228 .ty = ty,
229 .low = @truncate(@as(u64, @bitCast(value))),
230 .high = @truncate(@as(u64, @bitCast(value)) >> 32),
231 };
232 }
233
234 fn decode(self: Int64) i64 {
235 return @as(i64, @bitCast(@as(u64, self.low) | (@as(u64, self.high) << 32)));
236 }
237 };
238};
239
240pub const Ref = enum(u32) { _ };
241
242/// This union represents something that can be interned. This includes
243/// types and constants. This structure is used for interfacing with the
244/// database: Values described for this structure are ephemeral and stored
245/// in a more memory-efficient manner internally.
246pub const Key = union(enum) {
247 // -- Types
248 void_type,
249 bool_type,
250 int_type: IntType,
251 float_type: FloatType,
252 vector_type: VectorType,
253 array_type: ArrayType,
254 function_type: FunctionType,
255 ptr_type: PointerType,
256 fwd_ptr_type: ForwardPointerType,
257 struct_type: StructType,
258 opaque_type: OpaqueType,
259
260 // -- values
261 int: Int,
262 float: Float,
263 undef: Undef,
264 null: Null,
265 bool: Bool,
266
267 pub const IntType = std.builtin.Type.Int;
268 pub const FloatType = std.builtin.Type.Float;
269
270 pub const VectorType = struct {
271 component_type: Ref,
272 component_count: u32,
273 };
274
275 pub const ArrayType = struct {
276 /// Child type of this array.
277 element_type: Ref,
278 /// Reference to a constant.
279 length: Ref,
280 /// Type has the 'ArrayStride' decoration.
281 /// If zero, no stride is present.
282 stride: u32 = 0,
283 };
284
285 pub const FunctionType = struct {
286 return_type: Ref,
287 parameters: []const Ref,
288 };
289
290 pub const PointerType = struct {
291 storage_class: StorageClass,
292 child_type: Ref,
293 /// Ref to a .fwd_ptr_type.
294 fwd: Ref,
295 // TODO: Decorations:
296 // - Alignment
297 // - ArrayStride
298 // - MaxByteOffset
299 };
300
301 pub const ForwardPointerType = struct {
302 zig_child_type: InternPool.Index,
303 storage_class: StorageClass,
304 };
305
306 pub const StructType = struct {
307 // TODO: Decorations.
308 /// The name of the structure. Can be `.none`.
309 name: String = .none,
310 /// The type of each member.
311 member_types: []const Ref,
312 /// Name for each member. May be omitted.
313 member_names: ?[]const String = null,
314
315 fn memberNames(self: @This()) []const String {
316 return if (self.member_names) |member_names| member_names else &.{};
317 }
318 };
319
320 pub const OpaqueType = struct {
321 name: String = .none,
322 };
323
324 pub const Int = struct {
325 /// The type: any bitness integer.
326 ty: Ref,
327 /// The actual value. Only uint64 and int64 types
328 /// are available here: Smaller types should use these
329 /// fields.
330 value: Value,
331
332 pub const Value = union(enum) {
333 uint64: u64,
334 int64: i64,
335 };
336
337 /// Turns this value into the corresponding 32-bit literal, 2s complement signed.
338 fn toBits32(self: Int) u32 {
339 return switch (self.value) {
340 .uint64 => |val| @intCast(val),
341 .int64 => |val| if (val < 0) @bitCast(@as(i32, @intCast(val))) else @intCast(val),
342 };
343 }
344
345 fn toBits64(self: Int) u64 {
346 return switch (self.value) {
347 .uint64 => |val| val,
348 .int64 => |val| @bitCast(val),
349 };
350 }
351
352 fn to(self: Int, comptime T: type) T {
353 return switch (self.value) {
354 inline else => |val| @intCast(val),
355 };
356 }
357 };
358
359 /// Represents a numberic value of some type.
360 pub const Float = struct {
361 /// The type: 16, 32, or 64-bit float.
362 ty: Ref,
363 /// The actual value.
364 value: Value,
365
366 pub const Value = union(enum) {
367 float16: f16,
368 float32: f32,
369 float64: f64,
370 };
371 };
372
373 pub const Undef = struct {
374 ty: Ref,
375 };
376
377 pub const Null = struct {
378 ty: Ref,
379 };
380
381 pub const Bool = struct {
382 ty: Ref,
383 value: bool,
384 };
385
386 fn hash(self: Key) u32 {
387 var hasher = std.hash.Wyhash.init(0);
388 switch (self) {
389 .float => |float| {
390 std.hash.autoHash(&hasher, float.ty);
391 switch (float.value) {
392 .float16 => |value| std.hash.autoHash(&hasher, @as(u16, @bitCast(value))),
393 .float32 => |value| std.hash.autoHash(&hasher, @as(u32, @bitCast(value))),
394 .float64 => |value| std.hash.autoHash(&hasher, @as(u64, @bitCast(value))),
395 }
396 },
397 .function_type => |func| {
398 std.hash.autoHash(&hasher, func.return_type);
399 for (func.parameters) |param_type| {
400 std.hash.autoHash(&hasher, param_type);
401 }
402 },
403 .struct_type => |struct_type| {
404 std.hash.autoHash(&hasher, struct_type.name);
405 for (struct_type.member_types) |member_type| {
406 std.hash.autoHash(&hasher, member_type);
407 }
408 for (struct_type.memberNames()) |member_name| {
409 std.hash.autoHash(&hasher, member_name);
410 }
411 },
412 inline else => |key| std.hash.autoHash(&hasher, key),
413 }
414 return @truncate(hasher.final());
415 }
416
417 fn eql(a: Key, b: Key) bool {
418 const KeyTag = @typeInfo(Key).Union.tag_type.?;
419 const a_tag: KeyTag = a;
420 const b_tag: KeyTag = b;
421 if (a_tag != b_tag) {
422 return false;
423 }
424 return switch (a) {
425 .function_type => |a_func| {
426 const b_func = b.function_type;
427 return a_func.return_type == b_func.return_type and
428 std.mem.eql(Ref, a_func.parameters, b_func.parameters);
429 },
430 .struct_type => |a_struct| {
431 const b_struct = b.struct_type;
432 return a_struct.name == b_struct.name and
433 std.mem.eql(Ref, a_struct.member_types, b_struct.member_types) and
434 std.mem.eql(String, a_struct.memberNames(), b_struct.memberNames());
435 },
436 // TODO: Unroll?
437 else => std.meta.eql(a, b),
438 };
439 }
440
441 pub const Adapter = struct {
442 self: *const Self,
443
444 pub fn eql(ctx: @This(), a: Key, b_void: void, b_index: usize) bool {
445 _ = b_void;
446 return ctx.self.lookup(@enumFromInt(b_index)).eql(a);
447 }
448
449 pub fn hash(ctx: @This(), a: Key) u32 {
450 _ = ctx;
451 return a.hash();
452 }
453 };
454
455 fn toSimpleType(self: Key) Tag.SimpleType {
456 return switch (self) {
457 .void_type => .void,
458 .bool_type => .bool,
459 else => unreachable,
460 };
461 }
462
463 pub fn isNumericalType(self: Key) bool {
464 return switch (self) {
465 .int_type, .float_type => true,
466 else => false,
467 };
468 }
469};
470
471pub fn deinit(self: *Self, spv: *const Module) void {
472 self.map.deinit(spv.gpa);
473 self.items.deinit(spv.gpa);
474 self.extra.deinit(spv.gpa);
475 self.string_bytes.deinit(spv.gpa);
476 self.strings.deinit(spv.gpa);
477 self.recursive_ptrs.deinit(spv.gpa);
478}
479
480/// Actually materialize the database into spir-v instructions.
481/// This function returns a spir-v section of (only) constant and type instructions.
482/// Additionally, decorations, debug names, etc, are all directly emitted into the
483/// `spv` module. The section is allocated with `spv.gpa`.
484pub fn materialize(self: *const Self, spv: *Module) !Section {
485 var section = Section{};
486 errdefer section.deinit(spv.gpa);
487 for (self.items.items(.result_id), 0..) |result_id, index| {
488 try self.emit(spv, result_id, @enumFromInt(index), &section);
489 }
490 return section;
491}
492
493fn emit(
494 self: *const Self,
495 spv: *Module,
496 result_id: IdResult,
497 ref: Ref,
498 section: *Section,
499) !void {
500 const key = self.lookup(ref);
501 const Lit = spec.LiteralContextDependentNumber;
502 switch (key) {
503 .void_type => {
504 try section.emit(spv.gpa, .OpTypeVoid, .{ .id_result = result_id });
505 try spv.debugName(result_id, "void");
506 },
507 .bool_type => {
508 try section.emit(spv.gpa, .OpTypeBool, .{ .id_result = result_id });
509 try spv.debugName(result_id, "bool");
510 },
511 .int_type => |int| {
512 try section.emit(spv.gpa, .OpTypeInt, .{
513 .id_result = result_id,
514 .width = int.bits,
515 .signedness = switch (int.signedness) {
516 .unsigned => @as(spec.Word, 0),
517 .signed => 1,
518 },
519 });
520 const ui: []const u8 = switch (int.signedness) {
521 .unsigned => "u",
522 .signed => "i",
523 };
524 try spv.debugNameFmt(result_id, "{s}{}", .{ ui, int.bits });
525 },
526 .float_type => |float| {
527 try section.emit(spv.gpa, .OpTypeFloat, .{
528 .id_result = result_id,
529 .width = float.bits,
530 });
531 try spv.debugNameFmt(result_id, "f{}", .{float.bits});
532 },
533 .vector_type => |vector| {
534 try section.emit(spv.gpa, .OpTypeVector, .{
535 .id_result = result_id,
536 .component_type = self.resultId(vector.component_type),
537 .component_count = vector.component_count,
538 });
539 },
540 .array_type => |array| {
541 try section.emit(spv.gpa, .OpTypeArray, .{
542 .id_result = result_id,
543 .element_type = self.resultId(array.element_type),
544 .length = self.resultId(array.length),
545 });
546 if (array.stride != 0) {
547 try spv.decorate(result_id, .{ .ArrayStride = .{ .array_stride = array.stride } });
548 }
549 },
550 .function_type => |function| {
551 try section.emitRaw(spv.gpa, .OpTypeFunction, 2 + function.parameters.len);
552 section.writeOperand(IdResult, result_id);
553 section.writeOperand(IdResult, self.resultId(function.return_type));
554 for (function.parameters) |param_type| {
555 section.writeOperand(IdResult, self.resultId(param_type));
556 }
557 },
558 .ptr_type => |ptr| {
559 try section.emit(spv.gpa, .OpTypePointer, .{
560 .id_result = result_id,
561 .storage_class = ptr.storage_class,
562 .type = self.resultId(ptr.child_type),
563 });
564 // TODO: Decorations?
565 },
566 .fwd_ptr_type => |fwd| {
567 // Only emit the OpTypeForwardPointer if its actually required.
568 if (self.recursive_ptrs.contains(ref)) {
569 try section.emit(spv.gpa, .OpTypeForwardPointer, .{
570 .pointer_type = result_id,
571 .storage_class = fwd.storage_class,
572 });
573 }
574 },
575 .struct_type => |struct_type| {
576 try section.emitRaw(spv.gpa, .OpTypeStruct, 1 + struct_type.member_types.len);
577 section.writeOperand(IdResult, result_id);
578 for (struct_type.member_types) |member_type| {
579 section.writeOperand(IdResult, self.resultId(member_type));
580 }
581 if (self.getString(struct_type.name)) |name| {
582 try spv.debugName(result_id, name);
583 }
584 for (struct_type.memberNames(), 0..) |member_name, i| {
585 if (self.getString(member_name)) |name| {
586 try spv.memberDebugName(result_id, @intCast(i), name);
587 }
588 }
589 // TODO: Decorations?
590 },
591 .opaque_type => |opaque_type| {
592 const name = if (self.getString(opaque_type.name)) |name| name else "";
593 try section.emit(spv.gpa, .OpTypeOpaque, .{
594 .id_result = result_id,
595 .literal_string = name,
596 });
597 },
598 .int => |int| {
599 const int_type = self.lookup(int.ty).int_type;
600 const ty_id = self.resultId(int.ty);
601 const lit: Lit = switch (int_type.bits) {
602 1...32 => .{ .uint32 = int.toBits32() },
603 33...64 => .{ .uint64 = int.toBits64() },
604 else => unreachable,
605 };
606
607 try section.emit(spv.gpa, .OpConstant, .{
608 .id_result_type = ty_id,
609 .id_result = result_id,
610 .value = lit,
611 });
612 },
613 .float => |float| {
614 const ty_id = self.resultId(float.ty);
615 const lit: Lit = switch (float.value) {
616 .float16 => |value| .{ .uint32 = @as(u16, @bitCast(value)) },
617 .float32 => |value| .{ .float32 = value },
618 .float64 => |value| .{ .float64 = value },
619 };
620 try section.emit(spv.gpa, .OpConstant, .{
621 .id_result_type = ty_id,
622 .id_result = result_id,
623 .value = lit,
624 });
625 },
626 .undef => |undef| {
627 try section.emit(spv.gpa, .OpUndef, .{
628 .id_result_type = self.resultId(undef.ty),
629 .id_result = result_id,
630 });
631 },
632 .null => |null_info| {
633 try section.emit(spv.gpa, .OpConstantNull, .{
634 .id_result_type = self.resultId(null_info.ty),
635 .id_result = result_id,
636 });
637 },
638 .bool => |bool_info| switch (bool_info.value) {
639 true => {
640 try section.emit(spv.gpa, .OpConstantTrue, .{
641 .id_result_type = self.resultId(bool_info.ty),
642 .id_result = result_id,
643 });
644 },
645 false => {
646 try section.emit(spv.gpa, .OpConstantFalse, .{
647 .id_result_type = self.resultId(bool_info.ty),
648 .id_result = result_id,
649 });
650 },
651 },
652 }
653}
654
655/// Add a key to this cache. Returns a reference to the key that
656/// was added. The corresponding result-id can be queried using
657/// self.resultId with the result.
658pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {
659 const adapter: Key.Adapter = .{ .self = self };
660 const entry = try self.map.getOrPutAdapted(spv.gpa, key, adapter);
661 if (entry.found_existing) {
662 return @enumFromInt(entry.index);
663 }
664 const item: Item = switch (key) {
665 inline .void_type, .bool_type => .{
666 .tag = .type_simple,
667 .result_id = spv.allocId(),
668 .data = @intFromEnum(key.toSimpleType()),
669 },
670 .int_type => |int| blk: {
671 const t: Tag = switch (int.signedness) {
672 .signed => .type_int_signed,
673 .unsigned => .type_int_unsigned,
674 };
675 break :blk .{
676 .tag = t,
677 .result_id = spv.allocId(),
678 .data = int.bits,
679 };
680 },
681 .float_type => |float| .{
682 .tag = .type_float,
683 .result_id = spv.allocId(),
684 .data = float.bits,
685 },
686 .vector_type => |vector| .{
687 .tag = .type_vector,
688 .result_id = spv.allocId(),
689 .data = try self.addExtra(spv, vector),
690 },
691 .array_type => |array| .{
692 .tag = .type_array,
693 .result_id = spv.allocId(),
694 .data = try self.addExtra(spv, array),
695 },
696 .function_type => |function| blk: {
697 const extra = try self.addExtra(spv, Tag.FunctionType{
698 .param_len = @intCast(function.parameters.len),
699 .return_type = function.return_type,
700 });
701 try self.extra.appendSlice(spv.gpa, @ptrCast(function.parameters));
702 break :blk .{
703 .tag = .type_function,
704 .result_id = spv.allocId(),
705 .data = extra,
706 };
707 },
708 // .ptr_type => |ptr| switch (ptr.storage_class) {
709 // .Generic => Item{
710 // .tag = .type_ptr_generic,
711 // .result_id = spv.allocId(),
712 // .data = @intFromEnum(ptr.child_type),
713 // },
714 // .CrossWorkgroup => Item{
715 // .tag = .type_ptr_crosswgp,
716 // .result_id = spv.allocId(),
717 // .data = @intFromEnum(ptr.child_type),
718 // },
719 // .Function => Item{
720 // .tag = .type_ptr_function,
721 // .result_id = spv.allocId(),
722 // .data = @intFromEnum(ptr.child_type),
723 // },
724 // else => |storage_class| Item{
725 // .tag = .type_ptr_simple,
726 // .result_id = spv.allocId(),
727 // .data = try self.addExtra(spv, Tag.SimplePointerType{
728 // .storage_class = storage_class,
729 // .child_type = ptr.child_type,
730 // }),
731 // },
732 // },
733 .ptr_type => |ptr| Item{
734 .tag = .type_ptr_simple,
735 // For this variant we need to steal the ID of the forward-declaration, instead
736 // of allocating one manually. This will make sure that we get a single result-id
737 // any possibly forward declared pointer type.
738 .result_id = self.resultId(ptr.fwd),
739 .data = try self.addExtra(spv, Tag.SimplePointerType{
740 .storage_class = ptr.storage_class,
741 .child_type = ptr.child_type,
742 .fwd = ptr.fwd,
743 }),
744 },
745 .fwd_ptr_type => |fwd| Item{
746 .tag = .type_fwd_ptr,
747 .result_id = spv.allocId(),
748 .data = try self.addExtra(spv, Tag.ForwardPointerType{
749 .zig_child_type = fwd.zig_child_type,
750 .storage_class = fwd.storage_class,
751 }),
752 },
753 .struct_type => |struct_type| blk: {
754 const extra = try self.addExtra(spv, Tag.SimpleStructType{
755 .name = struct_type.name,
756 .members_len = @intCast(struct_type.member_types.len),
757 });
758 try self.extra.appendSlice(spv.gpa, @ptrCast(struct_type.member_types));
759
760 if (struct_type.member_names) |member_names| {
761 try self.extra.appendSlice(spv.gpa, @ptrCast(member_names));
762 break :blk Item{
763 .tag = .type_struct_simple_with_member_names,
764 .result_id = spv.allocId(),
765 .data = extra,
766 };
767 } else {
768 break :blk Item{
769 .tag = .type_struct_simple,
770 .result_id = spv.allocId(),
771 .data = extra,
772 };
773 }
774 },
775 .opaque_type => |opaque_type| Item{
776 .tag = .type_opaque,
777 .result_id = spv.allocId(),
778 .data = @intFromEnum(opaque_type.name),
779 },
780 .int => |int| blk: {
781 const int_type = self.lookup(int.ty).int_type;
782 if (int_type.signedness == .unsigned and int_type.bits == 8) {
783 break :blk .{
784 .tag = .uint8,
785 .result_id = spv.allocId(),
786 .data = int.to(u8),
787 };
788 } else if (int_type.signedness == .unsigned and int_type.bits == 32) {
789 break :blk .{
790 .tag = .uint32,
791 .result_id = spv.allocId(),
792 .data = int.to(u32),
793 };
794 }
795
796 switch (int.value) {
797 inline else => |val| {
798 if (val >= 0 and val <= std.math.maxInt(u32)) {
799 break :blk .{
800 .tag = .uint_small,
801 .result_id = spv.allocId(),
802 .data = try self.addExtra(spv, Tag.UInt32{
803 .ty = int.ty,
804 .value = @intCast(val),
805 }),
806 };
807 } else if (val >= std.math.minInt(i32) and val <= std.math.maxInt(i32)) {
808 break :blk .{
809 .tag = .int_small,
810 .result_id = spv.allocId(),
811 .data = try self.addExtra(spv, Tag.Int32{
812 .ty = int.ty,
813 .value = @intCast(val),
814 }),
815 };
816 } else if (val < 0) {
817 break :blk .{
818 .tag = .int_large,
819 .result_id = spv.allocId(),
820 .data = try self.addExtra(spv, Tag.Int64.encode(int.ty, @intCast(val))),
821 };
822 } else {
823 break :blk .{
824 .tag = .uint_large,
825 .result_id = spv.allocId(),
826 .data = try self.addExtra(spv, Tag.UInt64.encode(int.ty, @intCast(val))),
827 };
828 }
829 },
830 }
831 },
832 .float => |float| switch (self.lookup(float.ty).float_type.bits) {
833 16 => .{
834 .tag = .float16,
835 .result_id = spv.allocId(),
836 .data = @as(u16, @bitCast(float.value.float16)),
837 },
838 32 => .{
839 .tag = .float32,
840 .result_id = spv.allocId(),
841 .data = @as(u32, @bitCast(float.value.float32)),
842 },
843 64 => .{
844 .tag = .float64,
845 .result_id = spv.allocId(),
846 .data = try self.addExtra(spv, Tag.Float64.encode(float.value.float64)),
847 },
848 else => unreachable,
849 },
850 .undef => |undef| .{
851 .tag = .undef,
852 .result_id = spv.allocId(),
853 .data = @intFromEnum(undef.ty),
854 },
855 .null => |null_info| .{
856 .tag = .null,
857 .result_id = spv.allocId(),
858 .data = @intFromEnum(null_info.ty),
859 },
860 .bool => |bool_info| .{
861 .tag = switch (bool_info.value) {
862 true => Tag.bool_true,
863 false => Tag.bool_false,
864 },
865 .result_id = spv.allocId(),
866 .data = @intFromEnum(bool_info.ty),
867 },
868 };
869 try self.items.append(spv.gpa, item);
870
871 return @enumFromInt(entry.index);
872}
873
874/// Turn a Ref back into a Key.
875/// The Key is valid until the next call to resolve().
876pub fn lookup(self: *const Self, ref: Ref) Key {
877 const item = self.items.get(@intFromEnum(ref));
878 const data = item.data;
879 return switch (item.tag) {
880 .type_simple => switch (@as(Tag.SimpleType, @enumFromInt(data))) {
881 .void => .void_type,
882 .bool => .bool_type,
883 },
884 .type_int_signed => .{ .int_type = .{
885 .signedness = .signed,
886 .bits = @intCast(data),
887 } },
888 .type_int_unsigned => .{ .int_type = .{
889 .signedness = .unsigned,
890 .bits = @intCast(data),
891 } },
892 .type_float => .{ .float_type = .{
893 .bits = @intCast(data),
894 } },
895 .type_vector => .{ .vector_type = self.extraData(Tag.VectorType, data) },
896 .type_array => .{ .array_type = self.extraData(Tag.ArrayType, data) },
897 .type_function => {
898 const payload = self.extraDataTrail(Tag.FunctionType, data);
899 return .{
900 .function_type = .{
901 .return_type = payload.data.return_type,
902 .parameters = @ptrCast(self.extra.items[payload.trail..][0..payload.data.param_len]),
903 },
904 };
905 },
906 .type_ptr_simple => {
907 const payload = self.extraData(Tag.SimplePointerType, data);
908 return .{
909 .ptr_type = .{
910 .storage_class = payload.storage_class,
911 .child_type = payload.child_type,
912 .fwd = payload.fwd,
913 },
914 };
915 },
916 .type_fwd_ptr => {
917 const payload = self.extraData(Tag.ForwardPointerType, data);
918 return .{
919 .fwd_ptr_type = .{
920 .zig_child_type = payload.zig_child_type,
921 .storage_class = payload.storage_class,
922 },
923 };
924 },
925 .type_struct_simple => {
926 const payload = self.extraDataTrail(Tag.SimpleStructType, data);
927 const member_types: []const Ref = @ptrCast(self.extra.items[payload.trail..][0..payload.data.members_len]);
928 return .{
929 .struct_type = .{
930 .name = payload.data.name,
931 .member_types = member_types,
932 .member_names = null,
933 },
934 };
935 },
936 .type_struct_simple_with_member_names => {
937 const payload = self.extraDataTrail(Tag.SimpleStructType, data);
938 const trailing = self.extra.items[payload.trail..];
939 const member_types: []const Ref = @ptrCast(trailing[0..payload.data.members_len]);
940 const member_names: []const String = @ptrCast(trailing[payload.data.members_len..][0..payload.data.members_len]);
941 return .{
942 .struct_type = .{
943 .name = payload.data.name,
944 .member_types = member_types,
945 .member_names = member_names,
946 },
947 };
948 },
949 .type_opaque => .{
950 .opaque_type = .{
951 .name = @enumFromInt(data),
952 },
953 },
954 .float16 => .{ .float = .{
955 .ty = self.get(.{ .float_type = .{ .bits = 16 } }),
956 .value = .{ .float16 = @bitCast(@as(u16, @intCast(data))) },
957 } },
958 .float32 => .{ .float = .{
959 .ty = self.get(.{ .float_type = .{ .bits = 32 } }),
960 .value = .{ .float32 = @bitCast(data) },
961 } },
962 .float64 => .{ .float = .{
963 .ty = self.get(.{ .float_type = .{ .bits = 64 } }),
964 .value = .{ .float64 = self.extraData(Tag.Float64, data).decode() },
965 } },
966 .uint8 => .{ .int = .{
967 .ty = self.get(.{ .int_type = .{ .signedness = .unsigned, .bits = 8 } }),
968 .value = .{ .uint64 = data },
969 } },
970 .uint32 => .{ .int = .{
971 .ty = self.get(.{ .int_type = .{ .signedness = .unsigned, .bits = 32 } }),
972 .value = .{ .uint64 = data },
973 } },
974 .int_small => {
975 const payload = self.extraData(Tag.Int32, data);
976 return .{ .int = .{
977 .ty = payload.ty,
978 .value = .{ .int64 = payload.value },
979 } };
980 },
981 .uint_small => {
982 const payload = self.extraData(Tag.UInt32, data);
983 return .{ .int = .{
984 .ty = payload.ty,
985 .value = .{ .uint64 = payload.value },
986 } };
987 },
988 .int_large => {
989 const payload = self.extraData(Tag.Int64, data);
990 return .{ .int = .{
991 .ty = payload.ty,
992 .value = .{ .int64 = payload.decode() },
993 } };
994 },
995 .uint_large => {
996 const payload = self.extraData(Tag.UInt64, data);
997 return .{ .int = .{
998 .ty = payload.ty,
999 .value = .{ .uint64 = payload.decode() },
1000 } };
1001 },
1002 .undef => .{ .undef = .{
1003 .ty = @enumFromInt(data),
1004 } },
1005 .null => .{ .null = .{
1006 .ty = @enumFromInt(data),
1007 } },
1008 .bool_true => .{ .bool = .{
1009 .ty = @enumFromInt(data),
1010 .value = true,
1011 } },
1012 .bool_false => .{ .bool = .{
1013 .ty = @enumFromInt(data),
1014 .value = false,
1015 } },
1016 };
1017}
1018
1019/// Look op the result-id that corresponds to a particular
1020/// ref.
1021pub fn resultId(self: Self, ref: Ref) IdResult {
1022 return self.items.items(.result_id)[@intFromEnum(ref)];
1023}
1024
1025/// Get the ref for a key that has already been added to the cache.
1026fn get(self: *const Self, key: Key) Ref {
1027 const adapter: Key.Adapter = .{ .self = self };
1028 const index = self.map.getIndexAdapted(key, adapter).?;
1029 return @enumFromInt(index);
1030}
1031
1032fn addExtra(self: *Self, spv: *Module, extra: anytype) !u32 {
1033 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
1034 try self.extra.ensureUnusedCapacity(spv.gpa, fields.len);
1035 return try self.addExtraAssumeCapacity(extra);
1036}
1037
1038fn addExtraAssumeCapacity(self: *Self, extra: anytype) !u32 {
1039 const payload_offset: u32 = @intCast(self.extra.items.len);
1040 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
1041 const field_val = @field(extra, field.name);
1042 const word: u32 = switch (field.type) {
1043 u32 => field_val,
1044 i32 => @bitCast(field_val),
1045 Ref => @intFromEnum(field_val),
1046 StorageClass => @intFromEnum(field_val),
1047 String => @intFromEnum(field_val),
1048 InternPool.Index => @intFromEnum(field_val),
1049 else => @compileError("Invalid type: " ++ @typeName(field.type)),
1050 };
1051 self.extra.appendAssumeCapacity(word);
1052 }
1053 return payload_offset;
1054}
1055
1056fn extraData(self: Self, comptime T: type, offset: u32) T {
1057 return self.extraDataTrail(T, offset).data;
1058}
1059
1060fn extraDataTrail(self: Self, comptime T: type, offset: u32) struct { data: T, trail: u32 } {
1061 var result: T = undefined;
1062 const fields = @typeInfo(T).Struct.fields;
1063 inline for (fields, 0..) |field, i| {
1064 const word = self.extra.items[offset + i];
1065 @field(result, field.name) = switch (field.type) {
1066 u32 => word,
1067 i32 => @bitCast(word),
1068 Ref => @enumFromInt(word),
1069 StorageClass => @enumFromInt(word),
1070 String => @enumFromInt(word),
1071 InternPool.Index => @enumFromInt(word),
1072 else => @compileError("Invalid type: " ++ @typeName(field.type)),
1073 };
1074 }
1075 return .{
1076 .data = result,
1077 .trail = offset + @as(u32, @intCast(fields.len)),
1078 };
1079}
1080
1081/// Represents a reference to some null-terminated string.
1082pub const String = enum(u32) {
1083 none = std.math.maxInt(u32),
1084 _,
1085
1086 pub const Adapter = struct {
1087 self: *const Self,
1088
1089 pub fn eql(ctx: @This(), a: []const u8, _: void, b_index: usize) bool {
1090 const offset = ctx.self.strings.values()[b_index];
1091 const b = std.mem.sliceTo(ctx.self.string_bytes.items[offset..], 0);
1092 return std.mem.eql(u8, a, b);
1093 }
1094
1095 pub fn hash(ctx: @This(), a: []const u8) u32 {
1096 _ = ctx;
1097 var hasher = std.hash.Wyhash.init(0);
1098 hasher.update(a);
1099 return @truncate(hasher.final());
1100 }
1101 };
1102};
1103
1104/// Add a string to the cache. Must not contain any 0 values.
1105pub fn addString(self: *Self, spv: *Module, str: []const u8) !String {
1106 assert(std.mem.indexOfScalar(u8, str, 0) == null);
1107 const adapter = String.Adapter{ .self = self };
1108 const entry = try self.strings.getOrPutAdapted(spv.gpa, str, adapter);
1109 if (!entry.found_existing) {
1110 const offset = self.string_bytes.items.len;
1111 try self.string_bytes.ensureUnusedCapacity(spv.gpa, 1 + str.len);
1112 self.string_bytes.appendSliceAssumeCapacity(str);
1113 self.string_bytes.appendAssumeCapacity(0);
1114 entry.value_ptr.* = @intCast(offset);
1115 }
1116
1117 return @enumFromInt(entry.index);
1118}
1119
1120pub fn getString(self: *const Self, ref: String) ?[]const u8 {
1121 return switch (ref) {
1122 .none => null,
1123 else => std.mem.sliceTo(self.string_bytes.items[self.strings.values()[@intFromEnum(ref)]..], 0),
1124 };
1125}
src/codegen/spirv/Module.zig+146-102
...@@ -20,11 +20,6 @@ const IdResultType = spec.IdResultType;...@@ -20,11 +20,6 @@ const IdResultType = spec.IdResultType;
2020
21const Section = @import("Section.zig");21const Section = @import("Section.zig");
2222
23const Cache = @import("Cache.zig");
24pub const CacheKey = Cache.Key;
25pub const CacheRef = Cache.Ref;
26pub const CacheString = Cache.String;
27
28/// This structure represents a function that isc in-progress of being emitted.23/// This structure represents a function that isc in-progress of being emitted.
29/// Commonly, the contents of this structure will be merged with the appropriate24/// Commonly, the contents of this structure will be merged with the appropriate
30/// sections of the module and re-used. Note that the SPIR-V module system makes25/// sections of the module and re-used. Note that the SPIR-V module system makes
...@@ -98,7 +93,7 @@ pub const EntryPoint = struct {...@@ -98,7 +93,7 @@ pub const EntryPoint = struct {
98 /// The declaration that should be exported.93 /// The declaration that should be exported.
99 decl_index: Decl.Index,94 decl_index: Decl.Index,
100 /// The name of the kernel to be exported.95 /// The name of the kernel to be exported.
101 name: CacheString,96 name: []const u8,
102 /// Calling Convention97 /// Calling Convention
103 execution_model: spec.ExecutionModel,98 execution_model: spec.ExecutionModel,
104};99};
...@@ -106,6 +101,9 @@ pub const EntryPoint = struct {...@@ -106,6 +101,9 @@ pub const EntryPoint = struct {
106/// A general-purpose allocator which may be used to allocate resources for this module101/// A general-purpose allocator which may be used to allocate resources for this module
107gpa: Allocator,102gpa: Allocator,
108103
104/// Arena for things that need to live for the length of this program.
105arena: std.heap.ArenaAllocator,
106
109/// Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module".107/// Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module".
110sections: struct {108sections: struct {
111 /// Capability instructions109 /// Capability instructions
...@@ -143,14 +141,21 @@ sections: struct {...@@ -143,14 +141,21 @@ sections: struct {
143/// SPIR-V instructions return result-ids. This variable holds the module-wide counter for these.141/// SPIR-V instructions return result-ids. This variable holds the module-wide counter for these.
144next_result_id: Word,142next_result_id: Word,
145143
146/// Cache for results of OpString instructions for module file names fed to OpSource.144/// Cache for results of OpString instructions.
147/// Since OpString is pretty much only used for those, we don't need to keep track of all strings,145strings: std.StringArrayHashMapUnmanaged(IdRef) = .{},
148/// just the ones for OpLine. Note that OpLine needs the result of OpString, and not that of OpSource.146
149source_file_names: std.AutoArrayHashMapUnmanaged(CacheString, IdRef) = .{},147/// Some types shouldn't be emitted more than one time, but cannot be caught by
150148/// the `intern_map` during codegen. Sometimes, IDs are compared to check if
151/// SPIR-V type- and constant cache. This structure is used to store information about these in a more149/// types are the same, so we can't delay until the dedup pass. Therefore,
152/// efficient manner.150/// this is an ad-hoc structure to cache types where required.
153cache: Cache = .{},151/// According to the SPIR-V specification, section 2.8, this includes all non-aggregate
152/// non-pointer types.
153cache: struct {
154 bool_type: ?IdRef = null,
155 void_type: ?IdRef = null,
156 int_types: std.AutoHashMapUnmanaged(std.builtin.Type.Int, IdRef) = .{},
157 float_types: std.AutoHashMapUnmanaged(std.builtin.Type.Float, IdRef) = .{},
158} = .{},
154159
155/// Set of Decls, referred to by Decl.Index.160/// Set of Decls, referred to by Decl.Index.
156decls: std.ArrayListUnmanaged(Decl) = .{},161decls: std.ArrayListUnmanaged(Decl) = .{},
...@@ -168,6 +173,7 @@ extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, IdRef) =...@@ -168,6 +173,7 @@ extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, IdRef) =
168pub fn init(gpa: Allocator) Module {173pub fn init(gpa: Allocator) Module {
169 return .{174 return .{
170 .gpa = gpa,175 .gpa = gpa,
176 .arena = std.heap.ArenaAllocator.init(gpa),
171 .next_result_id = 1, // 0 is an invalid SPIR-V result id, so start counting at 1.177 .next_result_id = 1, // 0 is an invalid SPIR-V result id, so start counting at 1.
172 };178 };
173}179}
...@@ -184,8 +190,10 @@ pub fn deinit(self: *Module) void {...@@ -184,8 +190,10 @@ pub fn deinit(self: *Module) void {
184 self.sections.types_globals_constants.deinit(self.gpa);190 self.sections.types_globals_constants.deinit(self.gpa);
185 self.sections.functions.deinit(self.gpa);191 self.sections.functions.deinit(self.gpa);
186192
187 self.source_file_names.deinit(self.gpa);193 self.strings.deinit(self.gpa);
188 self.cache.deinit(self);194
195 self.cache.int_types.deinit(self.gpa);
196 self.cache.float_types.deinit(self.gpa);
189197
190 self.decls.deinit(self.gpa);198 self.decls.deinit(self.gpa);
191 self.decl_deps.deinit(self.gpa);199 self.decl_deps.deinit(self.gpa);
...@@ -193,38 +201,35 @@ pub fn deinit(self: *Module) void {...@@ -193,38 +201,35 @@ pub fn deinit(self: *Module) void {
193 self.entry_points.deinit(self.gpa);201 self.entry_points.deinit(self.gpa);
194202
195 self.extended_instruction_set.deinit(self.gpa);203 self.extended_instruction_set.deinit(self.gpa);
204 self.arena.deinit();
196205
197 self.* = undefined;206 self.* = undefined;
198}207}
199208
200pub fn allocId(self: *Module) spec.IdResult {209pub const IdRange = struct {
201 defer self.next_result_id += 1;210 base: u32,
202 return @enumFromInt(self.next_result_id);211 len: u32,
203}
204
205pub fn allocIds(self: *Module, n: u32) spec.IdResult {
206 defer self.next_result_id += n;
207 return @enumFromInt(self.next_result_id);
208}
209
210pub fn idBound(self: Module) Word {
211 return self.next_result_id;
212}
213212
214pub fn resolve(self: *Module, key: CacheKey) !CacheRef {213 pub fn at(range: IdRange, i: usize) IdResult {
215 return self.cache.resolve(self, key);214 assert(i < range.len);
216}215 return @enumFromInt(range.base + i);
216 }
217};
217218
218pub fn resultId(self: *const Module, ref: CacheRef) IdResult {219pub fn allocIds(self: *Module, n: u32) IdRange {
219 return self.cache.resultId(ref);220 defer self.next_result_id += n;
221 return .{
222 .base = self.next_result_id,
223 .len = n,
224 };
220}225}
221226
222pub fn resolveId(self: *Module, key: CacheKey) !IdResult {227pub fn allocId(self: *Module) IdResult {
223 return self.resultId(try self.resolve(key));228 return self.allocIds(1).at(0);
224}229}
225230
226pub fn resolveString(self: *Module, str: []const u8) !CacheString {231pub fn idBound(self: Module) Word {
227 return try self.cache.addString(self, str);232 return self.next_result_id;
228}233}
229234
230fn addEntryPointDeps(235fn addEntryPointDeps(
...@@ -271,7 +276,7 @@ fn entryPoints(self: *Module) !Section {...@@ -271,7 +276,7 @@ fn entryPoints(self: *Module) !Section {
271 try entry_points.emit(self.gpa, .OpEntryPoint, .{276 try entry_points.emit(self.gpa, .OpEntryPoint, .{
272 .execution_model = entry_point.execution_model,277 .execution_model = entry_point.execution_model,
273 .entry_point = entry_point_id,278 .entry_point = entry_point_id,
274 .name = self.cache.getString(entry_point.name).?,279 .name = entry_point.name,
275 .interface = interface.items,280 .interface = interface.items,
276 });281 });
277 }282 }
...@@ -286,9 +291,6 @@ pub fn finalize(self: *Module, a: Allocator, target: std.Target) ![]Word {...@@ -286,9 +291,6 @@ pub fn finalize(self: *Module, a: Allocator, target: std.Target) ![]Word {
286 var entry_points = try self.entryPoints();291 var entry_points = try self.entryPoints();
287 defer entry_points.deinit(self.gpa);292 defer entry_points.deinit(self.gpa);
288293
289 var types_constants = try self.cache.materialize(self);
290 defer types_constants.deinit(self.gpa);
291
292 const header = [_]Word{294 const header = [_]Word{
293 spec.magic_number,295 spec.magic_number,
294 // TODO: From cpu features296 // TODO: From cpu features
...@@ -331,7 +333,6 @@ pub fn finalize(self: *Module, a: Allocator, target: std.Target) ![]Word {...@@ -331,7 +333,6 @@ pub fn finalize(self: *Module, a: Allocator, target: std.Target) ![]Word {
331 self.sections.debug_strings.toWords(),333 self.sections.debug_strings.toWords(),
332 self.sections.debug_names.toWords(),334 self.sections.debug_names.toWords(),
333 self.sections.annotations.toWords(),335 self.sections.annotations.toWords(),
334 types_constants.toWords(),
335 self.sections.types_globals_constants.toWords(),336 self.sections.types_globals_constants.toWords(),
336 self.sections.functions.toWords(),337 self.sections.functions.toWords(),
337 };338 };
...@@ -376,83 +377,126 @@ pub fn importInstructionSet(self: *Module, set: spec.InstructionSet) !IdRef {...@@ -376,83 +377,126 @@ pub fn importInstructionSet(self: *Module, set: spec.InstructionSet) !IdRef {
376 return result_id;377 return result_id;
377}378}
378379
379/// Fetch the result-id of an OpString instruction that encodes the path of the source380/// Fetch the result-id of an instruction corresponding to a string.
380/// file of the decl. This function may also emit an OpSource with source-level information regarding381pub fn resolveString(self: *Module, string: []const u8) !IdRef {
381/// the decl.382 if (self.strings.get(string)) |id| {
382pub fn resolveSourceFileName(self: *Module, path: []const u8) !IdRef {383 return id;
383 const path_ref = try self.resolveString(path);
384 const result = try self.source_file_names.getOrPut(self.gpa, path_ref);
385 if (!result.found_existing) {
386 const file_result_id = self.allocId();
387 result.value_ptr.* = file_result_id;
388 try self.sections.debug_strings.emit(self.gpa, .OpString, .{
389 .id_result = file_result_id,
390 .string = path,
391 });
392 }384 }
393385
394 return result.value_ptr.*;386 const id = self.allocId();
395}387 try self.strings.put(self.gpa, try self.arena.allocator().dupe(u8, string), id);
388
389 try self.sections.debug_strings.emit(self.gpa, .OpString, .{
390 .id_result = id,
391 .string = string,
392 });
396393
397pub fn intType(self: *Module, signedness: std.builtin.Signedness, bits: u16) !CacheRef {394 return id;
398 return try self.resolve(.{ .int_type = .{
399 .signedness = signedness,
400 .bits = bits,
401 } });
402}395}
403396
404pub fn vectorType(self: *Module, len: u32, elem_ty_ref: CacheRef) !CacheRef {397pub fn structType(self: *Module, types: []const IdRef, maybe_names: ?[]const []const u8) !IdRef {
405 return try self.resolve(.{ .vector_type = .{398 const result_id = self.allocId();
406 .component_type = elem_ty_ref,399
407 .component_count = len,400 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeStruct, .{
408 } });401 .id_result = result_id,
402 .id_ref = types,
403 });
404
405 if (maybe_names) |names| {
406 assert(names.len == types.len);
407 for (names, 0..) |name, i| {
408 try self.memberDebugName(result_id, @intCast(i), name);
409 }
410 }
411
412 return result_id;
409}413}
410414
411pub fn arrayType(self: *Module, len: u32, elem_ty_ref: CacheRef) !CacheRef {415pub fn boolType(self: *Module) !IdRef {
412 const len_ty_ref = try self.resolve(.{ .int_type = .{416 if (self.cache.bool_type) |id| return id;
413 .signedness = .unsigned,417
414 .bits = 32,418 const result_id = self.allocId();
415 } });419 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeBool, .{
416 const len_ref = try self.resolve(.{ .int = .{420 .id_result = result_id,
417 .ty = len_ty_ref,421 });
418 .value = .{ .uint64 = len },422 self.cache.bool_type = result_id;
419 } });423 return result_id;
420 return try self.resolve(.{ .array_type = .{
421 .element_type = elem_ty_ref,
422 .length = len_ref,
423 } });
424}424}
425425
426pub fn constInt(self: *Module, ty_ref: CacheRef, value: anytype) !IdRef {426pub fn voidType(self: *Module) !IdRef {
427 const ty = self.cache.lookup(ty_ref).int_type;427 if (self.cache.void_type) |id| return id;
428 const Value = Cache.Key.Int.Value;428
429 return try self.resolveId(.{ .int = .{429 const result_id = self.allocId();
430 .ty = ty_ref,430 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeVoid, .{
431 .value = switch (ty.signedness) {431 .id_result = result_id,
432 .signed => Value{ .int64 = @intCast(value) },432 });
433 .unsigned => Value{ .uint64 = @intCast(value) },433 self.cache.void_type = result_id;
434 },434 try self.debugName(result_id, "void");
435 } });435 return result_id;
436}436}
437437
438pub fn constUndef(self: *Module, ty_ref: CacheRef) !IdRef {438pub fn intType(self: *Module, signedness: std.builtin.Signedness, bits: u16) !IdRef {
439 return try self.resolveId(.{ .undef = .{ .ty = ty_ref } });439 assert(bits > 0);
440 const entry = try self.cache.int_types.getOrPut(self.gpa, .{ .signedness = signedness, .bits = bits });
441 if (!entry.found_existing) {
442 const result_id = self.allocId();
443 entry.value_ptr.* = result_id;
444 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeInt, .{
445 .id_result = result_id,
446 .width = bits,
447 .signedness = switch (signedness) {
448 .signed => 1,
449 .unsigned => 0,
450 },
451 });
452
453 switch (signedness) {
454 .signed => try self.debugNameFmt(result_id, "i{}", .{bits}),
455 .unsigned => try self.debugNameFmt(result_id, "u{}", .{bits}),
456 }
457 }
458 return entry.value_ptr.*;
459}
460
461pub fn floatType(self: *Module, bits: u16) !IdRef {
462 assert(bits > 0);
463 const entry = try self.cache.float_types.getOrPut(self.gpa, .{ .bits = bits });
464 if (!entry.found_existing) {
465 const result_id = self.allocId();
466 entry.value_ptr.* = result_id;
467 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeFloat, .{
468 .id_result = result_id,
469 .width = bits,
470 });
471 try self.debugNameFmt(result_id, "f{}", .{bits});
472 }
473 return entry.value_ptr.*;
440}474}
441475
442pub fn constNull(self: *Module, ty_ref: CacheRef) !IdRef {476pub fn vectorType(self: *Module, len: u32, child_id: IdRef) !IdRef {
443 return try self.resolveId(.{ .null = .{ .ty = ty_ref } });477 const result_id = self.allocId();
478 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeVector, .{
479 .id_result = result_id,
480 .component_type = child_id,
481 .component_count = len,
482 });
483 return result_id;
444}484}
445485
446pub fn constBool(self: *Module, ty_ref: CacheRef, value: bool) !IdRef {486pub fn constUndef(self: *Module, ty_id: IdRef) !IdRef {
447 return try self.resolveId(.{ .bool = .{ .ty = ty_ref, .value = value } });487 const result_id = self.allocId();
488 try self.sections.types_globals_constants.emit(self.gpa, .OpUndef, .{
489 .id_result_type = ty_id,
490 .id_result = result_id,
491 });
492 return result_id;
448}493}
449494
450pub fn constComposite(self: *Module, ty_ref: CacheRef, members: []const IdRef) !IdRef {495pub fn constNull(self: *Module, ty_id: IdRef) !IdRef {
451 const result_id = self.allocId();496 const result_id = self.allocId();
452 try self.sections.types_globals_constants.emit(self.gpa, .OpSpecConstantComposite, .{497 try self.sections.types_globals_constants.emit(self.gpa, .OpConstantNull, .{
453 .id_result_type = self.resultId(ty_ref),498 .id_result_type = ty_id,
454 .id_result = result_id,499 .id_result = result_id,
455 .constituents = members,
456 });500 });
457 return result_id;501 return result_id;
458}502}
...@@ -520,7 +564,7 @@ pub fn declareEntryPoint(...@@ -520,7 +564,7 @@ pub fn declareEntryPoint(
520) !void {564) !void {
521 try self.entry_points.append(self.gpa, .{565 try self.entry_points.append(self.gpa, .{
522 .decl_index = decl_index,566 .decl_index = decl_index,
523 .name = try self.resolveString(name),567 .name = try self.arena.allocator().dupe(u8, name),
524 .execution_model = execution_model,568 .execution_model = execution_model,
525 });569 });
526}570}
src/link/SpirV.zig+5-5
...@@ -245,7 +245,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node...@@ -245,7 +245,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node
245 const module = try spv.finalize(arena, target);245 const module = try spv.finalize(arena, target);
246 errdefer arena.free(module);246 errdefer arena.free(module);
247247
248 const linked_module = self.linkModule(arena, module) catch |err| switch (err) {248 const linked_module = self.linkModule(arena, module, &sub_prog_node) catch |err| switch (err) {
249 error.OutOfMemory => return error.OutOfMemory,249 error.OutOfMemory => return error.OutOfMemory,
250 else => |other| {250 else => |other| {
251 log.err("error while linking: {s}\n", .{@errorName(other)});251 log.err("error while linking: {s}\n", .{@errorName(other)});
...@@ -256,7 +256,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node...@@ -256,7 +256,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node
256 try self.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module));256 try self.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module));
257}257}
258258
259fn linkModule(self: *SpirV, a: Allocator, module: []Word) ![]Word {259fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: *std.Progress.Node) ![]Word {
260 _ = self;260 _ = self;
261261
262 const lower_invocation_globals = @import("SpirV/lower_invocation_globals.zig");262 const lower_invocation_globals = @import("SpirV/lower_invocation_globals.zig");
...@@ -267,9 +267,9 @@ fn linkModule(self: *SpirV, a: Allocator, module: []Word) ![]Word {...@@ -267,9 +267,9 @@ fn linkModule(self: *SpirV, a: Allocator, module: []Word) ![]Word {
267 defer parser.deinit();267 defer parser.deinit();
268 var binary = try parser.parse(module);268 var binary = try parser.parse(module);
269269
270 try lower_invocation_globals.run(&parser, &binary);270 try lower_invocation_globals.run(&parser, &binary, progress);
271 try prune_unused.run(&parser, &binary);271 try prune_unused.run(&parser, &binary, progress);
272 try dedup.run(&parser, &binary);272 try dedup.run(&parser, &binary, progress);
273273
274 return binary.finalize(a);274 return binary.finalize(a);
275}275}
src/link/SpirV/BinaryModule.zig+2-1
...@@ -116,7 +116,8 @@ pub const Instruction = struct {...@@ -116,7 +116,8 @@ pub const Instruction = struct {
116 const instruction_len = self.words[self.offset] >> 16;116 const instruction_len = self.words[self.offset] >> 16;
117 defer self.offset += instruction_len;117 defer self.offset += instruction_len;
118 defer self.index += 1;118 defer self.index += 1;
119 assert(instruction_len != 0 and self.offset < self.words.len); // Verified in BinaryModule.parse.119 assert(instruction_len != 0);
120 assert(self.offset < self.words.len);
120121
121 return Instruction{122 return Instruction{
122 .opcode = @enumFromInt(self.words[self.offset] & 0xFFFF),123 .opcode = @enumFromInt(self.words[self.offset] & 0xFFFF),
src/link/SpirV/deduplicate.zig+72-8
...@@ -47,6 +47,10 @@ const ModuleInfo = struct {...@@ -47,6 +47,10 @@ const ModuleInfo = struct {
47 result_id_index: u16,47 result_id_index: u16,
48 /// The first decoration in `self.decorations`.48 /// The first decoration in `self.decorations`.
49 first_decoration: u32,49 first_decoration: u32,
50
51 fn operands(self: Entity, binary: *const BinaryModule) []const Word {
52 return binary.instructions[self.first_operand..][0..self.num_operands];
53 }
50 };54 };
5155
52 /// Maps result-id to Entity's56 /// Maps result-id to Entity's
...@@ -210,10 +214,41 @@ const EntityContext = struct {...@@ -210,10 +214,41 @@ const EntityContext = struct {
210214
211 const entity = self.info.entities.values()[index];215 const entity = self.info.entities.values()[index];
212216
217 // If the current pointer is recursive, don't immediately add it to the map. This is to ensure that
218 // if the current pointer is already recursive, it gets the same hash a pointer that points to the
219 // same child but has a different result-id.
213 if (entity.kind == .OpTypePointer) {220 if (entity.kind == .OpTypePointer) {
214 // This may be either a pointer that is forward-referenced in the future,221 // This may be either a pointer that is forward-referenced in the future,
215 // or a forward reference to a pointer.222 // or a forward reference to a pointer.
216 const entry = try self.ptr_map_a.getOrPut(self.a, id);223 // Note: We use the **struct** here instead of the pointer itself, to avoid an edge case like this:
224 //
225 // A - C*'
226 // \
227 // C - C*'
228 // /
229 // B - C*"
230 //
231 // In this case, hashing A goes like
232 // A -> C*' -> C -> C*' recursion
233 // And hashing B goes like
234 // B -> C*" -> C -> C*' -> C -> C*' recursion
235 // The are several calls to ptrType in codegen that may C*' and C*" to be generated as separate
236 // types. This is not a problem for C itself though - this can only be generated through resolveType()
237 // and so ensures equality by Zig's type system. Technically the above problem is still present, but it
238 // would only be present in a structure such as
239 //
240 // A - C*' - C'
241 // \
242 // C*" - C - C*
243 // /
244 // B
245 //
246 // where there is a duplicate definition of struct C. Resolving this requires a much more time consuming
247 // algorithm though, and because we don't expect any correctness issues with it, we leave that for now.
248
249 // TODO: Do we need to mind the storage class here? Its going to be recursive regardless, right?
250 const struct_id: ResultId = @enumFromInt(entity.operands(self.binary)[2]);
251 const entry = try self.ptr_map_a.getOrPut(self.a, struct_id);
217 if (entry.found_existing) {252 if (entry.found_existing) {
218 // Pointer already seen. Hash the index instead of recursing into its children.253 // Pointer already seen. Hash the index instead of recursing into its children.
219 std.hash.autoHash(hasher, entry.index);254 std.hash.autoHash(hasher, entry.index);
...@@ -228,12 +263,17 @@ const EntityContext = struct {...@@ -228,12 +263,17 @@ const EntityContext = struct {
228 for (decorations) |decoration| {263 for (decorations) |decoration| {
229 try self.hashEntity(hasher, decoration);264 try self.hashEntity(hasher, decoration);
230 }265 }
266
267 if (entity.kind == .OpTypePointer) {
268 const struct_id: ResultId = @enumFromInt(entity.operands(self.binary)[2]);
269 assert(self.ptr_map_a.swapRemove(struct_id));
270 }
231 }271 }
232272
233 fn hashEntity(self: *EntityContext, hasher: *std.hash.Wyhash, entity: ModuleInfo.Entity) !void {273 fn hashEntity(self: *EntityContext, hasher: *std.hash.Wyhash, entity: ModuleInfo.Entity) !void {
234 std.hash.autoHash(hasher, entity.kind);274 std.hash.autoHash(hasher, entity.kind);
235 // Process operands275 // Process operands
236 const operands = self.binary.instructions[entity.first_operand..][0..entity.num_operands];276 const operands = entity.operands(self.binary);
237 for (operands, 0..) |operand, i| {277 for (operands, 0..) |operand, i| {
238 if (i == entity.result_id_index) {278 if (i == entity.result_id_index) {
239 // Not relevant, skip...279 // Not relevant, skip...
...@@ -273,12 +313,19 @@ const EntityContext = struct {...@@ -273,12 +313,19 @@ const EntityContext = struct {
273 const entity_a = self.info.entities.values()[index_a];313 const entity_a = self.info.entities.values()[index_a];
274 const entity_b = self.info.entities.values()[index_b];314 const entity_b = self.info.entities.values()[index_b];
275315
316 if (entity_a.kind != entity_b.kind) {
317 return false;
318 }
319
276 if (entity_a.kind == .OpTypePointer) {320 if (entity_a.kind == .OpTypePointer) {
277 // May be a forward reference, or should be saved as a potential321 // May be a forward reference, or should be saved as a potential
278 // forward reference in the future. Whatever the case, it should322 // forward reference in the future. Whatever the case, it should
279 // be the same for both a and b.323 // be the same for both a and b.
280 const entry_a = try self.ptr_map_a.getOrPut(self.a, id_a);324 const struct_id_a: ResultId = @enumFromInt(entity_a.operands(self.binary)[2]);
281 const entry_b = try self.ptr_map_b.getOrPut(self.a, id_b);325 const struct_id_b: ResultId = @enumFromInt(entity_b.operands(self.binary)[2]);
326
327 const entry_a = try self.ptr_map_a.getOrPut(self.a, struct_id_a);
328 const entry_b = try self.ptr_map_b.getOrPut(self.a, struct_id_b);
282329
283 if (entry_a.found_existing != entry_b.found_existing) return false;330 if (entry_a.found_existing != entry_b.found_existing) return false;
284 if (entry_a.index != entry_b.index) return false;331 if (entry_a.index != entry_b.index) return false;
...@@ -306,6 +353,14 @@ const EntityContext = struct {...@@ -306,6 +353,14 @@ const EntityContext = struct {
306 }353 }
307 }354 }
308355
356 if (entity_a.kind == .OpTypePointer) {
357 const struct_id_a: ResultId = @enumFromInt(entity_a.operands(self.binary)[2]);
358 const struct_id_b: ResultId = @enumFromInt(entity_b.operands(self.binary)[2]);
359
360 assert(self.ptr_map_a.swapRemove(struct_id_a));
361 assert(self.ptr_map_b.swapRemove(struct_id_b));
362 }
363
309 return true;364 return true;
310 }365 }
311366
...@@ -316,8 +371,8 @@ const EntityContext = struct {...@@ -316,8 +371,8 @@ const EntityContext = struct {
316 return false;371 return false;
317 }372 }
318373
319 const operands_a = self.binary.instructions[entity_a.first_operand..][0..entity_a.num_operands];374 const operands_a = entity_a.operands(self.binary);
320 const operands_b = self.binary.instructions[entity_b.first_operand..][0..entity_b.num_operands];375 const operands_b = entity_b.operands(self.binary);
321376
322 // Note: returns false for operands that have explicit defaults in optional operands... oh well377 // Note: returns false for operands that have explicit defaults in optional operands... oh well
323 if (operands_a.len != operands_b.len) {378 if (operands_a.len != operands_b.len) {
...@@ -363,7 +418,11 @@ const EntityHashContext = struct {...@@ -363,7 +418,11 @@ const EntityHashContext = struct {
363 }418 }
364};419};
365420
366pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {421pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: *std.Progress.Node) !void {
422 var sub_node = progress.start("deduplicate", 0);
423 sub_node.activate();
424 defer sub_node.end();
425
367 var arena = std.heap.ArenaAllocator.init(parser.a);426 var arena = std.heap.ArenaAllocator.init(parser.a);
368 defer arena.deinit();427 defer arena.deinit();
369 const a = arena.allocator();428 const a = arena.allocator();
...@@ -376,6 +435,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {...@@ -376,6 +435,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {
376 .info = &info,435 .info = &info,
377 .binary = binary,436 .binary = binary,
378 };437 };
438
379 for (info.entities.keys()) |id| {439 for (info.entities.keys()) |id| {
380 _ = try ctx.hash(id);440 _ = try ctx.hash(id);
381 }441 }
...@@ -395,6 +455,8 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {...@@ -395,6 +455,8 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {
395 }455 }
396 }456 }
397457
458 sub_node.setEstimatedTotalItems(binary.instructions.len);
459
398 // Now process the module, and replace instructions where needed.460 // Now process the module, and replace instructions where needed.
399 var section = Section{};461 var section = Section{};
400 var it = binary.iterateInstructions();462 var it = binary.iterateInstructions();
...@@ -402,6 +464,8 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {...@@ -402,6 +464,8 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {
402 var new_operands = std.ArrayList(u32).init(a);464 var new_operands = std.ArrayList(u32).init(a);
403 var emitted_ptrs = std.AutoHashMap(ResultId, void).init(a);465 var emitted_ptrs = std.AutoHashMap(ResultId, void).init(a);
404 while (it.next()) |inst| {466 while (it.next()) |inst| {
467 defer sub_node.setCompletedItems(inst.offset);
468
405 // Result-id can only be the first or second operand469 // Result-id can only be the first or second operand
406 const inst_spec = parser.getInstSpec(inst.opcode).?;470 const inst_spec = parser.getInstSpec(inst.opcode).?;
407471
...@@ -454,7 +518,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {...@@ -454,7 +518,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {
454 if (entity.kind == .OpTypePointer and !emitted_ptrs.contains(id)) {518 if (entity.kind == .OpTypePointer and !emitted_ptrs.contains(id)) {
455 // Grab the pointer's storage class from its operands in the original519 // Grab the pointer's storage class from its operands in the original
456 // module.520 // module.
457 const storage_class: spec.StorageClass = @enumFromInt(binary.instructions[entity.first_operand + 1]);521 const storage_class: spec.StorageClass = @enumFromInt(entity.operands(binary)[1]);
458 try section.emit(a, .OpTypeForwardPointer, .{522 try section.emit(a, .OpTypeForwardPointer, .{
459 .pointer_type = id,523 .pointer_type = id,
460 .storage_class = storage_class,524 .storage_class = storage_class,
src/link/SpirV/lower_invocation_globals.zig+11-1
...@@ -682,7 +682,11 @@ const ModuleBuilder = struct {...@@ -682,7 +682,11 @@ const ModuleBuilder = struct {
682 }682 }
683};683};
684684
685pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {685pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: *std.Progress.Node) !void {
686 var sub_node = progress.start("Lower invocation globals", 6);
687 sub_node.activate();
688 defer sub_node.end();
689
686 var arena = std.heap.ArenaAllocator.init(parser.a);690 var arena = std.heap.ArenaAllocator.init(parser.a);
687 defer arena.deinit();691 defer arena.deinit();
688 const a = arena.allocator();692 const a = arena.allocator();
...@@ -691,10 +695,16 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {...@@ -691,10 +695,16 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {
691 try info.resolve(a);695 try info.resolve(a);
692696
693 var builder = try ModuleBuilder.init(a, binary.*, info);697 var builder = try ModuleBuilder.init(a, binary.*, info);
698 sub_node.completeOne();
694 try builder.deriveNewFnInfo(info);699 try builder.deriveNewFnInfo(info);
700 sub_node.completeOne();
695 try builder.processPreamble(binary.*, info);701 try builder.processPreamble(binary.*, info);
702 sub_node.completeOne();
696 try builder.emitFunctionTypes(info);703 try builder.emitFunctionTypes(info);
704 sub_node.completeOne();
697 try builder.rewriteFunctions(parser, binary.*, info);705 try builder.rewriteFunctions(parser, binary.*, info);
706 sub_node.completeOne();
698 try builder.emitNewEntryPoints(info);707 try builder.emitNewEntryPoints(info);
708 sub_node.completeOne();
699 try builder.finalize(parser.a, binary);709 try builder.finalize(parser.a, binary);
700}710}
src/link/SpirV/prune_unused.zig+9-1
...@@ -255,7 +255,11 @@ fn removeIdsFromMap(a: Allocator, map: anytype, info: ModuleInfo, alive_marker:...@@ -255,7 +255,11 @@ fn removeIdsFromMap(a: Allocator, map: anytype, info: ModuleInfo, alive_marker:
255 }255 }
256}256}
257257
258pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {258pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: *std.Progress.Node) !void {
259 var sub_node = progress.start("Prune unused IDs", 0);
260 sub_node.activate();
261 defer sub_node.end();
262
259 var arena = std.heap.ArenaAllocator.init(parser.a);263 var arena = std.heap.ArenaAllocator.init(parser.a);
260 defer arena.deinit();264 defer arena.deinit();
261 const a = arena.allocator();265 const a = arena.allocator();
...@@ -285,9 +289,13 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {...@@ -285,9 +289,13 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {
285289
286 var section = Section{};290 var section = Section{};
287291
292 sub_node.setEstimatedTotalItems(binary.instructions.len);
293
288 var new_functions_section: ?usize = null;294 var new_functions_section: ?usize = null;
289 var it = binary.iterateInstructions();295 var it = binary.iterateInstructions();
290 skip: while (it.next()) |inst| {296 skip: while (it.next()) |inst| {
297 defer sub_node.setCompletedItems(inst.offset);
298
291 const inst_spec = parser.getInstSpec(inst.opcode).?;299 const inst_spec = parser.getInstSpec(inst.opcode).?;
292300
293 reemit: {301 reemit: {
test/behavior/destructure.zig-2
...@@ -23,8 +23,6 @@ test "simple destructure" {...@@ -23,8 +23,6 @@ test "simple destructure" {
23}23}
2424
25test "destructure with comptime syntax" {25test "destructure with comptime syntax" {
26 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
27
28 const S = struct {26 const S = struct {
29 fn doTheTest() !void {27 fn doTheTest() !void {
30 {28 {
test/behavior/fn.zig-1
...@@ -181,7 +181,6 @@ test "function with complex callconv and return type expressions" {...@@ -181,7 +181,6 @@ test "function with complex callconv and return type expressions" {
181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
183 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO183 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
184 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
185184
186 try expect(fComplexCallconvRet(3).x == 9);185 try expect(fComplexCallconvRet(3).x == 9);
187}186}
test/behavior/generics.zig-1
...@@ -447,7 +447,6 @@ test "return type of generic function is function pointer" {...@@ -447,7 +447,6 @@ test "return type of generic function is function pointer" {
447447
448test "coerced function body has inequal value with its uncoerced body" {448test "coerced function body has inequal value with its uncoerced body" {
449 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;449 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
450 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
451450
452 const S = struct {451 const S = struct {
453 const A = B(i32, c);452 const A = B(i32, c);
test/behavior/math.zig-2
...@@ -12,7 +12,6 @@ const math = std.math;...@@ -12,7 +12,6 @@ const math = std.math;
12test "assignment operators" {12test "assignment operators" {
13 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO14 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1615
17 var i: u32 = 0;16 var i: u32 = 0;
18 i += 5;17 i += 5;
...@@ -188,7 +187,6 @@ test "@ctz vectors" {...@@ -188,7 +187,6 @@ test "@ctz vectors" {
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO187 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO188 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
191 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
192190
193 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {191 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
194 // This regressed with LLVM 14:192 // This regressed with LLVM 14:
test/behavior/switch.zig-2
...@@ -850,8 +850,6 @@ test "inline switch range that includes the maximum value of the switched type"...@@ -850,8 +850,6 @@ test "inline switch range that includes the maximum value of the switched type"
850}850}
851851
852test "nested break ignores switch conditions and breaks instead" {852test "nested break ignores switch conditions and breaks instead" {
853 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
854
855 const S = struct {853 const S = struct {
856 fn register_to_address(ident: []const u8) !u8 {854 fn register_to_address(ident: []const u8) !u8 {
857 const reg: u8 = if (std.mem.eql(u8, ident, "zero")) 0x00 else blk: {855 const reg: u8 = if (std.mem.eql(u8, ident, "zero")) 0x00 else blk: {
test/behavior/union.zig-1
...@@ -1750,7 +1750,6 @@ test "reinterpret extern union" {...@@ -1750,7 +1750,6 @@ test "reinterpret extern union" {
1750 // https://github.com/ziglang/zig/issues/193891750 // https://github.com/ziglang/zig/issues/19389
1751 return error.SkipZigTest;1751 return error.SkipZigTest;
1752 }1752 }
1753 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
17541753
1755 const U = extern union {1754 const U = extern union {
1756 foo: u8,1755 foo: u8,
test/behavior/vector.zig-2
...@@ -76,7 +76,6 @@ test "vector int operators" {...@@ -76,7 +76,6 @@ test "vector int operators" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO78 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
79 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
8079
81 const S = struct {80 const S = struct {
82 fn doTheTest() !void {81 fn doTheTest() !void {
...@@ -1037,7 +1036,6 @@ test "multiplication-assignment operator with an array operand" {...@@ -1037,7 +1036,6 @@ test "multiplication-assignment operator with an array operand" {
1037 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1036 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1038 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1037 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1039 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1038 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1040 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10411039
1042 const S = struct {1040 const S = struct {
1043 fn doTheTest() !void {1041 fn doTheTest() !void {