authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2025-02-15 23:03:59+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2025-02-18 18:07:48+03:30
log29e46633ce29e5325049dd1835c1c0bde0f6d79e
tree90dad2c55df31e8aec3279377baf1e544eed7856
parent7bbeac7f175f5b2aff27aea9c9f64d531150aa80
signature Commit is signed but in an unrecognized format.

spirv: cache more types & merge constructX functions


4 files changed, 219 insertions(+), 281 deletions(-)

src/codegen/spirv.zig+134-272
...@@ -159,7 +159,7 @@ pub const Object = struct {...@@ -159,7 +159,7 @@ pub const Object = struct {
159 uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, SpvModule.Decl.Index) = .empty,159 uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, SpvModule.Decl.Index) = .empty,
160160
161 /// A map that maps AIR intern pool indices to SPIR-V result-ids.161 /// A map that maps AIR intern pool indices to SPIR-V result-ids.
162 intern_map: InternMap = .{},162 intern_map: InternMap = .empty,
163163
164 /// This map serves a dual purpose:164 /// This map serves a dual purpose:
165 /// - It keeps track of pointers that are currently being emitted, so that we can tell165 /// - It keeps track of pointers that are currently being emitted, so that we can tell
...@@ -314,7 +314,7 @@ const NavGen = struct {...@@ -314,7 +314,7 @@ const NavGen = struct {
314 next_arg_index: u32 = 0,314 next_arg_index: u32 = 0,
315315
316 /// A map keeping track of which instruction generated which result-id.316 /// A map keeping track of which instruction generated which result-id.
317 inst_results: InstMap = .{},317 inst_results: InstMap = .empty,
318318
319 /// A map that maps AIR intern pool indices to SPIR-V result-ids.319 /// A map that maps AIR intern pool indices to SPIR-V result-ids.
320 /// See `Object.intern_map`.320 /// See `Object.intern_map`.
...@@ -469,7 +469,7 @@ const NavGen = struct {...@@ -469,7 +469,7 @@ const NavGen = struct {
469469
470 const zcu = self.pt.zcu;470 const zcu = self.pt.zcu;
471 const ty = Type.fromInterned(zcu.intern_pool.typeOf(val));471 const ty = Type.fromInterned(zcu.intern_pool.typeOf(val));
472 const decl_ptr_ty_id = try self.ptrType(ty, .Generic);472 const decl_ptr_ty_id = try self.ptrType(ty, .Generic, .indirect);
473473
474 const spv_decl_index = blk: {474 const spv_decl_index = blk: {
475 const entry = try self.object.uav_link.getOrPut(self.object.gpa, .{ val, .Function });475 const entry = try self.object.uav_link.getOrPut(self.object.gpa, .{ val, .Function });
...@@ -532,7 +532,7 @@ const NavGen = struct {...@@ -532,7 +532,7 @@ const NavGen = struct {
532532
533 try self.spv.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});533 try self.spv.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});
534534
535 const fn_decl_ptr_ty_id = try self.ptrType(ty, .Function);535 const fn_decl_ptr_ty_id = try self.ptrType(ty, .Function, .indirect);
536 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{536 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{
537 .id_result_type = fn_decl_ptr_ty_id,537 .id_result_type = fn_decl_ptr_ty_id,
538 .id_result = result_id,538 .id_result = result_id,
...@@ -721,36 +721,16 @@ const NavGen = struct {...@@ -721,36 +721,16 @@ const NavGen = struct {
721721
722 /// Emits a bool constant in a particular representation.722 /// Emits a bool constant in a particular representation.
723 fn constBool(self: *NavGen, value: bool, repr: Repr) !IdRef {723 fn constBool(self: *NavGen, value: bool, repr: Repr) !IdRef {
724 // TODO: Cache?724 return switch (repr) {
725725 .indirect => self.constInt(Type.u1, @intFromBool(value)),
726 const section = &self.spv.sections.types_globals_constants;726 .direct => self.spv.constBool(value),
727 switch (repr) {727 };
728 .indirect => {
729 return try self.constInt(Type.u1, @intFromBool(value), .indirect);
730 },
731 .direct => {
732 const result_ty_id = try self.resolveType(Type.bool, .direct);
733 const result_id = self.spv.allocId();
734 switch (value) {
735 inline else => |val_ct| try section.emit(
736 self.spv.gpa,
737 if (val_ct) .OpConstantTrue else .OpConstantFalse,
738 .{
739 .id_result_type = result_ty_id,
740 .id_result = result_id,
741 },
742 ),
743 }
744 return result_id;
745 },
746 }
747 }728 }
748729
749 /// Emits an integer constant.730 /// Emits an integer constant.
750 /// This function, unlike SpvModule.constInt, takes care to bitcast731 /// This function, unlike SpvModule.constInt, takes care to bitcast
751 /// the value to an unsigned int first for Kernels.732 /// the value to an unsigned int first for Kernels.
752 fn constInt(self: *NavGen, ty: Type, value: anytype, repr: Repr) !IdRef {733 fn constInt(self: *NavGen, ty: Type, value: anytype) !IdRef {
753 // TODO: Cache?
754 const zcu = self.pt.zcu;734 const zcu = self.pt.zcu;
755 const scalar_ty = ty.scalarType(zcu);735 const scalar_ty = ty.scalarType(zcu);
756 const int_info = scalar_ty.intInfo(zcu);736 const int_info = scalar_ty.intInfo(zcu);
...@@ -763,18 +743,18 @@ const NavGen = struct {...@@ -763,18 +743,18 @@ const NavGen = struct {
763 else => unreachable,743 else => unreachable,
764 };744 };
765745
766 const bits: u64 = switch (signedness) {746 const value64: u64 = switch (signedness) {
767 .signed => @bitCast(@as(i64, @intCast(value))),747 .signed => @bitCast(@as(i64, @intCast(value))),
768 .unsigned => @as(u64, @intCast(value)),748 .unsigned => @as(u64, @intCast(value)),
769 };749 };
770750
771 // Manually truncate the value to the right amount of bits.751 // Manually truncate the value to the right amount of bits.
772 const truncated_bits = if (backing_bits == 64)752 const truncated_value = if (backing_bits == 64)
773 bits753 value64
774 else754 else
775 bits & (@as(u64, 1) << @intCast(backing_bits)) - 1;755 value64 & (@as(u64, 1) << @intCast(backing_bits)) - 1;
776756
777 const result_ty_id = try self.resolveType(scalar_ty, repr);757 const result_ty_id = try self.resolveType(scalar_ty, .indirect);
778 const result_id = self.spv.allocId();758 const result_id = self.spv.allocId();
779759
780 const section = &self.spv.sections.types_globals_constants;760 const section = &self.spv.sections.types_globals_constants;
...@@ -783,100 +763,42 @@ const NavGen = struct {...@@ -783,100 +763,42 @@ const NavGen = struct {
783 1...32 => try section.emit(self.spv.gpa, .OpConstant, .{763 1...32 => try section.emit(self.spv.gpa, .OpConstant, .{
784 .id_result_type = result_ty_id,764 .id_result_type = result_ty_id,
785 .id_result = result_id,765 .id_result = result_id,
786 .value = .{ .uint32 = @truncate(truncated_bits) },766 .value = .{ .uint32 = @truncate(truncated_value) },
787 }),767 }),
788 33...64 => try section.emit(self.spv.gpa, .OpConstant, .{768 33...64 => try section.emit(self.spv.gpa, .OpConstant, .{
789 .id_result_type = result_ty_id,769 .id_result_type = result_ty_id,
790 .id_result = result_id,770 .id_result = result_id,
791 .value = .{ .uint64 = truncated_bits },771 .value = .{ .uint64 = truncated_value },
792 }),772 }),
793 else => unreachable, // TODO: Large integer constants773 else => unreachable, // TODO: Large integer constants
794 }774 }
795775
796 if (!ty.isVector(zcu)) {776 if (!ty.isVector(zcu)) return result_id;
797 return result_id;777 return self.constructCompositeSplat(ty, result_id);
798 }
799
800 const n = ty.vectorLen(zcu);
801 const ids = try self.gpa.alloc(IdRef, n);
802 defer self.gpa.free(ids);
803 @memset(ids, result_id);
804
805 const vec_ty_id = try self.resolveType(ty, repr);
806 const vec_result_id = self.spv.allocId();
807 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
808 .id_result_type = vec_ty_id,
809 .id_result = vec_result_id,
810 .constituents = ids,
811 });
812 return vec_result_id;
813 }778 }
814779
815 /// Construct a struct at runtime.780 pub fn constructComposite(self: *NavGen, result_ty_id: IdRef, constituents: []const IdRef) !IdRef {
816 /// ty must be a struct type.
817 /// Constituents should be in `indirect` representation (as the elements of a struct should be).
818 /// Result is in `direct` representation.
819 fn constructStruct(self: *NavGen, ty: Type, types: []const Type, constituents: []const IdRef) !IdRef {
820 assert(types.len == constituents.len);
821
822 const result_id = self.spv.allocId();781 const result_id = self.spv.allocId();
823 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{782 try self.func.body.emit(self.gpa, .OpCompositeConstruct, .{
824 .id_result_type = try self.resolveType(ty, .direct),783 .id_result_type = result_ty_id,
825 .id_result = result_id,
826 .constituents = constituents,
827 });
828 return result_id;
829 }
830
831 /// Construct a vector at runtime.
832 /// ty must be an vector type.
833 fn constructVector(self: *NavGen, ty: Type, constituents: []const IdRef) !IdRef {
834 const zcu = self.pt.zcu;
835 assert(ty.vectorLen(zcu) == constituents.len);
836
837 // Note: older versions of the Khronos SPRIV-LLVM translator crash on this instruction
838 // because it cannot construct structs which' operands are not constant.
839 // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349
840 // Currently this is the case for Intel OpenCL CPU runtime (2023-WW46), but the
841 // alternatives dont work properly:
842 // - using temporaries/pointers doesn't work properly with vectors of bool, causes
843 // backends that use llvm to crash
844 // - using OpVectorInsertDynamic doesn't work for non-spirv-vectors of bool.
845
846 const result_id = self.spv.allocId();
847 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
848 .id_result_type = try self.resolveType(ty, .direct),
849 .id_result = result_id,784 .id_result = result_id,
850 .constituents = constituents,785 .constituents = constituents,
851 });786 });
852 return result_id;787 return result_id;
853 }788 }
854789
855 /// Construct a vector at runtime with all lanes set to the same value.790 /// Construct a composite at runtime with all lanes set to the same value.
856 /// ty must be an vector type.791 /// ty must be an aggregate type.
857 fn constructVectorSplat(self: *NavGen, ty: Type, constituent: IdRef) !IdRef {792 fn constructCompositeSplat(self: *NavGen, ty: Type, constituent: IdRef) !IdRef {
858 const zcu = self.pt.zcu;793 const zcu = self.pt.zcu;
859 const n = ty.vectorLen(zcu);794 const n = ty.arrayLen(zcu);
860795
861 const constituents = try self.gpa.alloc(IdRef, n);796 const constituents = try self.gpa.alloc(IdRef, n);
862 defer self.gpa.free(constituents);797 defer self.gpa.free(constituents);
863 @memset(constituents, constituent);798 @memset(constituents, constituent);
864799
865 return try self.constructVector(ty, constituents);800 const result_ty_id = try self.resolveType(ty, .direct);
866 }801 return self.constructComposite(result_ty_id, constituents);
867
868 /// Construct an array at runtime.
869 /// ty must be an array type.
870 /// Constituents should be in `indirect` representation (as the elements of an array should be).
871 /// Result is in `direct` representation.
872 fn constructArray(self: *NavGen, ty: Type, constituents: []const IdRef) !IdRef {
873 const result_id = self.spv.allocId();
874 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
875 .id_result_type = try self.resolveType(ty, .direct),
876 .id_result = result_id,
877 .constituents = constituents,
878 });
879 return result_id;
880 }802 }
881803
882 /// This function generates a load for a constant in direct (ie, non-memory) representation.804 /// This function generates a load for a constant in direct (ie, non-memory) representation.
...@@ -947,9 +869,9 @@ const NavGen = struct {...@@ -947,9 +869,9 @@ const NavGen = struct {
947 },869 },
948 .int => {870 .int => {
949 if (ty.isSignedInt(zcu)) {871 if (ty.isSignedInt(zcu)) {
950 break :cache try self.constInt(ty, val.toSignedInt(zcu), repr);872 break :cache try self.constInt(ty, val.toSignedInt(zcu));
951 } else {873 } else {
952 break :cache try self.constInt(ty, val.toUnsignedInt(zcu), repr);874 break :cache try self.constInt(ty, val.toUnsignedInt(zcu));
953 }875 }
954 },876 },
955 .float => {877 .float => {
...@@ -970,7 +892,7 @@ const NavGen = struct {...@@ -970,7 +892,7 @@ const NavGen = struct {
970 },892 },
971 .err => |err| {893 .err => |err| {
972 const value = try pt.getErrorValue(err.name);894 const value = try pt.getErrorValue(err.name);
973 break :cache try self.constInt(ty, value, repr);895 break :cache try self.constInt(ty, value);
974 },896 },
975 .error_union => |error_union| {897 .error_union => |error_union| {
976 // TODO: Error unions may be constructed with constant instructions if the payload type898 // TODO: Error unions may be constructed with constant instructions if the payload type
...@@ -1011,7 +933,8 @@ const NavGen = struct {...@@ -1011,7 +933,8 @@ const NavGen = struct {
1011 types = .{ payload_ty, err_ty };933 types = .{ payload_ty, err_ty };
1012 }934 }
1013935
1014 return try self.constructStruct(ty, &types, &constituents);936 const comp_ty_id = try self.resolveType(ty, .direct);
937 return try self.constructComposite(comp_ty_id, &constituents);
1015 },938 },
1016 .enum_tag => {939 .enum_tag => {
1017 const int_val = try val.intFromEnum(ty, pt);940 const int_val = try val.intFromEnum(ty, pt);
...@@ -1020,14 +943,10 @@ const NavGen = struct {...@@ -1020,14 +943,10 @@ const NavGen = struct {
1020 },943 },
1021 .ptr => return self.constantPtr(val),944 .ptr => return self.constantPtr(val),
1022 .slice => |slice| {945 .slice => |slice| {
1023 const ptr_ty = ty.slicePtrFieldType(zcu);
1024 const ptr_id = try self.constantPtr(Value.fromInterned(slice.ptr));946 const ptr_id = try self.constantPtr(Value.fromInterned(slice.ptr));
1025 const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);947 const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);
1026 return self.constructStruct(948 const comp_ty_id = try self.resolveType(ty, .direct);
1027 ty,949 return try self.constructComposite(comp_ty_id, &.{ ptr_id, len_id });
1028 &.{ ptr_ty, Type.usize },
1029 &.{ ptr_id, len_id },
1030 );
1031 },950 },
1032 .opt => {951 .opt => {
1033 const payload_ty = ty.optionalChild(zcu);952 const payload_ty = ty.optionalChild(zcu);
...@@ -1053,11 +972,8 @@ const NavGen = struct {...@@ -1053,11 +972,8 @@ const NavGen = struct {
1053 else972 else
1054 try self.spv.constUndef(try self.resolveType(payload_ty, .indirect));973 try self.spv.constUndef(try self.resolveType(payload_ty, .indirect));
1055974
1056 return try self.constructStruct(975 const comp_ty_id = try self.resolveType(ty, .direct);
1057 ty,976 return try self.constructComposite(comp_ty_id, &.{ payload_id, has_pl_id });
1058 &.{ payload_ty, Type.bool },
1059 &.{ payload_id, has_pl_id },
1060 );
1061 },977 },
1062 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {978 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {
1063 inline .array_type, .vector_type => |array_type, tag| {979 inline .array_type, .vector_type => |array_type, tag| {
...@@ -1077,7 +993,7 @@ const NavGen = struct {...@@ -1077,7 +993,7 @@ const NavGen = struct {
1077 // TODO: This is really space inefficient, perhaps there is a better993 // TODO: This is really space inefficient, perhaps there is a better
1078 // way to do it?994 // way to do it?
1079 for (constituents, bytes.toSlice(constituents.len, ip)) |*constituent, byte| {995 for (constituents, bytes.toSlice(constituents.len, ip)) |*constituent, byte| {
1080 constituent.* = try self.constInt(elem_ty, byte, child_repr);996 constituent.* = try self.constInt(elem_ty, byte);
1081 }997 }
1082 },998 },
1083 .elems => |elems| {999 .elems => |elems| {
...@@ -1090,11 +1006,8 @@ const NavGen = struct {...@@ -1090,11 +1006,8 @@ const NavGen = struct {
1090 },1006 },
1091 }1007 }
10921008
1093 switch (tag) {1009 const comp_ty_id = try self.resolveType(ty, .direct);
1094 .array_type => return self.constructArray(ty, constituents),1010 return self.constructComposite(comp_ty_id, constituents);
1095 .vector_type => return self.constructVector(ty, constituents),
1096 else => unreachable,
1097 }
1098 },1011 },
1099 .struct_type => {1012 .struct_type => {
1100 const struct_type = zcu.typeToStruct(ty).?;1013 const struct_type = zcu.typeToStruct(ty).?;
...@@ -1124,7 +1037,8 @@ const NavGen = struct {...@@ -1124,7 +1037,8 @@ const NavGen = struct {
1124 try constituents.append(field_id);1037 try constituents.append(field_id);
1125 }1038 }
11261039
1127 return try self.constructStruct(ty, types.items, constituents.items);1040 const comp_ty_id = try self.resolveType(ty, .direct);
1041 return try self.constructComposite(comp_ty_id, constituents.items);
1128 },1042 },
1129 .tuple_type => unreachable, // TODO1043 .tuple_type => unreachable, // TODO
1130 else => unreachable,1044 else => unreachable,
...@@ -1149,8 +1063,6 @@ const NavGen = struct {...@@ -1149,8 +1063,6 @@ const NavGen = struct {
1149 }1063 }
11501064
1151 fn constantPtr(self: *NavGen, ptr_val: Value) Error!IdRef {1065 fn constantPtr(self: *NavGen, ptr_val: Value) Error!IdRef {
1152 // TODO: Caching??
1153
1154 const pt = self.pt;1066 const pt = self.pt;
11551067
1156 if (ptr_val.isUndef(pt.zcu)) {1068 if (ptr_val.isUndef(pt.zcu)) {
...@@ -1201,7 +1113,7 @@ const NavGen = struct {...@@ -1201,7 +1113,7 @@ const NavGen = struct {
1201 .elem_ptr => |elem| {1113 .elem_ptr => |elem| {
1202 const parent_ptr_id = try self.derivePtr(elem.parent.*);1114 const parent_ptr_id = try self.derivePtr(elem.parent.*);
1203 const parent_ptr_ty = try elem.parent.ptrType(pt);1115 const parent_ptr_ty = try elem.parent.ptrType(pt);
1204 const index_id = try self.constInt(Type.usize, elem.elem_idx, .direct);1116 const index_id = try self.constInt(Type.usize, elem.elem_idx);
1205 return self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);1117 return self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);
1206 },1118 },
1207 .offset_and_cast => |oac| {1119 .offset_and_cast => |oac| {
...@@ -1255,7 +1167,7 @@ const NavGen = struct {...@@ -1255,7 +1167,7 @@ const NavGen = struct {
12551167
1256 // Uav refs are always generic.1168 // Uav refs are always generic.
1257 assert(ty.ptrAddressSpace(zcu) == .generic);1169 assert(ty.ptrAddressSpace(zcu) == .generic);
1258 const decl_ptr_ty_id = try self.ptrType(uav_ty, .Generic);1170 const decl_ptr_ty_id = try self.ptrType(uav_ty, .Generic, .indirect);
1259 const ptr_id = try self.resolveUav(uav.val);1171 const ptr_id = try self.resolveUav(uav.val);
12601172
1261 if (decl_ptr_ty_id != ty_id) {1173 if (decl_ptr_ty_id != ty_id) {
...@@ -1310,7 +1222,7 @@ const NavGen = struct {...@@ -1310,7 +1222,7 @@ const NavGen = struct {
1310 const storage_class = self.spvStorageClass(nav.getAddrspace());1222 const storage_class = self.spvStorageClass(nav.getAddrspace());
1311 try self.addFunctionDep(spv_decl_index, storage_class);1223 try self.addFunctionDep(spv_decl_index, storage_class);
13121224
1313 const decl_ptr_ty_id = try self.ptrType(nav_ty, storage_class);1225 const decl_ptr_ty_id = try self.ptrType(nav_ty, storage_class, .indirect);
13141226
1315 const ptr_id = switch (storage_class) {1227 const ptr_id = switch (storage_class) {
1316 .Generic => try self.castToGeneric(decl_ptr_ty_id, decl_id),1228 .Generic => try self.castToGeneric(decl_ptr_ty_id, decl_id),
...@@ -1359,23 +1271,11 @@ const NavGen = struct {...@@ -1359,23 +1271,11 @@ const NavGen = struct {
1359 }1271 }
13601272
1361 fn arrayType(self: *NavGen, len: u32, child_ty: IdRef) !IdRef {1273 fn arrayType(self: *NavGen, len: u32, child_ty: IdRef) !IdRef {
1362 // TODO: Cache??1274 const len_id = try self.constInt(Type.u32, len);
1363 const len_id = try self.constInt(Type.u32, len, .direct);1275 return self.spv.arrayType(len_id, child_ty);
1364 const result_id = self.spv.allocId();
1365
1366 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypeArray, .{
1367 .id_result = result_id,
1368 .element_type = child_ty,
1369 .length = len_id,
1370 });
1371 return result_id;
1372 }
1373
1374 fn ptrType(self: *NavGen, child_ty: Type, storage_class: StorageClass) !IdRef {
1375 return try self.ptrType2(child_ty, storage_class, .indirect);
1376 }1276 }
13771277
1378 fn ptrType2(self: *NavGen, child_ty: Type, storage_class: StorageClass, child_repr: Repr) !IdRef {1278 fn ptrType(self: *NavGen, child_ty: Type, storage_class: StorageClass, child_repr: Repr) !IdRef {
1379 const key = .{ child_ty.toIntern(), storage_class, child_repr };1279 const key = .{ child_ty.toIntern(), storage_class, child_repr };
1380 const entry = try self.ptr_types.getOrPut(self.gpa, key);1280 const entry = try self.ptr_types.getOrPut(self.gpa, key);
1381 if (entry.found_existing) {1281 if (entry.found_existing) {
...@@ -1408,8 +1308,7 @@ const NavGen = struct {...@@ -1408,8 +1308,7 @@ const NavGen = struct {
1408 }1308 }
14091309
1410 fn functionType(self: *NavGen, return_ty: Type, param_types: []const Type) !IdRef {1310 fn functionType(self: *NavGen, return_ty: Type, param_types: []const Type) !IdRef {
1411 // TODO: Cache??1311 const return_ty_id = try self.resolveFnReturnType(return_ty);
1412
1413 const param_ids = try self.gpa.alloc(IdRef, param_types.len);1312 const param_ids = try self.gpa.alloc(IdRef, param_types.len);
1414 defer self.gpa.free(param_ids);1313 defer self.gpa.free(param_ids);
14151314
...@@ -1417,14 +1316,7 @@ const NavGen = struct {...@@ -1417,14 +1316,7 @@ const NavGen = struct {
1417 param_id.* = try self.resolveType(param_ty, .direct);1316 param_id.* = try self.resolveType(param_ty, .direct);
1418 }1317 }
14191318
1420 const ty_id = self.spv.allocId();1319 return self.spv.functionType(return_ty_id, param_ids);
1421 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypeFunction, .{
1422 .id_result = ty_id,
1423 .return_type = try self.resolveFnReturnType(return_ty),
1424 .id_ref_2 = param_ids,
1425 });
1426
1427 return ty_id;
1428 }1320 }
14291321
1430 fn zigScalarOrVectorTypeLike(self: *NavGen, new_ty: Type, base_ty: Type) !Type {1322 fn zigScalarOrVectorTypeLike(self: *NavGen, new_ty: Type, base_ty: Type) !Type {
...@@ -1702,13 +1594,7 @@ const NavGen = struct {...@@ -1702,13 +1594,7 @@ const NavGen = struct {
17021594
1703 const child_ty = Type.fromInterned(ptr_info.child);1595 const child_ty = Type.fromInterned(ptr_info.child);
1704 const storage_class = self.spvStorageClass(ptr_info.flags.address_space);1596 const storage_class = self.spvStorageClass(ptr_info.flags.address_space);
1705 const ptr_ty_id = try self.ptrType(child_ty, storage_class);1597 const ptr_ty_id = try self.ptrType(child_ty, storage_class, .indirect);
1706
1707 if (target.os.tag == .vulkan and ptr_info.flags.size == .many) {
1708 try self.spv.decorate(ptr_ty_id, .{ .ArrayStride = .{
1709 .array_stride = @intCast(child_ty.abiSize(zcu)),
1710 } });
1711 }
17121598
1713 if (ptr_info.flags.size != .slice) {1599 if (ptr_info.flags.size != .slice) {
1714 return ptr_ty_id;1600 return ptr_ty_id;
...@@ -1755,10 +1641,6 @@ const NavGen = struct {...@@ -1755,10 +1641,6 @@ const NavGen = struct {
1755 defer self.gpa.free(type_name);1641 defer self.gpa.free(type_name);
1756 try self.spv.debugName(result_id, type_name);1642 try self.spv.debugName(result_id, type_name);
17571643
1758 if (target.os.tag == .vulkan) {
1759 try self.spv.decorate(result_id, .Block); // Decorate all structs as block for now...
1760 }
1761
1762 return result_id;1644 return result_id;
1763 },1645 },
1764 .struct_type => ip.loadStructType(ty.toIntern()),1646 .struct_type => ip.loadStructType(ty.toIntern()),
...@@ -1804,10 +1686,6 @@ const NavGen = struct {...@@ -1804,10 +1686,6 @@ const NavGen = struct {
1804 defer self.gpa.free(type_name);1686 defer self.gpa.free(type_name);
1805 try self.spv.debugName(result_id, type_name);1687 try self.spv.debugName(result_id, type_name);
18061688
1807 if (target.os.tag == .vulkan) {
1808 try self.spv.decorate(result_id, .Block); // Decorate all structs as block for now...
1809 }
1810
1811 return result_id;1689 return result_id;
1812 },1690 },
1813 .optional => {1691 .optional => {
...@@ -2073,12 +1951,13 @@ const NavGen = struct {...@@ -2073,12 +1951,13 @@ const NavGen = struct {
2073 .exploded_vector => |range| {1951 .exploded_vector => |range| {
2074 assert(self.ty.isVector(zcu));1952 assert(self.ty.isVector(zcu));
2075 assert(self.ty.vectorLen(zcu) == range.len);1953 assert(self.ty.vectorLen(zcu) == range.len);
2076 const consituents = try ng.gpa.alloc(IdRef, range.len);1954 const constituents = try ng.gpa.alloc(IdRef, range.len);
2077 defer ng.gpa.free(consituents);1955 defer ng.gpa.free(constituents);
2078 for (consituents, 0..range.len) |*id, i| {1956 for (constituents, 0..range.len) |*id, i| {
2079 id.* = range.at(i);1957 id.* = range.at(i);
2080 }1958 }
2081 return ng.constructVector(self.ty, consituents);1959 const result_ty_id = try ng.resolveType(self.ty, .direct);
1960 return ng.constructComposite(result_ty_id, constituents);
2082 },1961 },
2083 }1962 }
2084 }1963 }
...@@ -2282,7 +2161,7 @@ const NavGen = struct {...@@ -2282,7 +2161,7 @@ const NavGen = struct {
2282 .child = tmp.ty.toIntern(),2161 .child = tmp.ty.toIntern(),
2283 });2162 });
22842163
2285 const vector = try ng.constructVectorSplat(vector_ty, id);2164 const vector = try ng.constructCompositeSplat(vector_ty, id);
2286 return .{2165 return .{
2287 .ty = vector_ty,2166 .ty = vector_ty,
2288 .value = .{ .spv_vectorwise = vector },2167 .value = .{ .spv_vectorwise = vector },
...@@ -3045,7 +2924,7 @@ const NavGen = struct {...@@ -3045,7 +2924,7 @@ const NavGen = struct {
3045 const spv_err_decl_index = self.object.error_push_constant.?.push_constant_ptr;2924 const spv_err_decl_index = self.object.error_push_constant.?.push_constant_ptr;
3046 const push_constant_id = self.spv.declPtr(spv_err_decl_index).result_id;2925 const push_constant_id = self.spv.declPtr(spv_err_decl_index).result_id;
30472926
3048 const zero_id = try self.constInt(Type.u32, 0, .direct);2927 const zero_id = try self.constInt(Type.u32, 0);
3049 // We cannot use OpInBoundsAccessChain to dereference cross-storage class, so we have to use2928 // We cannot use OpInBoundsAccessChain to dereference cross-storage class, so we have to use
3050 // a load.2929 // a load.
3051 const tmp = self.spv.allocId();2930 const tmp = self.spv.allocId();
...@@ -3187,7 +3066,7 @@ const NavGen = struct {...@@ -3187,7 +3066,7 @@ const NavGen = struct {
3187 const storage_class = self.spvStorageClass(nav.getAddrspace());3066 const storage_class = self.spvStorageClass(nav.getAddrspace());
3188 assert(storage_class != .Generic); // These should be instance globals3067 assert(storage_class != .Generic); // These should be instance globals
31893068
3190 const ptr_ty_id = try self.ptrType(ty, storage_class);3069 const ptr_ty_id = try self.ptrType(ty, storage_class, .indirect);
31913070
3192 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpVariable, .{3071 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpVariable, .{
3193 .id_result_type = ptr_ty_id,3072 .id_result_type = ptr_ty_id,
...@@ -3208,7 +3087,7 @@ const NavGen = struct {...@@ -3208,7 +3087,7 @@ const NavGen = struct {
32083087
3209 try self.spv.declareDeclDeps(spv_decl_index, &.{});3088 try self.spv.declareDeclDeps(spv_decl_index, &.{});
32103089
3211 const ptr_ty_id = try self.ptrType(ty, .Function);3090 const ptr_ty_id = try self.ptrType(ty, .Function, .indirect);
32123091
3213 if (maybe_init_val) |init_val| {3092 if (maybe_init_val) |init_val| {
3214 // TODO: Combine with resolveAnonDecl?3093 // TODO: Combine with resolveAnonDecl?
...@@ -3265,8 +3144,8 @@ const NavGen = struct {...@@ -3265,8 +3144,8 @@ const NavGen = struct {
3265 }3144 }
32663145
3267 fn intFromBool2(self: *NavGen, value: Temporary, result_ty: Type) !Temporary {3146 fn intFromBool2(self: *NavGen, value: Temporary, result_ty: Type) !Temporary {
3268 const zero_id = try self.constInt(result_ty, 0, .direct);3147 const zero_id = try self.constInt(result_ty, 0);
3269 const one_id = try self.constInt(result_ty, 1, .direct);3148 const one_id = try self.constInt(result_ty, 1);
32703149
3271 return try self.buildSelect(3150 return try self.buildSelect(
3272 value,3151 value,
...@@ -3648,12 +3527,12 @@ const NavGen = struct {...@@ -3648,12 +3527,12 @@ const NavGen = struct {
3648 .strange_integer => switch (info.signedness) {3527 .strange_integer => switch (info.signedness) {
3649 .unsigned => {3528 .unsigned => {
3650 const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1;3529 const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1;
3651 const mask_id = try self.constInt(ty.scalarType(zcu), mask_value, .direct);3530 const mask_id = try self.constInt(ty.scalarType(zcu), mask_value);
3652 return try self.buildBinary(.bit_and, value, Temporary.init(ty.scalarType(zcu), mask_id));3531 return try self.buildBinary(.bit_and, value, Temporary.init(ty.scalarType(zcu), mask_id));
3653 },3532 },
3654 .signed => {3533 .signed => {
3655 // Shift left and right so that we can copy the sight bit that way.3534 // Shift left and right so that we can copy the sight bit that way.
3656 const shift_amt_id = try self.constInt(ty.scalarType(zcu), info.backing_bits - info.bits, .direct);3535 const shift_amt_id = try self.constInt(ty.scalarType(zcu), info.backing_bits - info.bits);
3657 const shift_amt = Temporary.init(ty.scalarType(zcu), shift_amt_id);3536 const shift_amt = Temporary.init(ty.scalarType(zcu), shift_amt_id);
3658 const left = try self.buildBinary(.sll, value, shift_amt);3537 const left = try self.buildBinary(.sll, value, shift_amt);
3659 return try self.buildBinary(.sra, left, shift_amt);3538 return try self.buildBinary(.sra, left, shift_amt);
...@@ -3687,7 +3566,7 @@ const NavGen = struct {...@@ -3687,7 +3566,7 @@ const NavGen = struct {
3687 const div = try self.buildBinary(.s_div, lhs, rhs);3566 const div = try self.buildBinary(.s_div, lhs, rhs);
3688 const rem = try self.buildBinary(.s_rem, lhs, rhs);3567 const rem = try self.buildBinary(.s_rem, lhs, rhs);
36893568
3690 const zero = Temporary.init(lhs.ty, try self.constInt(lhs.ty, 0, .direct));3569 const zero = Temporary.init(lhs.ty, try self.constInt(lhs.ty, 0));
36913570
3692 const rem_is_not_zero = try self.buildCmp(.i_ne, rem, zero);3571 const rem_is_not_zero = try self.buildCmp(.i_ne, rem, zero);
36933572
...@@ -3863,7 +3742,7 @@ const NavGen = struct {...@@ -3863,7 +3742,7 @@ const NavGen = struct {
3863 // = (rhs < 0) == (value < lhs)3742 // = (rhs < 0) == (value < lhs)
3864 // = (rhs < 0) == (lhs > value)3743 // = (rhs < 0) == (lhs > value)
3865 .signed => blk: {3744 .signed => blk: {
3866 const zero = Temporary.init(rhs.ty, try self.constInt(rhs.ty, 0, .direct));3745 const zero = Temporary.init(rhs.ty, try self.constInt(rhs.ty, 0));
3867 const rhs_lt_zero = try self.buildCmp(.s_lt, rhs, zero);3746 const rhs_lt_zero = try self.buildCmp(.s_lt, rhs, zero);
3868 const result_gt_lhs = try self.buildCmp(scmp, lhs, result);3747 const result_gt_lhs = try self.buildCmp(scmp, lhs, result);
3869 break :blk try self.buildCmp(.l_eq, rhs_lt_zero, result_gt_lhs);3748 break :blk try self.buildCmp(.l_eq, rhs_lt_zero, result_gt_lhs);
...@@ -3872,11 +3751,8 @@ const NavGen = struct {...@@ -3872,11 +3751,8 @@ const NavGen = struct {
38723751
3873 const ov = try self.intFromBool(overflowed);3752 const ov = try self.intFromBool(overflowed);
38743753
3875 return try self.constructStruct(3754 const result_ty_id = try self.resolveType(result_ty, .direct);
3876 result_ty,3755 return try self.constructComposite(result_ty_id, &.{ try result.materialize(self), try ov.materialize(self) });
3877 &.{ result.ty, ov.ty },
3878 &.{ try result.materialize(self), try ov.materialize(self) },
3879 );
3880 }3756 }
38813757
3882 fn airMulOverflow(self: *NavGen, inst: Air.Inst.Index) !?IdRef {3758 fn airMulOverflow(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
...@@ -3928,11 +3804,11 @@ const NavGen = struct {...@@ -3928,11 +3804,11 @@ const NavGen = struct {
3928 const result = try self.normalize(low_bits, info);3804 const result = try self.normalize(low_bits, info);
39293805
3930 // Shift the result bits away to get the overflow bits.3806 // Shift the result bits away to get the overflow bits.
3931 const shift = Temporary.init(full_result.ty, try self.constInt(full_result.ty, info.bits, .direct));3807 const shift = Temporary.init(full_result.ty, try self.constInt(full_result.ty, info.bits));
3932 const overflow = try self.buildBinary(.srl, full_result, shift);3808 const overflow = try self.buildBinary(.srl, full_result, shift);
39333809
3934 // Directly check if its zero in the op_ty without converting first.3810 // Directly check if its zero in the op_ty without converting first.
3935 const zero = Temporary.init(full_result.ty, try self.constInt(full_result.ty, 0, .direct));3811 const zero = Temporary.init(full_result.ty, try self.constInt(full_result.ty, 0));
3936 const overflowed = try self.buildCmp(.i_ne, zero, overflow);3812 const overflowed = try self.buildCmp(.i_ne, zero, overflow);
39373813
3938 break :blk .{ result, overflowed };3814 break :blk .{ result, overflowed };
...@@ -3946,7 +3822,7 @@ const NavGen = struct {...@@ -3946,7 +3822,7 @@ const NavGen = struct {
3946 // Overflow happened if the high-bits of the result are non-zero OR if the3822 // Overflow happened if the high-bits of the result are non-zero OR if the
3947 // high bits of the low word of the result (those outside the range of the3823 // high bits of the low word of the result (those outside the range of the
3948 // int) are nonzero.3824 // int) are nonzero.
3949 const zero = Temporary.init(lhs.ty, try self.constInt(lhs.ty, 0, .direct));3825 const zero = Temporary.init(lhs.ty, try self.constInt(lhs.ty, 0));
3950 const high_overflowed = try self.buildCmp(.i_ne, zero, high_bits);3826 const high_overflowed = try self.buildCmp(.i_ne, zero, high_bits);
39513827
3952 // If no overflow bits in low_bits, no extra work needs to be done.3828 // If no overflow bits in low_bits, no extra work needs to be done.
...@@ -3955,7 +3831,7 @@ const NavGen = struct {...@@ -3955,7 +3831,7 @@ const NavGen = struct {
3955 }3831 }
39563832
3957 // Shift the result bits away to get the overflow bits.3833 // Shift the result bits away to get the overflow bits.
3958 const shift = Temporary.init(lhs.ty, try self.constInt(lhs.ty, info.bits, .direct));3834 const shift = Temporary.init(lhs.ty, try self.constInt(lhs.ty, info.bits));
3959 const low_overflow = try self.buildBinary(.srl, low_bits, shift);3835 const low_overflow = try self.buildBinary(.srl, low_bits, shift);
3960 const low_overflowed = try self.buildCmp(.i_ne, zero, low_overflow);3836 const low_overflowed = try self.buildCmp(.i_ne, zero, low_overflow);
39613837
...@@ -3974,7 +3850,7 @@ const NavGen = struct {...@@ -3974,7 +3850,7 @@ const NavGen = struct {
3974 // overflow should be -1 when3850 // overflow should be -1 when
3975 // (lhs > 0 && rhs < 0) || (lhs < 0 && rhs > 0)3851 // (lhs > 0 && rhs < 0) || (lhs < 0 && rhs > 0)
39763852
3977 const zero = Temporary.init(lhs.ty, try self.constInt(lhs.ty, 0, .direct));3853 const zero = Temporary.init(lhs.ty, try self.constInt(lhs.ty, 0));
3978 const lhs_negative = try self.buildCmp(.s_lt, lhs, zero);3854 const lhs_negative = try self.buildCmp(.s_lt, lhs, zero);
3979 const rhs_negative = try self.buildCmp(.s_lt, rhs, zero);3855 const rhs_negative = try self.buildCmp(.s_lt, rhs, zero);
3980 const lhs_positive = try self.buildCmp(.s_gt, lhs, zero);3856 const lhs_positive = try self.buildCmp(.s_gt, lhs, zero);
...@@ -4003,13 +3879,13 @@ const NavGen = struct {...@@ -4003,13 +3879,13 @@ const NavGen = struct {
4003 // bit for the expected overflow bits.3879 // bit for the expected overflow bits.
4004 // To do that, shift out everything bit the sign bit and3880 // To do that, shift out everything bit the sign bit and
4005 // then check what remains.3881 // then check what remains.
4006 const shift = Temporary.init(full_result.ty, try self.constInt(full_result.ty, info.bits - 1, .direct));3882 const shift = Temporary.init(full_result.ty, try self.constInt(full_result.ty, info.bits - 1));
4007 // Use SRA so that any sign bits are duplicated. Now we can just check if ALL bits are set3883 // Use SRA so that any sign bits are duplicated. Now we can just check if ALL bits are set
4008 // for negative cases.3884 // for negative cases.
4009 const overflow = try self.buildBinary(.sra, full_result, shift);3885 const overflow = try self.buildBinary(.sra, full_result, shift);
40103886
4011 const long_all_set = Temporary.init(full_result.ty, try self.constInt(full_result.ty, -1, .direct));3887 const long_all_set = Temporary.init(full_result.ty, try self.constInt(full_result.ty, -1));
4012 const long_zero = Temporary.init(full_result.ty, try self.constInt(full_result.ty, 0, .direct));3888 const long_zero = Temporary.init(full_result.ty, try self.constInt(full_result.ty, 0));
4013 const mask = try self.buildSelect(expected_overflow_bit, long_all_set, long_zero);3889 const mask = try self.buildSelect(expected_overflow_bit, long_all_set, long_zero);
40143890
4015 const overflowed = try self.buildCmp(.i_ne, mask, overflow);3891 const overflowed = try self.buildCmp(.i_ne, mask, overflow);
...@@ -4022,7 +3898,7 @@ const NavGen = struct {...@@ -4022,7 +3898,7 @@ const NavGen = struct {
4022 // Truncate result if required.3898 // Truncate result if required.
4023 const result = try self.normalize(low_bits, info);3899 const result = try self.normalize(low_bits, info);
40243900
4025 const all_set = Temporary.init(lhs.ty, try self.constInt(lhs.ty, -1, .direct));3901 const all_set = Temporary.init(lhs.ty, try self.constInt(lhs.ty, -1));
4026 const mask = try self.buildSelect(expected_overflow_bit, all_set, zero);3902 const mask = try self.buildSelect(expected_overflow_bit, all_set, zero);
40273903
4028 // Like with unsigned, overflow happened if high_bits are not the ones we expect,3904 // Like with unsigned, overflow happened if high_bits are not the ones we expect,
...@@ -4038,7 +3914,7 @@ const NavGen = struct {...@@ -4038,7 +3914,7 @@ const NavGen = struct {
4038 }3914 }
40393915
4040 // Shift the result bits away to get the overflow bits.3916 // Shift the result bits away to get the overflow bits.
4041 const shift = Temporary.init(lhs.ty, try self.constInt(lhs.ty, info.bits - 1, .direct));3917 const shift = Temporary.init(lhs.ty, try self.constInt(lhs.ty, info.bits - 1));
4042 // Use SRA so that any sign bits are duplicated. Now we can just check if ALL bits are set3918 // Use SRA so that any sign bits are duplicated. Now we can just check if ALL bits are set
4043 // for negative cases.3919 // for negative cases.
4044 const low_overflow = try self.buildBinary(.sra, low_bits, shift);3920 const low_overflow = try self.buildBinary(.sra, low_bits, shift);
...@@ -4052,11 +3928,8 @@ const NavGen = struct {...@@ -4052,11 +3928,8 @@ const NavGen = struct {
40523928
4053 const ov = try self.intFromBool(overflowed);3929 const ov = try self.intFromBool(overflowed);
40543930
4055 return try self.constructStruct(3931 const result_ty_id = try self.resolveType(result_ty, .direct);
4056 result_ty,3932 return try self.constructComposite(result_ty_id, &.{ try result.materialize(self), try ov.materialize(self) });
4057 &.{ result.ty, ov.ty },
4058 &.{ try result.materialize(self), try ov.materialize(self) },
4059 );
4060 }3933 }
40613934
4062 fn airShlOverflow(self: *NavGen, inst: Air.Inst.Index) !?IdRef {3935 fn airShlOverflow(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
...@@ -4092,11 +3965,8 @@ const NavGen = struct {...@@ -4092,11 +3965,8 @@ const NavGen = struct {
4092 const overflowed = try self.buildCmp(.i_ne, base, right);3965 const overflowed = try self.buildCmp(.i_ne, base, right);
4093 const ov = try self.intFromBool(overflowed);3966 const ov = try self.intFromBool(overflowed);
40943967
4095 return try self.constructStruct(3968 const result_ty_id = try self.resolveType(result_ty, .direct);
4096 result_ty,3969 return try self.constructComposite(result_ty_id, &.{ try result.materialize(self), try ov.materialize(self) });
4097 &.{ result.ty, ov.ty },
4098 &.{ try result.materialize(self), try ov.materialize(self) },
4099 );
4100 }3970 }
41013971
4102 fn airMulAdd(self: *NavGen, inst: Air.Inst.Index) !?IdRef {3972 fn airMulAdd(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
...@@ -4163,7 +4033,7 @@ const NavGen = struct {...@@ -4163,7 +4033,7 @@ const NavGen = struct {
4163 const operand_id = try self.resolve(ty_op.operand);4033 const operand_id = try self.resolve(ty_op.operand);
4164 const result_ty = self.typeOfIndex(inst);4034 const result_ty = self.typeOfIndex(inst);
41654035
4166 return try self.constructVectorSplat(result_ty, operand_id);4036 return try self.constructCompositeSplat(result_ty, operand_id);
4167 }4037 }
41684038
4169 fn airReduce(self: *NavGen, inst: Air.Inst.Index) !?IdRef {4039 fn airReduce(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
...@@ -4297,10 +4167,10 @@ const NavGen = struct {...@@ -4297,10 +4167,10 @@ const NavGen = struct {
42974167
4298 // Fall back to manually extracting and inserting components.4168 // Fall back to manually extracting and inserting components.
42994169
4300 const components = try self.gpa.alloc(IdRef, result_ty.vectorLen(zcu));4170 const constituents = try self.gpa.alloc(IdRef, result_ty.vectorLen(zcu));
4301 defer self.gpa.free(components);4171 defer self.gpa.free(constituents);
43024172
4303 for (components, 0..) |*id, i| {4173 for (constituents, 0..) |*id, i| {
4304 const elem = try mask.elemValue(pt, i);4174 const elem = try mask.elemValue(pt, i);
4305 if (elem.isUndef(zcu)) {4175 if (elem.isUndef(zcu)) {
4306 id.* = try self.spv.constUndef(scalar_ty_id);4176 id.* = try self.spv.constUndef(scalar_ty_id);
...@@ -4315,14 +4185,15 @@ const NavGen = struct {...@@ -4315,14 +4185,15 @@ const NavGen = struct {
4315 }4185 }
4316 }4186 }
43174187
4318 return try self.constructVector(result_ty, components);4188 const result_ty_id = try self.resolveType(result_ty, .direct);
4189 return try self.constructComposite(result_ty_id, constituents);
4319 }4190 }
43204191
4321 fn indicesToIds(self: *NavGen, indices: []const u32) ![]IdRef {4192 fn indicesToIds(self: *NavGen, indices: []const u32) ![]IdRef {
4322 const ids = try self.gpa.alloc(IdRef, indices.len);4193 const ids = try self.gpa.alloc(IdRef, indices.len);
4323 errdefer self.gpa.free(ids);4194 errdefer self.gpa.free(ids);
4324 for (indices, ids) |index, *id| {4195 for (indices, ids) |index, *id| {
4325 id.* = try self.constInt(Type.u32, index, .direct);4196 id.* = try self.constInt(Type.u32, index);
4326 }4197 }
43274198
4328 return ids;4199 return ids;
...@@ -4676,7 +4547,7 @@ const NavGen = struct {...@@ -4676,7 +4547,7 @@ const NavGen = struct {
4676 break :blk result_id;4547 break :blk result_id;
4677 }4548 }
46784549
4679 const dst_ptr_ty_id = try self.ptrType(dst_ty, .Function);4550 const dst_ptr_ty_id = try self.ptrType(dst_ty, .Function, .indirect);
46804551
4681 const tmp_id = try self.alloc(src_ty, .{ .storage_class = .Function });4552 const tmp_id = try self.alloc(src_ty, .{ .storage_class = .Function });
4682 try self.store(src_ty, tmp_id, src_id, .{});4553 try self.store(src_ty, tmp_id, src_id, .{});
...@@ -4851,7 +4722,7 @@ const NavGen = struct {...@@ -4851,7 +4722,7 @@ const NavGen = struct {
4851 const elem_ptr_ty_id = try self.resolveType(elem_ptr_ty, .direct);4722 const elem_ptr_ty_id = try self.resolveType(elem_ptr_ty, .direct);
48524723
4853 const array_ptr_id = try self.resolve(ty_op.operand);4724 const array_ptr_id = try self.resolve(ty_op.operand);
4854 const len_id = try self.constInt(Type.usize, array_ty.arrayLen(zcu), .direct);4725 const len_id = try self.constInt(Type.usize, array_ty.arrayLen(zcu));
48554726
4856 const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(zcu))4727 const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(zcu))
4857 // Note: The pointer is something like *opaque{}, so we need to bitcast it to the element type.4728 // Note: The pointer is something like *opaque{}, so we need to bitcast it to the element type.
...@@ -4860,11 +4731,8 @@ const NavGen = struct {...@@ -4860,11 +4731,8 @@ const NavGen = struct {
4860 // Convert the pointer-to-array to a pointer to the first element.4731 // Convert the pointer-to-array to a pointer to the first element.
4861 try self.accessChain(elem_ptr_ty_id, array_ptr_id, &.{0});4732 try self.accessChain(elem_ptr_ty_id, array_ptr_id, &.{0});
48624733
4863 return try self.constructStruct(4734 const slice_ty_id = try self.resolveType(slice_ty, .direct);
4864 slice_ty,4735 return try self.constructComposite(slice_ty_id, &.{ elem_ptr_id, len_id });
4865 &.{ elem_ptr_ty, Type.usize },
4866 &.{ elem_ptr_id, len_id },
4867 );
4868 }4736 }
48694737
4870 fn airSlice(self: *NavGen, inst: Air.Inst.Index) !?IdRef {4738 fn airSlice(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
...@@ -4872,16 +4740,9 @@ const NavGen = struct {...@@ -4872,16 +4740,9 @@ const NavGen = struct {
4872 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;4740 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
4873 const ptr_id = try self.resolve(bin_op.lhs);4741 const ptr_id = try self.resolve(bin_op.lhs);
4874 const len_id = try self.resolve(bin_op.rhs);4742 const len_id = try self.resolve(bin_op.rhs);
4875 const ptr_ty = self.typeOf(bin_op.lhs);
4876 const slice_ty = self.typeOfIndex(inst);4743 const slice_ty = self.typeOfIndex(inst);
48774744 const slice_ty_id = try self.resolveType(slice_ty, .direct);
4878 // Note: Types should not need to be converted to direct, these types4745 return try self.constructComposite(slice_ty_id, &.{ ptr_id, len_id });
4879 // dont need to be converted.
4880 return try self.constructStruct(
4881 slice_ty,
4882 &.{ ptr_ty, Type.usize },
4883 &.{ ptr_id, len_id },
4884 );
4885 }4746 }
48864747
4887 fn airAggregateInit(self: *NavGen, inst: Air.Inst.Index) !?IdRef {4748 fn airAggregateInit(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
...@@ -4936,11 +4797,8 @@ const NavGen = struct {...@@ -4936,11 +4797,8 @@ const NavGen = struct {
4936 else => unreachable,4797 else => unreachable,
4937 }4798 }
49384799
4939 return try self.constructStruct(4800 const result_ty_id = try self.resolveType(result_ty, .direct);
4940 result_ty,4801 return try self.constructComposite(result_ty_id, constituents[0..index]);
4941 types[0..index],
4942 constituents[0..index],
4943 );
4944 },4802 },
4945 .vector => {4803 .vector => {
4946 const n_elems = result_ty.vectorLen(zcu);4804 const n_elems = result_ty.vectorLen(zcu);
...@@ -4951,7 +4809,8 @@ const NavGen = struct {...@@ -4951,7 +4809,8 @@ const NavGen = struct {
4951 elem_ids[i] = try self.resolve(element);4809 elem_ids[i] = try self.resolve(element);
4952 }4810 }
49534811
4954 return try self.constructVector(result_ty, elem_ids);4812 const result_ty_id = try self.resolveType(result_ty, .direct);
4813 return try self.constructComposite(result_ty_id, elem_ids);
4955 },4814 },
4956 .array => {4815 .array => {
4957 const array_info = result_ty.arrayInfo(zcu);4816 const array_info = result_ty.arrayInfo(zcu);
...@@ -4968,7 +4827,8 @@ const NavGen = struct {...@@ -4968,7 +4827,8 @@ const NavGen = struct {
4968 elem_ids[n_elems - 1] = try self.constant(array_info.elem_type, sentinel_val, .indirect);4827 elem_ids[n_elems - 1] = try self.constant(array_info.elem_type, sentinel_val, .indirect);
4969 }4828 }
49704829
4971 return try self.constructArray(result_ty, elem_ids);4830 const result_ty_id = try self.resolveType(result_ty, .direct);
4831 return try self.constructComposite(result_ty_id, elem_ids);
4972 },4832 },
4973 else => unreachable,4833 else => unreachable,
4974 }4834 }
...@@ -4984,7 +4844,7 @@ const NavGen = struct {...@@ -4984,7 +4844,7 @@ const NavGen = struct {
4984 const elem_ty = array_ty.childType(zcu);4844 const elem_ty = array_ty.childType(zcu);
4985 const abi_size = elem_ty.abiSize(zcu);4845 const abi_size = elem_ty.abiSize(zcu);
4986 const size = array_ty.arrayLenIncludingSentinel(zcu) * abi_size;4846 const size = array_ty.arrayLenIncludingSentinel(zcu) * abi_size;
4987 return try self.constInt(Type.usize, size, .direct);4847 return try self.constInt(Type.usize, size);
4988 },4848 },
4989 .many, .c => unreachable,4849 .many, .c => unreachable,
4990 }4850 }
...@@ -5060,7 +4920,7 @@ const NavGen = struct {...@@ -5060,7 +4920,7 @@ const NavGen = struct {
5060 const zcu = self.pt.zcu;4920 const zcu = self.pt.zcu;
5061 // Construct new pointer type for the resulting pointer4921 // Construct new pointer type for the resulting pointer
5062 const elem_ty = ptr_ty.elemType2(zcu); // use elemType() so that we get T for *[N]T.4922 const elem_ty = ptr_ty.elemType2(zcu); // use elemType() so that we get T for *[N]T.
5063 const elem_ptr_ty_id = try self.ptrType(elem_ty, self.spvStorageClass(ptr_ty.ptrAddressSpace(zcu)));4923 const elem_ptr_ty_id = try self.ptrType(elem_ty, self.spvStorageClass(ptr_ty.ptrAddressSpace(zcu)), .indirect);
5064 if (ptr_ty.isSinglePointer(zcu)) {4924 if (ptr_ty.isSinglePointer(zcu)) {
5065 // Pointer-to-array. In this case, the resulting pointer is not of the same type4925 // Pointer-to-array. In this case, the resulting pointer is not of the same type
5066 // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain.4926 // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain.
...@@ -5115,8 +4975,8 @@ const NavGen = struct {...@@ -5115,8 +4975,8 @@ const NavGen = struct {
5115 const is_vector = array_ty.isVector(zcu);4975 const is_vector = array_ty.isVector(zcu);
51164976
5117 const elem_repr: Repr = if (is_vector) .direct else .indirect;4977 const elem_repr: Repr = if (is_vector) .direct else .indirect;
5118 const ptr_array_ty_id = try self.ptrType2(array_ty, .Function, .direct);4978 const ptr_array_ty_id = try self.ptrType(array_ty, .Function, .direct);
5119 const ptr_elem_ty_id = try self.ptrType2(elem_ty, .Function, elem_repr);4979 const ptr_elem_ty_id = try self.ptrType(elem_ty, .Function, elem_repr);
51204980
5121 const tmp_id = self.spv.allocId();4981 const tmp_id = self.spv.allocId();
5122 try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{4982 try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{
...@@ -5171,7 +5031,7 @@ const NavGen = struct {...@@ -5171,7 +5031,7 @@ const NavGen = struct {
5171 const scalar_ty = vector_ty.scalarType(zcu);5031 const scalar_ty = vector_ty.scalarType(zcu);
51725032
5173 const storage_class = self.spvStorageClass(vector_ptr_ty.ptrAddressSpace(zcu));5033 const storage_class = self.spvStorageClass(vector_ptr_ty.ptrAddressSpace(zcu));
5174 const scalar_ptr_ty_id = try self.ptrType(scalar_ty, storage_class);5034 const scalar_ptr_ty_id = try self.ptrType(scalar_ty, storage_class, .indirect);
51755035
5176 const vector_ptr = try self.resolve(data.vector_ptr);5036 const vector_ptr = try self.resolve(data.vector_ptr);
5177 const index = try self.resolve(extra.lhs);5037 const index = try self.resolve(extra.lhs);
...@@ -5193,7 +5053,7 @@ const NavGen = struct {...@@ -5193,7 +5053,7 @@ const NavGen = struct {
5193 if (layout.tag_size == 0) return;5053 if (layout.tag_size == 0) return;
51945054
5195 const tag_ty = un_ty.unionTagTypeSafety(zcu).?;5055 const tag_ty = un_ty.unionTagTypeSafety(zcu).?;
5196 const tag_ptr_ty_id = try self.ptrType(tag_ty, self.spvStorageClass(un_ptr_ty.ptrAddressSpace(zcu)));5056 const tag_ptr_ty_id = try self.ptrType(tag_ty, self.spvStorageClass(un_ptr_ty.ptrAddressSpace(zcu)), .indirect);
51975057
5198 const union_ptr_id = try self.resolve(bin_op.lhs);5058 const union_ptr_id = try self.resolve(bin_op.lhs);
5199 const new_tag_id = try self.resolve(bin_op.rhs);5059 const new_tag_id = try self.resolve(bin_op.rhs);
...@@ -5252,23 +5112,23 @@ const NavGen = struct {...@@ -5252,23 +5112,23 @@ const NavGen = struct {
5252 } else 0;5112 } else 0;
52535113
5254 if (!layout.has_payload) {5114 if (!layout.has_payload) {
5255 return try self.constInt(tag_ty, tag_int, .direct);5115 return try self.constInt(tag_ty, tag_int);
5256 }5116 }
52575117
5258 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });5118 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });
52595119
5260 if (layout.tag_size != 0) {5120 if (layout.tag_size != 0) {
5261 const tag_ptr_ty_id = try self.ptrType(tag_ty, .Function);5121 const tag_ptr_ty_id = try self.ptrType(tag_ty, .Function, .indirect);
5262 const ptr_id = try self.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});5122 const ptr_id = try self.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});
5263 const tag_id = try self.constInt(tag_ty, tag_int, .direct);5123 const tag_id = try self.constInt(tag_ty, tag_int);
5264 try self.store(tag_ty, ptr_id, tag_id, .{});5124 try self.store(tag_ty, ptr_id, tag_id, .{});
5265 }5125 }
52665126
5267 const payload_ty = Type.fromInterned(union_ty.field_types.get(ip)[active_field]);5127 const payload_ty = Type.fromInterned(union_ty.field_types.get(ip)[active_field]);
5268 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {5128 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
5269 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, .Function);5129 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, .Function, .indirect);
5270 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});5130 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
5271 const active_pl_ptr_ty_id = try self.ptrType(payload_ty, .Function);5131 const active_pl_ptr_ty_id = try self.ptrType(payload_ty, .Function, .indirect);
5272 const active_pl_ptr_id = self.spv.allocId();5132 const active_pl_ptr_id = self.spv.allocId();
5273 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{5133 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
5274 .id_result_type = active_pl_ptr_ty_id,5134 .id_result_type = active_pl_ptr_ty_id,
...@@ -5332,10 +5192,10 @@ const NavGen = struct {...@@ -5332,10 +5192,10 @@ const NavGen = struct {
5332 const tmp_id = try self.alloc(object_ty, .{ .storage_class = .Function });5192 const tmp_id = try self.alloc(object_ty, .{ .storage_class = .Function });
5333 try self.store(object_ty, tmp_id, object_id, .{});5193 try self.store(object_ty, tmp_id, object_id, .{});
53345194
5335 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, .Function);5195 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, .Function, .indirect);
5336 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});5196 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
53375197
5338 const active_pl_ptr_ty_id = try self.ptrType(field_ty, .Function);5198 const active_pl_ptr_ty_id = try self.ptrType(field_ty, .Function, .indirect);
5339 const active_pl_ptr_id = self.spv.allocId();5199 const active_pl_ptr_id = self.spv.allocId();
5340 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{5200 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
5341 .id_result_type = active_pl_ptr_ty_id,5201 .id_result_type = active_pl_ptr_ty_id,
...@@ -5365,7 +5225,7 @@ const NavGen = struct {...@@ -5365,7 +5225,7 @@ const NavGen = struct {
5365 const base_ptr_int = base_ptr_int: {5225 const base_ptr_int = base_ptr_int: {
5366 if (field_offset == 0) break :base_ptr_int field_ptr_int;5226 if (field_offset == 0) break :base_ptr_int field_ptr_int;
53675227
5368 const field_offset_id = try self.constInt(Type.usize, field_offset, .direct);5228 const field_offset_id = try self.constInt(Type.usize, field_offset);
5369 const field_ptr_tmp = Temporary.init(Type.usize, field_ptr_int);5229 const field_ptr_tmp = Temporary.init(Type.usize, field_ptr_int);
5370 const field_offset_tmp = Temporary.init(Type.usize, field_offset_id);5230 const field_offset_tmp = Temporary.init(Type.usize, field_offset_id);
5371 const result = try self.buildBinary(.i_sub, field_ptr_tmp, field_offset_tmp);5231 const result = try self.buildBinary(.i_sub, field_ptr_tmp, field_offset_tmp);
...@@ -5415,7 +5275,7 @@ const NavGen = struct {...@@ -5415,7 +5275,7 @@ const NavGen = struct {
5415 }5275 }
54165276
5417 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(zcu));5277 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(zcu));
5418 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, storage_class);5278 const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, storage_class, .indirect);
5419 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});5279 const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
54205280
5421 const active_pl_ptr_id = self.spv.allocId();5281 const active_pl_ptr_id = self.spv.allocId();
...@@ -5456,7 +5316,7 @@ const NavGen = struct {...@@ -5456,7 +5316,7 @@ const NavGen = struct {
5456 ty: Type,5316 ty: Type,
5457 options: AllocOptions,5317 options: AllocOptions,
5458 ) !IdRef {5318 ) !IdRef {
5459 const ptr_fn_ty_id = try self.ptrType(ty, .Function);5319 const ptr_fn_ty_id = try self.ptrType(ty, .Function, .indirect);
54605320
5461 // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to5321 // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to
5462 // directly generate them into func.prologue instead of the body.5322 // directly generate them into func.prologue instead of the body.
...@@ -5475,7 +5335,7 @@ const NavGen = struct {...@@ -5475,7 +5335,7 @@ const NavGen = struct {
54755335
5476 switch (options.storage_class) {5336 switch (options.storage_class) {
5477 .Generic => {5337 .Generic => {
5478 const ptr_gn_ty_id = try self.ptrType(ty, .Generic);5338 const ptr_gn_ty_id = try self.ptrType(ty, .Generic, .indirect);
5479 // Convert to a generic pointer5339 // Convert to a generic pointer
5480 return self.castToGeneric(ptr_gn_ty_id, var_id);5340 return self.castToGeneric(ptr_gn_ty_id, var_id);
5481 },5341 },
...@@ -5724,7 +5584,7 @@ const NavGen = struct {...@@ -5724,7 +5584,7 @@ const NavGen = struct {
5724 assert(cf.block_stack.items.len > 0);5584 assert(cf.block_stack.items.len > 0);
57255585
5726 // Check if the target of the branch was this current block.5586 // Check if the target of the branch was this current block.
5727 const this_block = try self.constInt(Type.u32, @intFromEnum(inst), .direct);5587 const this_block = try self.constInt(Type.u32, @intFromEnum(inst));
5728 const jump_to_this_block_id = self.spv.allocId();5588 const jump_to_this_block_id = self.spv.allocId();
5729 const bool_ty_id = try self.resolveType(Type.bool, .direct);5589 const bool_ty_id = try self.resolveType(Type.bool, .direct);
5730 try self.func.body.emit(self.spv.gpa, .OpIEqual, .{5590 try self.func.body.emit(self.spv.gpa, .OpIEqual, .{
...@@ -5804,7 +5664,7 @@ const NavGen = struct {...@@ -5804,7 +5664,7 @@ const NavGen = struct {
5804 try self.store(operand_ty, block_result_var_id, operand_id, .{});5664 try self.store(operand_ty, block_result_var_id, operand_id, .{});
5805 }5665 }
58065666
5807 const next_block = try self.constInt(Type.u32, @intFromEnum(br.block_inst), .direct);5667 const next_block = try self.constInt(Type.u32, @intFromEnum(br.block_inst));
5808 try self.structuredBreak(next_block);5668 try self.structuredBreak(next_block);
5809 },5669 },
5810 .unstructured => |cf| {5670 .unstructured => |cf| {
...@@ -5968,7 +5828,7 @@ const NavGen = struct {...@@ -5968,7 +5828,7 @@ const NavGen = struct {
5968 // Functions with an empty error set are emitted with an error code5828 // Functions with an empty error set are emitted with an error code
5969 // return type and return zero so they can be function pointers coerced5829 // return type and return zero so they can be function pointers coerced
5970 // to functions that return anyerror.5830 // to functions that return anyerror.
5971 const no_err_id = try self.constInt(Type.anyerror, 0, .direct);5831 const no_err_id = try self.constInt(Type.anyerror, 0);
5972 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });5832 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });
5973 } else {5833 } else {
5974 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});5834 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});
...@@ -5992,7 +5852,7 @@ const NavGen = struct {...@@ -5992,7 +5852,7 @@ const NavGen = struct {
5992 // Functions with an empty error set are emitted with an error code5852 // Functions with an empty error set are emitted with an error code
5993 // return type and return zero so they can be function pointers coerced5853 // return type and return zero so they can be function pointers coerced
5994 // to functions that return anyerror.5854 // to functions that return anyerror.
5995 const no_err_id = try self.constInt(Type.anyerror, 0, .direct);5855 const no_err_id = try self.constInt(Type.anyerror, 0);
5996 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });5856 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });
5997 } else {5857 } else {
5998 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});5858 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});
...@@ -6026,7 +5886,7 @@ const NavGen = struct {...@@ -6026,7 +5886,7 @@ const NavGen = struct {
6026 else5886 else
6027 err_union_id;5887 err_union_id;
60285888
6029 const zero_id = try self.constInt(Type.anyerror, 0, .direct);5889 const zero_id = try self.constInt(Type.anyerror, 0);
6030 const is_err_id = self.spv.allocId();5890 const is_err_id = self.spv.allocId();
6031 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{5891 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
6032 .id_result_type = bool_ty_id,5892 .id_result_type = bool_ty_id,
...@@ -6134,7 +5994,8 @@ const NavGen = struct {...@@ -6134,7 +5994,8 @@ const NavGen = struct {
6134 types[eu_layout.errorFieldIndex()] = Type.anyerror;5994 types[eu_layout.errorFieldIndex()] = Type.anyerror;
6135 types[eu_layout.payloadFieldIndex()] = payload_ty;5995 types[eu_layout.payloadFieldIndex()] = payload_ty;
61365996
6137 return try self.constructStruct(err_union_ty, &types, &members);5997 const err_union_ty_id = try self.resolveType(err_union_ty, .direct);
5998 return try self.constructComposite(err_union_ty_id, &members);
6138 }5999 }
61396000
6140 fn airWrapErrUnionPayload(self: *NavGen, inst: Air.Inst.Index) !?IdRef {6001 fn airWrapErrUnionPayload(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
...@@ -6145,18 +6006,19 @@ const NavGen = struct {...@@ -6145,18 +6006,19 @@ const NavGen = struct {
6145 const eu_layout = self.errorUnionLayout(payload_ty);6006 const eu_layout = self.errorUnionLayout(payload_ty);
61466007
6147 if (!eu_layout.payload_has_bits) {6008 if (!eu_layout.payload_has_bits) {
6148 return try self.constInt(Type.anyerror, 0, .direct);6009 return try self.constInt(Type.anyerror, 0);
6149 }6010 }
61506011
6151 var members: [2]IdRef = undefined;6012 var members: [2]IdRef = undefined;
6152 members[eu_layout.errorFieldIndex()] = try self.constInt(Type.anyerror, 0, .direct);6013 members[eu_layout.errorFieldIndex()] = try self.constInt(Type.anyerror, 0);
6153 members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id);6014 members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id);
61546015
6155 var types: [2]Type = undefined;6016 var types: [2]Type = undefined;
6156 types[eu_layout.errorFieldIndex()] = Type.anyerror;6017 types[eu_layout.errorFieldIndex()] = Type.anyerror;
6157 types[eu_layout.payloadFieldIndex()] = payload_ty;6018 types[eu_layout.payloadFieldIndex()] = payload_ty;
61586019
6159 return try self.constructStruct(err_union_ty, &types, &members);6020 const err_union_ty_id = try self.resolveType(err_union_ty, .direct);
6021 return try self.constructComposite(err_union_ty_id, &members);
6160 }6022 }
61616023
6162 fn airIsNull(self: *NavGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?IdRef {6024 fn airIsNull(self: *NavGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?IdRef {
...@@ -6204,7 +6066,7 @@ const NavGen = struct {...@@ -6204,7 +6066,7 @@ const NavGen = struct {
6204 if (is_pointer) {6066 if (is_pointer) {
6205 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {6067 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
6206 const storage_class = self.spvStorageClass(operand_ty.ptrAddressSpace(zcu));6068 const storage_class = self.spvStorageClass(operand_ty.ptrAddressSpace(zcu));
6207 const bool_ptr_ty_id = try self.ptrType(Type.bool, storage_class);6069 const bool_ptr_ty_id = try self.ptrType(Type.bool, storage_class, .indirect);
6208 const tag_ptr_id = try self.accessChain(bool_ptr_ty_id, operand_id, &.{1});6070 const tag_ptr_id = try self.accessChain(bool_ptr_ty_id, operand_id, &.{1});
6209 break :blk try self.load(Type.bool, tag_ptr_id, .{});6071 break :blk try self.load(Type.bool, tag_ptr_id, .{});
6210 }6072 }
...@@ -6267,7 +6129,7 @@ const NavGen = struct {...@@ -6267,7 +6129,7 @@ const NavGen = struct {
6267 .id_result_type = bool_ty_id,6129 .id_result_type = bool_ty_id,
6268 .id_result = result_id,6130 .id_result = result_id,
6269 .operand_1 = error_id,6131 .operand_1 = error_id,
6270 .operand_2 = try self.constInt(Type.anyerror, 0, .direct),6132 .operand_2 = try self.constInt(Type.anyerror, 0),
6271 },6133 },
6272 ),6134 ),
6273 }6135 }
...@@ -6335,8 +6197,8 @@ const NavGen = struct {...@@ -6335,8 +6197,8 @@ const NavGen = struct {
63356197
6336 const payload_id = try self.convertToIndirect(payload_ty, operand_id);6198 const payload_id = try self.convertToIndirect(payload_ty, operand_id);
6337 const members = [_]IdRef{ payload_id, try self.constBool(true, .indirect) };6199 const members = [_]IdRef{ payload_id, try self.constBool(true, .indirect) };
6338 const types = [_]Type{ payload_ty, Type.bool };6200 const optional_ty_id = try self.resolveType(optional_ty, .direct);
6339 return try self.constructStruct(optional_ty, &types, &members);6201 return try self.constructComposite(optional_ty_id, &members);
6340 }6202 }
63416203
6342 fn airSwitchBr(self: *NavGen, inst: Air.Inst.Index) !void {6204 fn airSwitchBr(self: *NavGen, inst: Air.Inst.Index) !void {
...@@ -6752,13 +6614,13 @@ const NavGen = struct {...@@ -6752,13 +6614,13 @@ const NavGen = struct {
67526614
6753 fn builtin3D(self: *NavGen, result_ty: Type, builtin: spec.BuiltIn, dimension: u32, out_of_range_value: anytype) !IdRef {6615 fn builtin3D(self: *NavGen, result_ty: Type, builtin: spec.BuiltIn, dimension: u32, out_of_range_value: anytype) !IdRef {
6754 if (dimension >= 3) {6616 if (dimension >= 3) {
6755 return try self.constInt(result_ty, out_of_range_value, .direct);6617 return try self.constInt(result_ty, out_of_range_value);
6756 }6618 }
6757 const vec_ty = try self.pt.vectorType(.{6619 const vec_ty = try self.pt.vectorType(.{
6758 .len = 3,6620 .len = 3,
6759 .child = result_ty.toIntern(),6621 .child = result_ty.toIntern(),
6760 });6622 });
6761 const ptr_ty_id = try self.ptrType(vec_ty, .Input);6623 const ptr_ty_id = try self.ptrType(vec_ty, .Input, .indirect);
6762 const spv_decl_index = try self.spv.builtin(ptr_ty_id, builtin);6624 const spv_decl_index = try self.spv.builtin(ptr_ty_id, builtin);
6763 try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {});6625 try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {});
6764 const ptr = self.spv.declPtr(spv_decl_index).result_id;6626 const ptr = self.spv.declPtr(spv_decl_index).result_id;
src/codegen/spirv/Module.zig+83-7
...@@ -10,6 +10,8 @@ const Module = @This();...@@ -10,6 +10,8 @@ const Module = @This();
10const std = @import("std");10const std = @import("std");
11const Allocator = std.mem.Allocator;11const Allocator = std.mem.Allocator;
12const assert = std.debug.assert;12const assert = std.debug.assert;
13const autoHashStrat = std.hash.autoHashStrat;
14const Wyhash = std.hash.Wyhash;
1315
14const spec = @import("spec.zig");16const spec = @import("spec.zig");
15const Word = spec.Word;17const Word = spec.Word;
...@@ -19,6 +21,19 @@ const IdResultType = spec.IdResultType;...@@ -19,6 +21,19 @@ const IdResultType = spec.IdResultType;
1921
20const Section = @import("Section.zig");22const Section = @import("Section.zig");
2123
24/// Helper HashMap type to hash deeply
25fn DeepHashMap(K: type, V: type) type {
26 return std.HashMapUnmanaged(K, V, struct {
27 pub fn hash(ctx: @This(), key: K) u64 {
28 _ = ctx;
29 var hasher = Wyhash.init(0);
30 autoHashStrat(&hasher, key, .Deep);
31 return hasher.final();
32 }
33 pub const eql = std.hash_map.getAutoEqlFn(K, @This());
34 }, std.hash_map.default_max_load_percentage);
35}
36
22/// This structure represents a function that isc in-progress of being emitted.37/// This structure represents a function that isc in-progress of being emitted.
23/// Commonly, the contents of this structure will be merged with the appropriate38/// Commonly, the contents of this structure will be merged with the appropriate
24/// sections of the module and re-used. Note that the SPIR-V module system makes39/// sections of the module and re-used. Note that the SPIR-V module system makes
...@@ -159,8 +174,13 @@ cache: struct {...@@ -159,8 +174,13 @@ cache: struct {
159 // This cache is required so that @Vector(X, u1) in direct representation has the174 // This cache is required so that @Vector(X, u1) in direct representation has the
160 // same ID as @Vector(X, bool) in indirect representation.175 // same ID as @Vector(X, bool) in indirect representation.
161 vector_types: std.AutoHashMapUnmanaged(struct { IdRef, u32 }, IdRef) = .empty,176 vector_types: std.AutoHashMapUnmanaged(struct { IdRef, u32 }, IdRef) = .empty,
177 array_types: std.AutoHashMapUnmanaged(struct { IdRef, IdRef }, IdRef) = .empty,
178 function_types: DeepHashMap(struct { IdRef, []const IdRef }, IdRef) = .empty,
162179
163 builtins: std.AutoHashMapUnmanaged(struct { IdRef, spec.BuiltIn }, Decl.Index) = .empty,180 builtins: std.AutoHashMapUnmanaged(struct { IdRef, spec.BuiltIn }, Decl.Index) = .empty,
181 decorations: std.AutoHashMapUnmanaged(struct { IdRef, spec.Decoration }, void) = .empty,
182
183 bool_const: [2]?IdRef = .{ null, null },
164} = .{},184} = .{},
165185
166/// Set of Decls, referred to by Decl.Index.186/// Set of Decls, referred to by Decl.Index.
...@@ -201,7 +221,10 @@ pub fn deinit(self: *Module) void {...@@ -201,7 +221,10 @@ pub fn deinit(self: *Module) void {
201 self.cache.int_types.deinit(self.gpa);221 self.cache.int_types.deinit(self.gpa);
202 self.cache.float_types.deinit(self.gpa);222 self.cache.float_types.deinit(self.gpa);
203 self.cache.vector_types.deinit(self.gpa);223 self.cache.vector_types.deinit(self.gpa);
224 self.cache.array_types.deinit(self.gpa);
225 self.cache.function_types.deinit(self.gpa);
204 self.cache.builtins.deinit(self.gpa);226 self.cache.builtins.deinit(self.gpa);
227 self.cache.decorations.deinit(self.gpa);
205228
206 self.decls.deinit(self.gpa);229 self.decls.deinit(self.gpa);
207 self.decl_deps.deinit(self.gpa);230 self.decl_deps.deinit(self.gpa);
...@@ -477,20 +500,69 @@ pub fn floatType(self: *Module, bits: u16) !IdRef {...@@ -477,20 +500,69 @@ pub fn floatType(self: *Module, bits: u16) !IdRef {
477 return entry.value_ptr.*;500 return entry.value_ptr.*;
478}501}
479502
480pub fn vectorType(self: *Module, len: u32, child_id: IdRef) !IdRef {503pub fn vectorType(self: *Module, len: u32, child_ty_id: IdRef) !IdRef {
481 const entry = try self.cache.vector_types.getOrPut(self.gpa, .{ child_id, len });504 const entry = try self.cache.vector_types.getOrPut(self.gpa, .{ child_ty_id, len });
482 if (!entry.found_existing) {505 if (!entry.found_existing) {
483 const result_id = self.allocId();506 const result_id = self.allocId();
484 entry.value_ptr.* = result_id;507 entry.value_ptr.* = result_id;
485 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeVector, .{508 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeVector, .{
486 .id_result = result_id,509 .id_result = result_id,
487 .component_type = child_id,510 .component_type = child_ty_id,
488 .component_count = len,511 .component_count = len,
489 });512 });
490 }513 }
491 return entry.value_ptr.*;514 return entry.value_ptr.*;
492}515}
493516
517pub fn arrayType(self: *Module, len_id: IdRef, child_ty_id: IdRef) !IdRef {
518 const entry = try self.cache.array_types.getOrPut(self.gpa, .{ child_ty_id, len_id });
519 if (!entry.found_existing) {
520 const result_id = self.allocId();
521 entry.value_ptr.* = result_id;
522 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeArray, .{
523 .id_result = result_id,
524 .element_type = child_ty_id,
525 .length = len_id,
526 });
527 }
528 return entry.value_ptr.*;
529}
530
531pub fn functionType(self: *Module, return_ty_id: IdRef, param_type_ids: []const IdRef) !IdRef {
532 const entry = try self.cache.function_types.getOrPut(self.gpa, .{ return_ty_id, param_type_ids });
533 if (!entry.found_existing) {
534 const result_id = self.allocId();
535 entry.value_ptr.* = result_id;
536 try self.sections.types_globals_constants.emit(self.gpa, .OpTypeFunction, .{
537 .id_result = result_id,
538 .return_type = return_ty_id,
539 .id_ref_2 = param_type_ids,
540 });
541 }
542 return entry.value_ptr.*;
543}
544
545pub fn constBool(self: *Module, value: bool) !IdRef {
546 if (self.cache.bool_const[@intFromBool(value)]) |b| return b;
547
548 const result_ty_id = try self.boolType();
549 const result_id = self.allocId();
550 self.cache.bool_const[@intFromBool(value)] = result_id;
551
552 switch (value) {
553 inline else => |value_ct| try self.sections.types_globals_constants.emit(
554 self.gpa,
555 if (value_ct) .OpConstantTrue else .OpConstantFalse,
556 .{
557 .id_result_type = result_ty_id,
558 .id_result = result_id,
559 },
560 ),
561 }
562
563 return result_id;
564}
565
494/// Return a pointer to a builtin variable. `result_ty_id` must be a **pointer**566/// Return a pointer to a builtin variable. `result_ty_id` must be a **pointer**
495/// with storage class `.Input`.567/// with storage class `.Input`.
496pub fn builtin(self: *Module, result_ty_id: IdRef, spirv_builtin: spec.BuiltIn) !Decl.Index {568pub fn builtin(self: *Module, result_ty_id: IdRef, spirv_builtin: spec.BuiltIn) !Decl.Index {
...@@ -534,13 +606,17 @@ pub fn decorate(...@@ -534,13 +606,17 @@ pub fn decorate(
534 target: IdRef,606 target: IdRef,
535 decoration: spec.Decoration.Extended,607 decoration: spec.Decoration.Extended,
536) !void {608) !void {
537 try self.sections.annotations.emit(self.gpa, .OpDecorate, .{609 const entry = try self.cache.decorations.getOrPut(self.gpa, .{ target, decoration });
538 .target = target,610 if (!entry.found_existing) {
539 .decoration = decoration,611 try self.sections.annotations.emit(self.gpa, .OpDecorate, .{
540 });612 .target = target,
613 .decoration = decoration,
614 });
615 }
541}616}
542617
543/// Decorate a result-id which is a member of some struct.618/// Decorate a result-id which is a member of some struct.
619/// We really don't have to and shouldn't need to cache this.
544pub fn decorateMember(620pub fn decorateMember(
545 self: *Module,621 self: *Module,
546 structure_type: IdRef,622 structure_type: IdRef,
src/link/SpirV/deduplicate.zig+1-1
...@@ -155,7 +155,7 @@ const ModuleInfo = struct {...@@ -155,7 +155,7 @@ const ModuleInfo = struct {
155 }155 }
156 }156 }
157157
158 return ModuleInfo{158 return .{
159 .entities = entities.unmanaged,159 .entities = entities.unmanaged,
160 .operand_is_id = operand_is_id,160 .operand_is_id = operand_is_id,
161 // There may be unrelated decorations at the end, so make sure to161 // There may be unrelated decorations at the end, so make sure to
src/link/SpirV/prune_unused.zig+1-1
...@@ -166,7 +166,7 @@ const ModuleInfo = struct {...@@ -166,7 +166,7 @@ const ModuleInfo = struct {
166 return error.InvalidPhysicalFormat;166 return error.InvalidPhysicalFormat;
167 }167 }
168168
169 return ModuleInfo{169 return .{
170 .functions = functions.unmanaged,170 .functions = functions.unmanaged,
171 .callee_store = callee_store.items,171 .callee_store = callee_store.items,
172 .result_id_to_code_offset = result_id_to_code_offset.unmanaged,172 .result_id_to_code_offset = result_id_to_code_offset.unmanaged,