authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-04-04 23:03:01+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-04-06 13:37:39+02:00
log188922a5448417d1939023b1eab7f70fa1953dde
treed636f03bb030b070bc2e14aba4844f2e9c61cd4e
parent42c7e752e1eae7663068e9c52ad77f7383d977e9
signaturebadge-check Signed by SSH key SHA256:ZS52FNyUv2WUXvO4njmVaFVO46RHojFuOrxRc4LuKzg

spirv: remove cache usage for constants


2 files changed, 407 insertions(+), 393 deletions(-)

src/codegen/spirv.zig+393-373
......@@ -41,6 +41,8 @@ const SpvTypeInfo = struct {
4141
4242const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, SpvTypeInfo);
4343
44const InternMap = std.AutoHashMapUnmanaged(struct { InternPool.Index, DeclGen.Repr }, IdResult);
45
4446const ControlFlow = union(enum) {
4547 const Structured = struct {
4648 /// This type indicates the way that a block is terminated. The
......@@ -171,6 +173,8 @@ pub const Object = struct {
171173 /// of the SPIR-V module.
172174 type_map: TypeMap = .{},
173175
176 intern_map: InternMap = .{},
177
174178 pub fn init(gpa: Allocator) Object {
175179 return .{
176180 .gpa = gpa,
......@@ -183,6 +187,7 @@ pub const Object = struct {
183187 self.decl_link.deinit(self.gpa);
184188 self.anon_decl_link.deinit(self.gpa);
185189 self.type_map.deinit(self.gpa);
190 self.intern_map.deinit(self.gpa);
186191 }
187192
188193 fn genDecl(
......@@ -205,6 +210,7 @@ pub const Object = struct {
205210 .air = air,
206211 .liveness = liveness,
207212 .type_map = &self.type_map,
213 .intern_map = &self.intern_map,
208214 .control_flow = switch (structured_cfg) {
209215 true => .{ .structured = .{} },
210216 false => .{ .unstructured = .{} },
......@@ -313,6 +319,8 @@ const DeclGen = struct {
313319 /// See Object.type_map
314320 type_map: *TypeMap,
315321
322 intern_map: *InternMap,
323
316324 /// Child types of pointers that are currently in progress of being resolved. If a pointer
317325 /// is already in this map, its recursive.
318326 wip_pointers: std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, CacheRef) = .{},
......@@ -696,14 +704,25 @@ const DeclGen = struct {
696704
697705 /// Emits a bool constant in a particular representation.
698706 fn constBool(self: *DeclGen, value: bool, repr: Repr) !IdRef {
707 // TODO: Cache?
708
709 const section = &self.spv.sections.types_globals_constants;
699710 switch (repr) {
700711 .indirect => {
701 const int_ty_ref = try self.intType(.unsigned, 1);
702 return self.constInt(int_ty_ref, @intFromBool(value));
712 return try self.constInt(Type.u1, @intFromBool(value), .indirect);
703713 },
704714 .direct => {
705 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
706 return self.spv.constBool(bool_ty_ref, value);
715 const result_ty_id = try self.resolveType2(Type.bool, .direct);
716 const result_id = self.spv.allocId();
717 const operands = .{
718 .id_result_type = result_ty_id,
719 .id_result = result_id,
720 };
721 switch (value) {
722 true => try section.emit(self.spv.gpa, .OpConstantTrue, operands),
723 false => try section.emit(self.spv.gpa, .OpConstantFalse, operands),
724 }
725 return result_id;
707726 },
708727 }
709728 }
......@@ -711,68 +730,63 @@ const DeclGen = struct {
711730 /// Emits an integer constant.
712731 /// This function, unlike SpvModule.constInt, takes care to bitcast
713732 /// the value to an unsigned int first for Kernels.
714 fn constInt(self: *DeclGen, ty_ref: CacheRef, value: anytype) !IdRef {
715 switch (self.spv.cache.lookup(ty_ref)) {
716 .vector_type => |vec_type| {
717 const elem_ids = try self.gpa.alloc(IdRef, vec_type.component_count);
718 defer self.gpa.free(elem_ids);
719 const int_value = try self.constInt(vec_type.component_type, value);
720 @memset(elem_ids, int_value);
721
722 const constituents_id = self.spv.allocId();
723 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
724 .id_result_type = self.typeId(ty_ref),
725 .id_result = constituents_id,
726 .constituents = elem_ids,
727 });
728 return constituents_id;
729 },
730 else => {},
731 }
733 fn constInt(self: *DeclGen, ty: Type, value: anytype, repr: Repr) !IdRef {
734 // TODO: Cache?
735 const mod = self.module;
736 const scalar_ty = ty.scalarType(mod);
737 const int_info = scalar_ty.intInfo(mod);
738 // Use backing bits so that negatives are sign extended
739 const backing_bits = self.backingIntBits(int_info.bits).?; // Assertion failure means big int
740
741 const bits: u64 = switch (int_info.signedness) {
742 // Intcast needed to silence compile errors for when the wrong path is compiled.
743 // Lazy fix.
744 .signed => @bitCast(@as(i64, @intCast(value))),
745 .unsigned => @as(u64, @intCast(value)),
746 };
732747
733 if (value < 0) {
734 const ty = self.spv.cache.lookup(ty_ref).int_type;
735 // Manually truncate the value so that the resulting value
736 // fits within the unsigned type.
737 const bits: u64 = @bitCast(@as(i64, @intCast(value)));
738 const truncated_bits = if (ty.bits == 64)
739 bits
740 else
741 bits & (@as(u64, 1) << @intCast(ty.bits)) - 1;
742 return try self.spv.constInt(ty_ref, truncated_bits);
743 } else {
744 return try self.spv.constInt(ty_ref, value);
748 // Manually truncate the value to the right amount of bits.
749 const truncated_bits = if (backing_bits == 64)
750 bits
751 else
752 bits & (@as(u64, 1) << @intCast(backing_bits)) - 1;
753
754 const result_ty_id = try self.resolveType2(scalar_ty, repr);
755 const result_id = self.spv.allocId();
756
757 const section = &self.spv.sections.types_globals_constants;
758 switch (backing_bits) {
759 0 => unreachable, // u0 is comptime
760 1...32 => try section.emit(self.spv.gpa, .OpConstant, .{
761 .id_result_type = result_ty_id,
762 .id_result = result_id,
763 .value = .{ .uint32 = @truncate(truncated_bits) },
764 }),
765 33...64 => try section.emit(self.spv.gpa, .OpConstant, .{
766 .id_result_type = result_ty_id,
767 .id_result = result_id,
768 .value = .{ .uint64 = truncated_bits },
769 }),
770 else => unreachable, // TODO: Large integer constants
745771 }
746 }
747772
748 /// Emits a float constant
749 fn constFloat(self: *DeclGen, ty_ref: CacheRef, value: f128) !IdRef {
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 => {},
773 if (!ty.isVector(mod)) {
774 return result_id;
766775 }
767776
768 const ty = self.spv.cache.lookup(ty_ref).float_type;
769 return switch (ty.bits) {
770 16 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float16 = @floatCast(value) } } }),
771 32 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float32 = @floatCast(value) } } }),
772 64 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float64 = @floatCast(value) } } }),
773 80, 128 => unreachable, // TODO
774 else => unreachable,
775 };
777 const n = ty.vectorLen(mod);
778 const ids = try self.gpa.alloc(IdRef, n);
779 defer self.gpa.free(ids);
780 @memset(ids, result_id);
781
782 const vec_ty_id = try self.resolveType2(ty, repr);
783 const vec_result_id = self.spv.allocId();
784 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
785 .id_result_type = vec_ty_id,
786 .id_result = vec_result_id,
787 .constituents = ids,
788 });
789 return vec_result_id;
776790 }
777791
778792 /// Construct a struct at runtime.
......@@ -852,258 +866,279 @@ const DeclGen = struct {
852866 /// is done by emitting a sequence of instructions that initialize the value.
853867 //
854868 /// This function should only be called during function code generation.
855 fn constant(self: *DeclGen, ty: Type, arg_val: Value, repr: Repr) !IdRef {
869 fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef {
870 // Note: Using intern_map can only be used with constants that DO NOT generate any runtime code!!
871 // Ideally that should be all constants in the future, or it should be cleaned up somehow. For
872 // now, only use the intern_map on case-by-case basis by breaking to :cache.
873 if (self.intern_map.get(.{ val.toIntern(), repr })) |id| {
874 return id;
875 }
876
856877 const mod = self.module;
857878 const target = self.getTarget();
858879 const result_ty_ref = try self.resolveType(ty, repr);
880 const result_ty_id = self.typeId(result_ty_ref);
859881 const ip = &mod.intern_pool;
860882
861 const val = arg_val;
862
863 log.debug("constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod) });
883 log.debug("lowering constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod) });
864884 if (val.isUndefDeep(mod)) {
865 return self.spv.constUndef(result_ty_ref);
866 }
867
868 switch (ip.indexToKey(val.toIntern())) {
869 .int_type,
870 .ptr_type,
871 .array_type,
872 .vector_type,
873 .opt_type,
874 .anyframe_type,
875 .error_union_type,
876 .simple_type,
877 .struct_type,
878 .anon_struct_type,
879 .union_type,
880 .opaque_type,
881 .enum_type,
882 .func_type,
883 .error_set_type,
884 .inferred_error_set_type,
885 => unreachable, // types, not values
886
887 .undef => unreachable, // handled above
888
889 .variable,
890 .extern_func,
891 .func,
892 .enum_literal,
893 .empty_enum_value,
894 => unreachable, // non-runtime values
895
896 .simple_value => |simple_value| switch (simple_value) {
897 .undefined,
898 .void,
899 .null,
900 .empty_struct,
901 .@"unreachable",
902 .generic_poison,
885 return self.spv.constUndef(result_ty_id);
886 }
887
888 const section = &self.spv.sections.types_globals_constants;
889
890 const cacheable_id = cache: {
891 switch (ip.indexToKey(val.toIntern())) {
892 .int_type,
893 .ptr_type,
894 .array_type,
895 .vector_type,
896 .opt_type,
897 .anyframe_type,
898 .error_union_type,
899 .simple_type,
900 .struct_type,
901 .anon_struct_type,
902 .union_type,
903 .opaque_type,
904 .enum_type,
905 .func_type,
906 .error_set_type,
907 .inferred_error_set_type,
908 => unreachable, // types, not values
909
910 .undef => unreachable, // handled above
911
912 .variable,
913 .extern_func,
914 .func,
915 .enum_literal,
916 .empty_enum_value,
903917 => unreachable, // non-runtime values
904918
905 .false, .true => return try self.constBool(val.toBool(), repr),
906 },
907
908 .int => {
909 if (ty.isSignedInt(mod)) {
910 return try self.constInt(result_ty_ref, val.toSignedInt(mod));
911 } else {
912 return try self.constInt(result_ty_ref, val.toUnsignedInt(mod));
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 }
919 .simple_value => |simple_value| switch (simple_value) {
920 .undefined,
921 .void,
922 .null,
923 .empty_struct,
924 .@"unreachable",
925 .generic_poison,
926 => unreachable, // non-runtime values
964927
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);
928 .false, .true => break :cache try self.constBool(val.toBool(), repr),
929 },
930 .int => {
931 if (ty.isSignedInt(mod)) {
932 break :cache try self.constInt(ty, val.toSignedInt(mod), repr);
993933 } else {
994 const ptr_ty_ref = try self.resolveType(ty, .indirect);
995 return self.spv.constNull(ptr_ty_ref);
934 break :cache try self.constInt(ty, val.toUnsignedInt(mod), repr);
935 }
936 },
937 .float => {
938 const lit: spec.LiteralContextDependentNumber = switch (ty.floatBits(target)) {
939 16 => .{ .uint32 = @as(u16, @bitCast(val.toFloat(f16, mod))) },
940 32 => .{ .float32 = val.toFloat(f32, mod) },
941 64 => .{ .float64 = val.toFloat(f64, mod) },
942 80, 128 => unreachable, // TODO
943 else => unreachable,
944 };
945 const result_id = self.spv.allocId();
946 try section.emit(self.spv.gpa, .OpConstant, .{
947 .id_result_type = result_ty_id,
948 .id_result = result_id,
949 .value = lit,
950 });
951 break :cache result_id;
952 },
953 .err => |err| {
954 const value = try mod.getErrorValue(err.name);
955 break :cache try self.constInt(ty, value, repr);
956 },
957 .error_union => |error_union| {
958 // TODO: Error unions may be constructed with constant instructions if the payload type
959 // allows it. For now, just generate it here regardless.
960 const err_int_ty = try mod.errorIntType();
961 const err_ty = switch (error_union.val) {
962 .err_name => ty.errorUnionSet(mod),
963 .payload => err_int_ty,
964 };
965 const err_val = switch (error_union.val) {
966 .err_name => |err_name| Value.fromInterned((try mod.intern(.{ .err = .{
967 .ty = ty.errorUnionSet(mod).toIntern(),
968 .name = err_name,
969 } }))),
970 .payload => try mod.intValue(err_int_ty, 0),
971 };
972 const payload_ty = ty.errorUnionPayload(mod);
973 const eu_layout = self.errorUnionLayout(payload_ty);
974 if (!eu_layout.payload_has_bits) {
975 // We use the error type directly as the type.
976 break :cache try self.constant(err_ty, err_val, .indirect);
996977 }
997 }
998
999 // Optional representation is a structure.
1000 // { Payload, Bool }
1001978
1002 const has_pl_id = try self.constBool(maybe_payload_val != null, .indirect);
1003 const payload_id = if (maybe_payload_val) |payload_val|
1004 try self.constant(payload_ty, payload_val, .indirect)
1005 else
1006 try self.spv.constUndef(try self.resolveType(payload_ty, .indirect));
979 const payload_val = Value.fromInterned(switch (error_union.val) {
980 .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }),
981 .payload => |payload| payload,
982 });
1007983
1008 return try self.constructStruct(
1009 ty,
1010 &.{ payload_ty, Type.bool },
1011 &.{ payload_id, has_pl_id },
1012 );
1013 },
1014 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {
1015 inline .array_type, .vector_type => |array_type, tag| {
1016 const elem_ty = Type.fromInterned(array_type.child);
1017 const elem_ty_ref = try self.resolveType(elem_ty, .indirect);
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 },
984 var constituents: [2]IdRef = undefined;
985 var types: [2]Type = undefined;
986 if (eu_layout.error_first) {
987 constituents[0] = try self.constant(err_ty, err_val, .indirect);
988 constituents[1] = try self.constant(payload_ty, payload_val, .indirect);
989 types = .{ err_ty, payload_ty };
990 } else {
991 constituents[0] = try self.constant(payload_ty, payload_val, .indirect);
992 constituents[1] = try self.constant(err_ty, err_val, .indirect);
993 types = .{ payload_ty, err_ty };
1041994 }
1042995
1043 switch (tag) {
1044 inline .array_type => {
1045 if (array_type.sentinel != .none) {
1046 const sentinel = Value.fromInterned(array_type.sentinel);
1047 constituents[constituents.len - 1] = try self.constant(elem_ty, sentinel, .indirect);
1048 }
1049 return self.constructArray(ty, constituents);
1050 },
1051 inline .vector_type => return self.constructVector(ty, constituents),
1052 else => unreachable,
1053 }
996 return try self.constructStruct(ty, &types, &constituents);
997 },
998 .enum_tag => {
999 const int_val = try val.intFromEnum(ty, mod);
1000 const int_ty = ty.intTagType(mod);
1001 break :cache try self.constant(int_ty, int_val, repr);
10541002 },
1055 .struct_type => {
1056 const struct_type = mod.typeToStruct(ty).?;
1057 if (struct_type.layout == .@"packed") {
1058 return self.todo("packed struct constants", .{});
1003 .ptr => return self.constantPtr(ty, val),
1004 .slice => |slice| {
1005 const ptr_ty = ty.slicePtrFieldType(mod);
1006 const ptr_id = try self.constantPtr(ptr_ty, Value.fromInterned(slice.ptr));
1007 const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);
1008 return self.constructStruct(
1009 ty,
1010 &.{ ptr_ty, Type.usize },
1011 &.{ ptr_id, len_id },
1012 );
1013 },
1014 .opt => {
1015 const payload_ty = ty.optionalChild(mod);
1016 const maybe_payload_val = val.optionalValue(mod);
1017
1018 if (!payload_ty.hasRuntimeBits(mod)) {
1019 break :cache try self.constBool(maybe_payload_val != null, .indirect);
1020 } else if (ty.optionalReprIsPayload(mod)) {
1021 // Optional representation is a nullable pointer or slice.
1022 if (maybe_payload_val) |payload_val| {
1023 return try self.constant(payload_ty, payload_val, .indirect);
1024 } else {
1025 break :cache try self.spv.constNull(result_ty_id);
1026 }
10591027 }
10601028
1061 var types = std.ArrayList(Type).init(self.gpa);
1062 defer types.deinit();
1029 // Optional representation is a structure.
1030 // { Payload, Bool }
10631031
1064 var constituents = std.ArrayList(IdRef).init(self.gpa);
1065 defer constituents.deinit();
1032 const has_pl_id = try self.constBool(maybe_payload_val != null, .indirect);
1033 const payload_id = if (maybe_payload_val) |payload_val|
1034 try self.constant(payload_ty, payload_val, .indirect)
1035 else
1036 try self.spv.constUndef(try self.resolveType2(payload_ty, .indirect));
10661037
1067 var it = struct_type.iterateRuntimeOrder(ip);
1068 while (it.next()) |field_index| {
1069 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1070 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
1071 // This is a zero-bit field - we only needed it for the alignment.
1072 continue;
1038 return try self.constructStruct(
1039 ty,
1040 &.{ payload_ty, Type.bool },
1041 &.{ payload_id, has_pl_id },
1042 );
1043 },
1044 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {
1045 inline .array_type, .vector_type => |array_type, tag| {
1046 const elem_ty = Type.fromInterned(array_type.child);
1047
1048 const constituents = try self.gpa.alloc(IdRef, @as(u32, @intCast(ty.arrayLenIncludingSentinel(mod))));
1049 defer self.gpa.free(constituents);
1050
1051 switch (aggregate.storage) {
1052 .bytes => |bytes| {
1053 // TODO: This is really space inefficient, perhaps there is a better
1054 // way to do it?
1055 for (bytes, 0..) |byte, i| {
1056 constituents[i] = try self.constInt(elem_ty, byte, .indirect);
1057 }
1058 },
1059 .elems => |elems| {
1060 for (0..@as(usize, @intCast(array_type.len))) |i| {
1061 constituents[i] = try self.constant(elem_ty, Value.fromInterned(elems[i]), .indirect);
1062 }
1063 },
1064 .repeated_elem => |elem| {
1065 const val_id = try self.constant(elem_ty, Value.fromInterned(elem), .indirect);
1066 for (0..@as(usize, @intCast(array_type.len))) |i| {
1067 constituents[i] = val_id;
1068 }
1069 },
10731070 }
10741071
1075 // TODO: Padding?
1076 const field_val = try val.fieldValue(mod, field_index);
1077 const field_id = try self.constant(field_ty, field_val, .indirect);
1072 switch (tag) {
1073 inline .array_type => {
1074 if (array_type.sentinel != .none) {
1075 const sentinel = Value.fromInterned(array_type.sentinel);
1076 constituents[constituents.len - 1] = try self.constant(elem_ty, sentinel, .indirect);
1077 }
1078 return self.constructArray(ty, constituents);
1079 },
1080 inline .vector_type => return self.constructVector(ty, constituents),
1081 else => unreachable,
1082 }
1083 },
1084 .struct_type => {
1085 const struct_type = mod.typeToStruct(ty).?;
1086 if (struct_type.layout == .@"packed") {
1087 return self.todo("packed struct constants", .{});
1088 }
10781089
1079 try types.append(field_ty);
1080 try constituents.append(field_id);
1081 }
1090 var types = std.ArrayList(Type).init(self.gpa);
1091 defer types.deinit();
1092
1093 var constituents = std.ArrayList(IdRef).init(self.gpa);
1094 defer constituents.deinit();
1095
1096 var it = struct_type.iterateRuntimeOrder(ip);
1097 while (it.next()) |field_index| {
1098 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1099 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
1100 // This is a zero-bit field - we only needed it for the alignment.
1101 continue;
1102 }
1103
1104 // TODO: Padding?
1105 const field_val = try val.fieldValue(mod, field_index);
1106 const field_id = try self.constant(field_ty, field_val, .indirect);
10821107
1083 return try self.constructStruct(ty, types.items, constituents.items);
1108 try types.append(field_ty);
1109 try constituents.append(field_id);
1110 }
1111
1112 return try self.constructStruct(ty, types.items, constituents.items);
1113 },
1114 .anon_struct_type => unreachable, // TODO
1115 else => unreachable,
10841116 },
1085 .anon_struct_type => unreachable, // TODO
1086 else => unreachable,
1087 },
1088 .un => |un| {
1089 const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), mod).?;
1090 const union_obj = mod.typeToUnion(ty).?;
1091 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[active_field]);
1092 const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod))
1093 try self.constant(field_ty, Value.fromInterned(un.val), .direct)
1094 else
1095 null;
1096 return try self.unionInit(ty, active_field, payload);
1097 },
1098 .memoized_call => unreachable,
1099 }
1117 .un => |un| {
1118 const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), mod).?;
1119 const union_obj = mod.typeToUnion(ty).?;
1120 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[active_field]);
1121 const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod))
1122 try self.constant(field_ty, Value.fromInterned(un.val), .direct)
1123 else
1124 null;
1125 return try self.unionInit(ty, active_field, payload);
1126 },
1127 .memoized_call => unreachable,
1128 }
1129 };
1130
1131 try self.intern_map.putNoClobber(self.gpa, .{ val.toIntern(), repr }, cacheable_id);
1132
1133 return cacheable_id;
11001134 }
11011135
11021136 fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) Error!IdRef {
1137 const result_ty_id = try self.resolveType2(ptr_ty, .direct);
11031138 const result_ty_ref = try self.resolveType(ptr_ty, .direct);
11041139 const mod = self.module;
11051140
1106 if (ptr_val.isUndef(mod)) return self.spv.constUndef(result_ty_ref);
1141 if (ptr_val.isUndef(mod)) return self.spv.constUndef(result_ty_id);
11071142
11081143 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
11091144 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),
......@@ -1126,8 +1161,7 @@ const DeclGen = struct {
11261161 .elem => |elem_ptr| {
11271162 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));
11281163 const parent_ptr_id = try self.constantPtr(parent_ptr_ty, Value.fromInterned(elem_ptr.base));
1129 const size_ty_ref = try self.sizeType();
1130 const index_id = try self.constInt(size_ty_ref, elem_ptr.index);
1164 const index_id = try self.constInt(Type.usize, elem_ptr.index, .direct);
11311165
11321166 const elem_ptr_id = try self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);
11331167
......@@ -1181,7 +1215,7 @@ const DeclGen = struct {
11811215 // const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
11821216 if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
11831217 // Pointer to nothing - return undefoined
1184 return self.spv.constUndef(ty_ref);
1218 return self.spv.constUndef(self.typeId(ty_ref));
11851219 }
11861220
11871221 if (decl_ty.zigTypeTag(mod) == .Fn) {
......@@ -1217,7 +1251,7 @@ const DeclGen = struct {
12171251 .func => {
12181252 // TODO: Properly lower function pointers. For now we are going to hack around it and
12191253 // just generate an empty pointer. Function pointers are represented by a pointer to usize.
1220 return try self.spv.constUndef(ty_ref);
1254 return try self.spv.constUndef(ty_id);
12211255 },
12221256 .extern_func => unreachable, // TODO
12231257 else => {},
......@@ -1225,7 +1259,7 @@ const DeclGen = struct {
12251259
12261260 if (!decl.typeOf(mod).isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
12271261 // Pointer to nothing - return undefined.
1228 return self.spv.constUndef(ty_ref);
1262 return self.spv.constUndef(ty_id);
12291263 }
12301264
12311265 const spv_decl_index = try self.object.resolveDecl(mod, decl_index);
......@@ -1274,6 +1308,14 @@ const DeclGen = struct {
12741308 return self.spv.resultId(type_ref);
12751309 }
12761310
1311 /// Turn a Zig type into a SPIR-V Type result-id.
1312 /// This function represents the "new interface", where types handled only
1313 /// with Type and IdResult, and CacheRef is not used. Prefer this for now.
1314 fn resolveType2(self: *DeclGen, ty: Type, repr: Repr) !IdResult {
1315 const type_ref = try self.resolveType(ty, repr);
1316 return self.typeId(type_ref);
1317 }
1318
12771319 fn typeId(self: *DeclGen, ty_ref: CacheRef) IdRef {
12781320 return self.spv.resultId(ty_ref);
12791321 }
......@@ -1297,11 +1339,6 @@ const DeclGen = struct {
12971339 return self.spv.intType(.unsigned, backing_bits);
12981340 }
12991341
1300 /// Create an integer type that represents 'usize'.
1301 fn sizeType(self: *DeclGen) !CacheRef {
1302 return try self.intType(.unsigned, self.getTarget().ptrBitWidth());
1303 }
1304
13051342 fn ptrType(self: *DeclGen, child_ty: Type, storage_class: StorageClass) !CacheRef {
13061343 const key = .{ child_ty.toIntern(), storage_class };
13071344 const entry = try self.wip_pointers.getOrPut(self.gpa, key);
......@@ -1367,7 +1404,7 @@ const DeclGen = struct {
13671404 var member_types: [4]CacheRef = undefined;
13681405 var member_names: [4]CacheString = undefined;
13691406
1370 const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled?
1407 const u8_ty_ref = try self.resolveType(Type.u8, .direct); // TODO: What if Int8Type is not enabled?
13711408
13721409 if (layout.tag_size != 0) {
13731410 const tag_ty_ref = try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect);
......@@ -1439,7 +1476,7 @@ const DeclGen = struct {
14391476 },
14401477 .Bool => switch (repr) {
14411478 .direct => return try self.spv.resolve(.bool_type),
1442 .indirect => return try self.intType(.unsigned, 1),
1479 .indirect => return try self.resolveType(Type.u1, .indirect),
14431480 },
14441481 .Int => {
14451482 const int_info = ty.intInfo(mod);
......@@ -1548,7 +1585,7 @@ const DeclGen = struct {
15481585 .indirect => {
15491586 // TODO: Represent function pointers properly.
15501587 // For now, just use an usize type.
1551 return try self.sizeType();
1588 return try self.resolveType(Type.usize, .indirect);
15521589 },
15531590 },
15541591 .Pointer => {
......@@ -1564,7 +1601,7 @@ const DeclGen = struct {
15641601 return ptr_ty_ref;
15651602 }
15661603
1567 const size_ty_ref = try self.sizeType();
1604 const size_ty_ref = try self.resolveType(Type.usize, .direct);
15681605 return self.spv.resolve(.{ .struct_type = .{
15691606 .member_types = &.{ ptr_ty_ref, size_ty_ref },
15701607 .member_names = &.{
......@@ -1680,7 +1717,7 @@ const DeclGen = struct {
16801717 return ty_ref;
16811718 },
16821719 .Union => return try self.resolveUnionType(ty),
1683 .ErrorSet => return try self.intType(.unsigned, 16),
1720 .ErrorSet => return try self.resolveType(Type.u16, repr),
16841721 .ErrorUnion => {
16851722 const payload_ty = ty.errorUnionPayload(mod);
16861723 const error_ty_ref = try self.resolveType(Type.anyerror, .indirect);
......@@ -2202,12 +2239,12 @@ const DeclGen = struct {
22022239 }
22032240 }
22042241
2205 fn intFromBool(self: *DeclGen, result_ty_ref: CacheRef, condition_id: IdRef) !IdRef {
2206 const zero_id = try self.constInt(result_ty_ref, 0);
2207 const one_id = try self.constInt(result_ty_ref, 1);
2242 fn intFromBool(self: *DeclGen, ty: Type, condition_id: IdRef) !IdRef {
2243 const zero_id = try self.constInt(ty, 0, .direct);
2244 const one_id = try self.constInt(ty, 1, .direct);
22082245 const result_id = self.spv.allocId();
22092246 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
2210 .id_result_type = self.typeId(result_ty_ref),
2247 .id_result_type = try self.resolveType2(ty, .direct),
22112248 .id_result = result_id,
22122249 .condition = condition_id,
22132250 .object_1 = one_id,
......@@ -2222,15 +2259,12 @@ const DeclGen = struct {
22222259 const mod = self.module;
22232260 return switch (ty.zigTypeTag(mod)) {
22242261 .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);
22282262 const result_id = self.spv.allocId();
22292263 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
2230 .id_result_type = self.typeId(direct_bool_ty_ref),
2264 .id_result_type = try self.resolveType2(Type.bool, .direct),
22312265 .id_result = result_id,
22322266 .operand_1 = operand_id,
2233 .operand_2 = zero_id,
2267 .operand_2 = try self.constBool(false, .indirect),
22342268 });
22352269 break :blk result_id;
22362270 },
......@@ -2243,10 +2277,7 @@ const DeclGen = struct {
22432277 fn convertToIndirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef {
22442278 const mod = self.module;
22452279 return switch (ty.zigTypeTag(mod)) {
2246 .Bool => blk: {
2247 const indirect_bool_ty_ref = try self.resolveType(ty, .indirect);
2248 break :blk self.intFromBool(indirect_bool_ty_ref, operand_id);
2249 },
2280 .Bool => try self.intFromBool(Type.u1, operand_id),
22502281 else => operand_id,
22512282 };
22522283 }
......@@ -2529,7 +2560,7 @@ const DeclGen = struct {
25292560 try self.func.body.emit(self.spv.gpa, unsigned, args);
25302561 }
25312562
2532 result_id.* = try self.normalize(wip.ty_ref, value_id, info);
2563 result_id.* = try self.normalize(wip.ty, value_id, info);
25332564 }
25342565 return try wip.finalize();
25352566 }
......@@ -2622,7 +2653,7 @@ const DeclGen = struct {
26222653 /// - Signed integers are also sign extended if they are negative.
26232654 /// All other values are returned unmodified (this makes strange integer
26242655 /// wrapping easier to use in generic operations).
2625 fn normalize(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, info: ArithmeticTypeInfo) !IdRef {
2656 fn normalize(self: *DeclGen, ty: Type, value_id: IdRef, info: ArithmeticTypeInfo) !IdRef {
26262657 switch (info.class) {
26272658 .integer, .bool, .float => return value_id,
26282659 .composite_integer => unreachable, // TODO
......@@ -2630,9 +2661,9 @@ const DeclGen = struct {
26302661 .unsigned => {
26312662 const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1;
26322663 const result_id = self.spv.allocId();
2633 const mask_id = try self.constInt(ty_ref, mask_value);
2664 const mask_id = try self.constInt(ty, mask_value, .direct);
26342665 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{
2635 .id_result_type = self.typeId(ty_ref),
2666 .id_result_type = try self.resolveType2(ty, .direct),
26362667 .id_result = result_id,
26372668 .operand_1 = value_id,
26382669 .operand_2 = mask_id,
......@@ -2641,17 +2672,17 @@ const DeclGen = struct {
26412672 },
26422673 .signed => {
26432674 // 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);
2675 const shift_amt_id = try self.constInt(ty, info.backing_bits - info.bits, .direct);
26452676 const left_id = self.spv.allocId();
26462677 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{
2647 .id_result_type = self.typeId(ty_ref),
2678 .id_result_type = try self.resolveType2(ty, .direct),
26482679 .id_result = left_id,
26492680 .base = value_id,
26502681 .shift = shift_amt_id,
26512682 });
26522683 const right_id = self.spv.allocId();
26532684 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{
2654 .id_result_type = self.typeId(ty_ref),
2685 .id_result_type = try self.resolveType2(ty, .direct),
26552686 .id_result = right_id,
26562687 .base = left_id,
26572688 .shift = shift_amt_id,
......@@ -2667,13 +2698,13 @@ const DeclGen = struct {
26672698 const lhs_id = try self.resolve(bin_op.lhs);
26682699 const rhs_id = try self.resolve(bin_op.rhs);
26692700 const ty = self.typeOfIndex(inst);
2670 const ty_ref = try self.resolveType(ty, .direct);
2701 const ty_id = try self.resolveType2(ty, .direct);
26712702 const info = self.arithmeticTypeInfo(ty);
26722703 switch (info.class) {
26732704 .composite_integer => unreachable, // TODO
26742705 .integer, .strange_integer => {
2675 const zero_id = try self.constInt(ty_ref, 0);
2676 const one_id = try self.constInt(ty_ref, 1);
2706 const zero_id = try self.constInt(ty, 0, .direct);
2707 const one_id = try self.constInt(ty, 1, .direct);
26772708
26782709 // (a ^ b) > 0
26792710 const bin_bitwise_id = try self.binOpSimple(ty, lhs_id, rhs_id, .OpBitwiseXor);
......@@ -2696,14 +2727,14 @@ const DeclGen = struct {
26962727 const negative_div_id = try self.arithOp(ty, negative_div_lhs, rhs_abs, .OpFDiv, .OpSDiv, .OpUDiv);
26972728 const negated_negative_div_id = self.spv.allocId();
26982729 try self.func.body.emit(self.spv.gpa, .OpSNegate, .{
2699 .id_result_type = self.typeId(ty_ref),
2730 .id_result_type = ty_id,
27002731 .id_result = negated_negative_div_id,
27012732 .operand = negative_div_id,
27022733 });
27032734
27042735 const result_id = self.spv.allocId();
27052736 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
2706 .id_result_type = self.typeId(ty_ref),
2737 .id_result_type = ty_id,
27072738 .id_result = result_id,
27082739 .condition = is_positive_id,
27092740 .object_1 = positive_div_id,
......@@ -2819,7 +2850,7 @@ const DeclGen = struct {
28192850
28202851 // TODO: Trap on overflow? Probably going to be annoying.
28212852 // 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);
2853 result_id.* = try self.normalize(wip.ty, value_id, info);
28232854 }
28242855
28252856 return try wip.finalize();
......@@ -2929,7 +2960,7 @@ const DeclGen = struct {
29292960 });
29302961
29312962 // Normalize the result so that the comparisons go well
2932 result_id.* = try self.normalize(wip_result.ty_ref, value_id, info);
2963 result_id.* = try self.normalize(wip_result.ty, value_id, info);
29332964
29342965 const overflowed_id = switch (info.signedness) {
29352966 .unsigned => blk: {
......@@ -2963,7 +2994,7 @@ const DeclGen = struct {
29632994 // = (rhs < 0) == (lhs > value)
29642995
29652996 const rhs_lt_zero_id = self.spv.allocId();
2966 const zero_id = try self.constInt(wip_result.ty_ref, 0);
2997 const zero_id = try self.constInt(wip_result.ty, 0, .direct);
29672998 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{
29682999 .id_result_type = self.typeId(cmp_ty_ref),
29693000 .id_result = rhs_lt_zero_id,
......@@ -2990,7 +3021,7 @@ const DeclGen = struct {
29903021 },
29913022 };
29923023
2993 ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id);
3024 ov_id.* = try self.intFromBool(wip_ov.ty, overflowed_id);
29943025 }
29953026
29963027 return try self.constructStruct(
......@@ -3022,9 +3053,9 @@ const DeclGen = struct {
30223053 var wip_ov = try self.elementWise(ov_ty, true);
30233054 defer wip_ov.deinit();
30243055
3025 const zero_id = try self.constInt(wip_result.ty_ref, 0);
3026 const zero_ov_id = try self.constInt(wip_ov.ty_ref, 0);
3027 const one_ov_id = try self.constInt(wip_ov.ty_ref, 1);
3056 const zero_id = try self.constInt(wip_result.ty, 0, .direct);
3057 const zero_ov_id = try self.constInt(wip_ov.ty, 0, .direct);
3058 const one_ov_id = try self.constInt(wip_ov.ty, 1, .direct);
30283059
30293060 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {
30303061 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);
......@@ -3109,7 +3140,7 @@ const DeclGen = struct {
31093140 .base = lhs_elem_id,
31103141 .shift = shift_id,
31113142 });
3112 result_id.* = try self.normalize(wip_result.ty_ref, value_id, info);
3143 result_id.* = try self.normalize(wip_result.ty, value_id, info);
31133144
31143145 const right_shift_id = self.spv.allocId();
31153146 switch (info.signedness) {
......@@ -3139,7 +3170,7 @@ const DeclGen = struct {
31393170 .operand_2 = right_shift_id,
31403171 });
31413172
3142 ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id);
3173 ov_id.* = try self.intFromBool(wip_ov.ty, overflowed_id);
31433174 }
31443175
31453176 return try self.constructStruct(
......@@ -3351,7 +3382,7 @@ const DeclGen = struct {
33513382 for (wip.results, 0..) |*result_id, i| {
33523383 const elem = try mask.elemValue(mod, i);
33533384 if (elem.isUndef(mod)) {
3354 result_id.* = try self.spv.constUndef(wip.ty_ref);
3385 result_id.* = try self.spv.constUndef(wip.ty_id);
33553386 continue;
33563387 }
33573388
......@@ -3366,11 +3397,10 @@ const DeclGen = struct {
33663397 }
33673398
33683399 fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef {
3369 const index_ty_ref = try self.intType(.unsigned, 32);
33703400 const ids = try self.gpa.alloc(IdRef, indices.len);
33713401 errdefer self.gpa.free(ids);
33723402 for (indices, ids) |index, *id| {
3373 id.* = try self.constInt(index_ty_ref, index);
3403 id.* = try self.constInt(Type.u32, index, .direct);
33743404 }
33753405
33763406 return ids;
......@@ -3502,7 +3532,7 @@ const DeclGen = struct {
35023532 cmp_lhs_id = self.spv.allocId();
35033533 cmp_rhs_id = self.spv.allocId();
35043534
3505 const usize_ty_id = self.typeId(try self.sizeType());
3535 const usize_ty_id = try self.resolveType2(Type.usize, .direct);
35063536
35073537 try self.func.body.emit(self.spv.gpa, .OpConvertPtrToU, .{
35083538 .id_result_type = usize_ty_id,
......@@ -3761,7 +3791,7 @@ const DeclGen = struct {
37613791 // should we change the representation of strange integers?
37623792 if (dst_ty.zigTypeTag(mod) == .Int) {
37633793 const info = self.arithmeticTypeInfo(dst_ty);
3764 return try self.normalize(dst_ty_ref, result_id, info);
3794 return try self.normalize(dst_ty, result_id, info);
37653795 }
37663796
37673797 return result_id;
......@@ -3811,7 +3841,7 @@ const DeclGen = struct {
38113841 // type, we don't need to normalize when growing the type. The
38123842 // representation is already the same.
38133843 if (dst_info.bits < src_info.bits) {
3814 result_id.* = try self.normalize(wip.ty_ref, value_id, dst_info);
3844 result_id.* = try self.normalize(wip.ty, value_id, dst_info);
38153845 } else {
38163846 result_id.* = value_id;
38173847 }
......@@ -3898,7 +3928,7 @@ const DeclGen = struct {
38983928 defer wip.deinit();
38993929 for (wip.results, 0..) |*result_id, i| {
39003930 const elem_id = try wip.elementAt(Type.bool, operand_id, i);
3901 result_id.* = try self.intFromBool(wip.ty_ref, elem_id);
3931 result_id.* = try self.intFromBool(wip.ty, elem_id);
39023932 }
39033933 return try wip.finalize();
39043934 }
......@@ -3958,10 +3988,9 @@ const DeclGen = struct {
39583988 const elem_ptr_ty = slice_ty.slicePtrFieldType(mod);
39593989
39603990 const elem_ptr_ty_ref = try self.resolveType(elem_ptr_ty, .direct);
3961 const size_ty_ref = try self.sizeType();
39623991
39633992 const array_ptr_id = try self.resolve(ty_op.operand);
3964 const len_id = try self.constInt(size_ty_ref, array_ty.arrayLen(mod));
3993 const len_id = try self.constInt(Type.usize, array_ty.arrayLen(mod), .direct);
39653994
39663995 const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))
39673996 // Note: The pointer is something like *opaque{}, so we need to bitcast it to the element type.
......@@ -4092,8 +4121,8 @@ const DeclGen = struct {
40924121 const array_ty = ty.childType(mod);
40934122 const elem_ty = array_ty.childType(mod);
40944123 const abi_size = elem_ty.abiSize(mod);
4095 const usize_ty_ref = try self.resolveType(Type.usize, .direct);
4096 return self.spv.constInt(usize_ty_ref, array_ty.arrayLenIncludingSentinel(mod) * abi_size);
4124 const size = array_ty.arrayLenIncludingSentinel(mod) * abi_size;
4125 return try self.constInt(Type.usize, size, .direct);
40974126 },
40984127 .Many, .C => unreachable,
40994128 }
......@@ -4298,6 +4327,8 @@ const DeclGen = struct {
42984327 // union type, then get the field pointer and pointer-cast it to the
42994328 // right type to store it. Finally load the entire union.
43004329
4330 // Note: The result here is not cached, because it generates runtime code.
4331
43014332 const mod = self.module;
43024333 const ip = &mod.intern_pool;
43034334 const union_ty = mod.typeToUnion(ty).?;
......@@ -4316,17 +4347,15 @@ const DeclGen = struct {
43164347 } else 0;
43174348
43184349 if (!layout.has_payload) {
4319 const tag_ty_ref = try self.resolveType(tag_ty, .direct);
4320 return try self.constInt(tag_ty_ref, tag_int);
4350 return try self.constInt(tag_ty, tag_int, .direct);
43214351 }
43224352
43234353 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });
43244354
43254355 if (layout.tag_size != 0) {
4326 const tag_ty_ref = try self.resolveType(tag_ty, .direct);
43274356 const tag_ptr_ty_ref = try self.ptrType(tag_ty, .Function);
43284357 const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});
4329 const tag_id = try self.constInt(tag_ty_ref, tag_int);
4358 const tag_id = try self.constInt(tag_ty, tag_int, .direct);
43304359 try self.store(tag_ty, ptr_id, tag_id, .{});
43314360 }
43324361
......@@ -4420,8 +4449,6 @@ const DeclGen = struct {
44204449
44214450 const parent_ty = ty_pl.ty.toType().childType(mod);
44224451 const res_ty = 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);
44254452
44264453 const field_ptr = try self.resolve(extra.field_ptr);
44274454 const field_ptr_int = try self.intFromPtr(field_ptr);
......@@ -4430,8 +4457,8 @@ const DeclGen = struct {
44304457 const base_ptr_int = base_ptr_int: {
44314458 if (field_offset == 0) break :base_ptr_int field_ptr_int;
44324459
4433 const field_offset_id = try self.constInt(usize_ty_ref, field_offset);
4434 break :base_ptr_int try self.binOpSimple(usize_ty, field_ptr_int, field_offset_id, .OpISub);
4460 const field_offset_id = try self.constInt(Type.usize, field_offset, .direct);
4461 break :base_ptr_int try self.binOpSimple(Type.usize, field_ptr_int, field_offset_id, .OpISub);
44354462 };
44364463
44374464 const base_ptr = self.spv.allocId();
......@@ -4469,7 +4496,7 @@ const DeclGen = struct {
44694496 if (!layout.has_payload) {
44704497 // Asked to get a pointer to a zero-sized field. Just lower this
44714498 // to undefined, there is no reason to make it be a valid pointer.
4472 return try self.spv.constUndef(result_ty_ref);
4499 return try self.spv.constUndef(self.typeId(result_ty_ref));
44734500 }
44744501
44754502 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(mod));
......@@ -4563,7 +4590,7 @@ const DeclGen = struct {
45634590 assert(self.control_flow == .structured);
45644591
45654592 const result_id = self.spv.allocId();
4566 const block_id_ty_ref = try self.intType(.unsigned, 32);
4593 const block_id_ty_ref = try self.resolveType(Type.u32, .direct);
45674594 try self.func.body.emitRaw(self.spv.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent...
45684595 self.func.body.writeOperand(spec.IdResultType, self.typeId(block_id_ty_ref));
45694596 self.func.body.writeOperand(spec.IdRef, result_id);
......@@ -4663,8 +4690,8 @@ const DeclGen = struct {
46634690 // Make sure that we are still in a block when exiting the function.
46644691 // TODO: Can we get rid of that?
46654692 try self.beginSpvBlock(self.spv.allocId());
4666 const block_id_ty_ref = try self.intType(.unsigned, 32);
4667 return try self.spv.constUndef(block_id_ty_ref);
4693 const block_id_ty_ref = try self.resolveType(Type.u32, .direct);
4694 return try self.spv.constUndef(self.typeId(block_id_ty_ref));
46684695 }
46694696
46704697 // The top-most merge actually only has a single source, the
......@@ -4781,8 +4808,7 @@ const DeclGen = struct {
47814808 assert(cf.block_stack.items.len > 0);
47824809
47834810 // Check if the target of the branch was this current block.
4784 const block_id_ty_ref = try self.intType(.unsigned, 32);
4785 const this_block = try self.constInt(block_id_ty_ref, @intFromEnum(inst));
4811 const this_block = try self.constInt(Type.u32, @intFromEnum(inst), .direct);
47864812 const jump_to_this_block_id = self.spv.allocId();
47874813 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
47884814 try self.func.body.emit(self.spv.gpa, .OpIEqual, .{
......@@ -4862,8 +4888,7 @@ const DeclGen = struct {
48624888 try self.store(operand_ty, block_result_var_id, operand_id, .{});
48634889 }
48644890
4865 const block_id_ty_ref = try self.intType(.unsigned, 32);
4866 const next_block = try self.constInt(block_id_ty_ref, @intFromEnum(br.block_inst));
4891 const next_block = try self.constInt(Type.u32, @intFromEnum(br.block_inst), .direct);
48674892 try self.structuredBreak(next_block);
48684893 },
48694894 .unstructured => |cf| {
......@@ -5026,8 +5051,7 @@ const DeclGen = struct {
50265051 // Functions with an empty error set are emitted with an error code
50275052 // return type and return zero so they can be function pointers coerced
50285053 // to functions that return anyerror.
5029 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
5030 const no_err_id = try self.constInt(err_ty_ref, 0);
5054 const no_err_id = try self.constInt(Type.anyerror, 0, .direct);
50315055 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });
50325056 } else {
50335057 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});
......@@ -5051,8 +5075,7 @@ const DeclGen = struct {
50515075 // Functions with an empty error set are emitted with an error code
50525076 // return type and return zero so they can be function pointers coerced
50535077 // to functions that return anyerror.
5054 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
5055 const no_err_id = try self.constInt(err_ty_ref, 0);
5078 const no_err_id = try self.constInt(Type.anyerror, 0, .direct);
50565079 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });
50575080 } else {
50585081 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});
......@@ -5076,7 +5099,6 @@ const DeclGen = struct {
50765099 const err_union_ty = self.typeOf(pl_op.operand);
50775100 const payload_ty = self.typeOfIndex(inst);
50785101
5079 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
50805102 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
50815103
50825104 const eu_layout = self.errorUnionLayout(payload_ty);
......@@ -5087,7 +5109,7 @@ const DeclGen = struct {
50875109 else
50885110 err_union_id;
50895111
5090 const zero_id = try self.constInt(err_ty_ref, 0);
5112 const zero_id = try self.constInt(Type.anyerror, 0, .direct);
50915113 const is_err_id = self.spv.allocId();
50925114 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
50935115 .id_result_type = self.typeId(bool_ty_ref),
......@@ -5146,7 +5168,7 @@ const DeclGen = struct {
51465168
51475169 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
51485170 // No error possible, so just return undefined.
5149 return try self.spv.constUndef(err_ty_ref);
5171 return try self.spv.constUndef(self.typeId(err_ty_ref));
51505172 }
51515173
51525174 const payload_ty = err_union_ty.errorUnionPayload(mod);
......@@ -5189,7 +5211,7 @@ const DeclGen = struct {
51895211
51905212 var members: [2]IdRef = undefined;
51915213 members[eu_layout.errorFieldIndex()] = operand_id;
5192 members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref);
5214 members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(self.typeId(payload_ty_ref));
51935215
51945216 var types: [2]Type = undefined;
51955217 types[eu_layout.errorFieldIndex()] = Type.anyerror;
......@@ -5203,15 +5225,14 @@ const DeclGen = struct {
52035225 const err_union_ty = self.typeOfIndex(inst);
52045226 const operand_id = try self.resolve(ty_op.operand);
52055227 const payload_ty = self.typeOf(ty_op.operand);
5206 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
52075228 const eu_layout = self.errorUnionLayout(payload_ty);
52085229
52095230 if (!eu_layout.payload_has_bits) {
5210 return try self.constInt(err_ty_ref, 0);
5231 return try self.constInt(Type.anyerror, 0, .direct);
52115232 }
52125233
52135234 var members: [2]IdRef = undefined;
5214 members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0);
5235 members[eu_layout.errorFieldIndex()] = try self.constInt(Type.anyerror, 0, .direct);
52155236 members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id);
52165237
52175238 var types: [2]Type = undefined;
......@@ -5248,8 +5269,8 @@ const DeclGen = struct {
52485269 else
52495270 loaded_id;
52505271
5251 const payload_ty_ref = try self.resolveType(ptr_ty, .direct);
5252 const null_id = try self.spv.constNull(payload_ty_ref);
5272 const payload_ty_id = try self.resolveType2(ptr_ty, .direct);
5273 const null_id = try self.spv.constNull(payload_ty_id);
52535274 const op: std.math.CompareOperator = switch (pred) {
52545275 .is_null => .eq,
52555276 .is_non_null => .neq,
......@@ -5306,7 +5327,6 @@ const DeclGen = struct {
53065327 const payload_ty = err_union_ty.errorUnionPayload(mod);
53075328 const eu_layout = self.errorUnionLayout(payload_ty);
53085329 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
5309 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
53105330
53115331 const error_id = if (!eu_layout.payload_has_bits)
53125332 operand_id
......@@ -5318,7 +5338,7 @@ const DeclGen = struct {
53185338 .id_result_type = self.typeId(bool_ty_ref),
53195339 .id_result = result_id,
53205340 .operand_1 = error_id,
5321 .operand_2 = try self.constInt(err_ty_ref, 0),
5341 .operand_2 = try self.constInt(Type.anyerror, 0, .direct),
53225342 };
53235343 switch (pred) {
53245344 .is_err => try self.func.body.emit(self.spv.gpa, .OpINotEqual, operands),
src/codegen/spirv/Module.zig+14-20
......@@ -435,28 +435,22 @@ pub fn arrayType(self: *Module, len: u32, elem_ty_ref: CacheRef) !CacheRef {
435435 } });
436436}
437437
438pub fn constInt(self: *Module, ty_ref: CacheRef, value: anytype) !IdRef {
439 const ty = self.cache.lookup(ty_ref).int_type;
440 const Value = Cache.Key.Int.Value;
441 return try self.resolveId(.{ .int = .{
442 .ty = ty_ref,
443 .value = switch (ty.signedness) {
444 .signed => Value{ .int64 = @intCast(value) },
445 .unsigned => Value{ .uint64 = @intCast(value) },
446 },
447 } });
448}
449
450pub fn constUndef(self: *Module, ty_ref: CacheRef) !IdRef {
451 return try self.resolveId(.{ .undef = .{ .ty = ty_ref } });
452}
453
454pub fn constNull(self: *Module, ty_ref: CacheRef) !IdRef {
455 return try self.resolveId(.{ .null = .{ .ty = ty_ref } });
438pub fn constUndef(self: *Module, ty_id: IdRef) !IdRef {
439 const result_id = self.allocId();
440 try self.sections.types_globals_constants.emit(self.gpa, .OpUndef, .{
441 .id_result_type = ty_id,
442 .id_result = result_id,
443 });
444 return result_id;
456445}
457446
458pub fn constBool(self: *Module, ty_ref: CacheRef, value: bool) !IdRef {
459 return try self.resolveId(.{ .bool = .{ .ty = ty_ref, .value = value } });
447pub fn constNull(self: *Module, ty_id: IdRef) !IdRef {
448 const result_id = self.allocId();
449 try self.sections.types_globals_constants.emit(self.gpa, .OpConstantNull, .{
450 .id_result_type = ty_id,
451 .id_result = result_id,
452 });
453 return result_id;
460454}
461455
462456pub fn constComposite(self: *Module, ty_ref: CacheRef, members: []const IdRef) !IdRef {