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 {...@@ -41,6 +41,8 @@ const SpvTypeInfo = struct {
4141
42const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, SpvTypeInfo);42const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, SpvTypeInfo);
4343
44const InternMap = std.AutoHashMapUnmanaged(struct { InternPool.Index, DeclGen.Repr }, IdResult);
45
44const ControlFlow = union(enum) {46const ControlFlow = union(enum) {
45 const Structured = struct {47 const Structured = struct {
46 /// This type indicates the way that a block is terminated. The48 /// This type indicates the way that a block is terminated. The
...@@ -171,6 +173,8 @@ pub const Object = struct {...@@ -171,6 +173,8 @@ pub const Object = struct {
171 /// of the SPIR-V module.173 /// of the SPIR-V module.
172 type_map: TypeMap = .{},174 type_map: TypeMap = .{},
173175
176 intern_map: InternMap = .{},
177
174 pub fn init(gpa: Allocator) Object {178 pub fn init(gpa: Allocator) Object {
175 return .{179 return .{
176 .gpa = gpa,180 .gpa = gpa,
...@@ -183,6 +187,7 @@ pub const Object = struct {...@@ -183,6 +187,7 @@ pub const Object = struct {
183 self.decl_link.deinit(self.gpa);187 self.decl_link.deinit(self.gpa);
184 self.anon_decl_link.deinit(self.gpa);188 self.anon_decl_link.deinit(self.gpa);
185 self.type_map.deinit(self.gpa);189 self.type_map.deinit(self.gpa);
190 self.intern_map.deinit(self.gpa);
186 }191 }
187192
188 fn genDecl(193 fn genDecl(
...@@ -205,6 +210,7 @@ pub const Object = struct {...@@ -205,6 +210,7 @@ pub const Object = struct {
205 .air = air,210 .air = air,
206 .liveness = liveness,211 .liveness = liveness,
207 .type_map = &self.type_map,212 .type_map = &self.type_map,
213 .intern_map = &self.intern_map,
208 .control_flow = switch (structured_cfg) {214 .control_flow = switch (structured_cfg) {
209 true => .{ .structured = .{} },215 true => .{ .structured = .{} },
210 false => .{ .unstructured = .{} },216 false => .{ .unstructured = .{} },
...@@ -313,6 +319,8 @@ const DeclGen = struct {...@@ -313,6 +319,8 @@ const DeclGen = struct {
313 /// See Object.type_map319 /// See Object.type_map
314 type_map: *TypeMap,320 type_map: *TypeMap,
315321
322 intern_map: *InternMap,
323
316 /// Child types of pointers that are currently in progress of being resolved. If a pointer324 /// Child types of pointers that are currently in progress of being resolved. If a pointer
317 /// is already in this map, its recursive.325 /// is already in this map, its recursive.
318 wip_pointers: std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, CacheRef) = .{},326 wip_pointers: std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, CacheRef) = .{},
...@@ -696,14 +704,25 @@ const DeclGen = struct {...@@ -696,14 +704,25 @@ const DeclGen = struct {
696704
697 /// Emits a bool constant in a particular representation.705 /// Emits a bool constant in a particular representation.
698 fn constBool(self: *DeclGen, value: bool, repr: Repr) !IdRef {706 fn constBool(self: *DeclGen, value: bool, repr: Repr) !IdRef {
707 // TODO: Cache?
708
709 const section = &self.spv.sections.types_globals_constants;
699 switch (repr) {710 switch (repr) {
700 .indirect => {711 .indirect => {
701 const int_ty_ref = try self.intType(.unsigned, 1);712 return try self.constInt(Type.u1, @intFromBool(value), .indirect);
702 return self.constInt(int_ty_ref, @intFromBool(value));
703 },713 },
704 .direct => {714 .direct => {
705 const bool_ty_ref = try self.resolveType(Type.bool, .direct);715 const result_ty_id = try self.resolveType2(Type.bool, .direct);
706 return self.spv.constBool(bool_ty_ref, value);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;
707 },726 },
708 }727 }
709 }728 }
...@@ -711,68 +730,63 @@ const DeclGen = struct {...@@ -711,68 +730,63 @@ const DeclGen = struct {
711 /// Emits an integer constant.730 /// Emits an integer constant.
712 /// This function, unlike SpvModule.constInt, takes care to bitcast731 /// This function, unlike SpvModule.constInt, takes care to bitcast
713 /// the value to an unsigned int first for Kernels.732 /// the value to an unsigned int first for Kernels.
714 fn constInt(self: *DeclGen, ty_ref: CacheRef, value: anytype) !IdRef {733 fn constInt(self: *DeclGen, ty: Type, value: anytype, repr: Repr) !IdRef {
715 switch (self.spv.cache.lookup(ty_ref)) {734 // TODO: Cache?
716 .vector_type => |vec_type| {735 const mod = self.module;
717 const elem_ids = try self.gpa.alloc(IdRef, vec_type.component_count);736 const scalar_ty = ty.scalarType(mod);
718 defer self.gpa.free(elem_ids);737 const int_info = scalar_ty.intInfo(mod);
719 const int_value = try self.constInt(vec_type.component_type, value);738 // Use backing bits so that negatives are sign extended
720 @memset(elem_ids, int_value);739 const backing_bits = self.backingIntBits(int_info.bits).?; // Assertion failure means big int
721740
722 const constituents_id = self.spv.allocId();741 const bits: u64 = switch (int_info.signedness) {
723 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{742 // Intcast needed to silence compile errors for when the wrong path is compiled.
724 .id_result_type = self.typeId(ty_ref),743 // Lazy fix.
725 .id_result = constituents_id,744 .signed => @bitCast(@as(i64, @intCast(value))),
726 .constituents = elem_ids,745 .unsigned => @as(u64, @intCast(value)),
727 });746 };
728 return constituents_id;
729 },
730 else => {},
731 }
732747
733 if (value < 0) {748 // Manually truncate the value to the right amount of bits.
734 const ty = self.spv.cache.lookup(ty_ref).int_type;749 const truncated_bits = if (backing_bits == 64)
735 // Manually truncate the value so that the resulting value750 bits
736 // fits within the unsigned type.751 else
737 const bits: u64 = @bitCast(@as(i64, @intCast(value)));752 bits & (@as(u64, 1) << @intCast(backing_bits)) - 1;
738 const truncated_bits = if (ty.bits == 64)753
739 bits754 const result_ty_id = try self.resolveType2(scalar_ty, repr);
740 else755 const result_id = self.spv.allocId();
741 bits & (@as(u64, 1) << @intCast(ty.bits)) - 1;756
742 return try self.spv.constInt(ty_ref, truncated_bits);757 const section = &self.spv.sections.types_globals_constants;
743 } else {758 switch (backing_bits) {
744 return try self.spv.constInt(ty_ref, value);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
745 }771 }
746 }
747772
748 /// Emits a float constant773 if (!ty.isVector(mod)) {
749 fn constFloat(self: *DeclGen, ty_ref: CacheRef, value: f128) !IdRef {774 return result_id;
750 switch (self.spv.cache.lookup(ty_ref)) {
751 .vector_type => |vec_type| {
752 const elem_ids = try self.gpa.alloc(IdRef, vec_type.component_count);
753 defer self.gpa.free(elem_ids);
754 const int_value = try self.constFloat(vec_type.component_type, value);
755 @memset(elem_ids, int_value);
756
757 const constituents_id = self.spv.allocId();
758 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
759 .id_result_type = self.typeId(ty_ref),
760 .id_result = constituents_id,
761 .constituents = elem_ids,
762 });
763 return constituents_id;
764 },
765 else => {},
766 }775 }
767776
768 const ty = self.spv.cache.lookup(ty_ref).float_type;777 const n = ty.vectorLen(mod);
769 return switch (ty.bits) {778 const ids = try self.gpa.alloc(IdRef, n);
770 16 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float16 = @floatCast(value) } } }),779 defer self.gpa.free(ids);
771 32 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float32 = @floatCast(value) } } }),780 @memset(ids, result_id);
772 64 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float64 = @floatCast(value) } } }),781
773 80, 128 => unreachable, // TODO782 const vec_ty_id = try self.resolveType2(ty, repr);
774 else => unreachable,783 const vec_result_id = self.spv.allocId();
775 };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;
776 }790 }
777791
778 /// Construct a struct at runtime.792 /// Construct a struct at runtime.
...@@ -852,258 +866,279 @@ const DeclGen = struct {...@@ -852,258 +866,279 @@ const DeclGen = struct {
852 /// is done by emitting a sequence of instructions that initialize the value.866 /// is done by emitting a sequence of instructions that initialize the value.
853 //867 //
854 /// This function should only be called during function code generation.868 /// 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
856 const mod = self.module;877 const mod = self.module;
857 const target = self.getTarget();878 const target = self.getTarget();
858 const result_ty_ref = try self.resolveType(ty, repr);879 const result_ty_ref = try self.resolveType(ty, repr);
880 const result_ty_id = self.typeId(result_ty_ref);
859 const ip = &mod.intern_pool;881 const ip = &mod.intern_pool;
860882
861 const val = arg_val;883 log.debug("lowering constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod) });
862
863 log.debug("constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod) });
864 if (val.isUndefDeep(mod)) {884 if (val.isUndefDeep(mod)) {
865 return self.spv.constUndef(result_ty_ref);885 return self.spv.constUndef(result_ty_id);
866 }886 }
867887
868 switch (ip.indexToKey(val.toIntern())) {888 const section = &self.spv.sections.types_globals_constants;
869 .int_type,889
870 .ptr_type,890 const cacheable_id = cache: {
871 .array_type,891 switch (ip.indexToKey(val.toIntern())) {
872 .vector_type,892 .int_type,
873 .opt_type,893 .ptr_type,
874 .anyframe_type,894 .array_type,
875 .error_union_type,895 .vector_type,
876 .simple_type,896 .opt_type,
877 .struct_type,897 .anyframe_type,
878 .anon_struct_type,898 .error_union_type,
879 .union_type,899 .simple_type,
880 .opaque_type,900 .struct_type,
881 .enum_type,901 .anon_struct_type,
882 .func_type,902 .union_type,
883 .error_set_type,903 .opaque_type,
884 .inferred_error_set_type,904 .enum_type,
885 => unreachable, // types, not values905 .func_type,
886906 .error_set_type,
887 .undef => unreachable, // handled above907 .inferred_error_set_type,
888908 => unreachable, // types, not values
889 .variable,909
890 .extern_func,910 .undef => unreachable, // handled above
891 .func,911
892 .enum_literal,912 .variable,
893 .empty_enum_value,913 .extern_func,
894 => unreachable, // non-runtime values914 .func,
895915 .enum_literal,
896 .simple_value => |simple_value| switch (simple_value) {916 .empty_enum_value,
897 .undefined,
898 .void,
899 .null,
900 .empty_struct,
901 .@"unreachable",
902 .generic_poison,
903 => unreachable, // non-runtime values917 => unreachable, // non-runtime values
904918
905 .false, .true => return try self.constBool(val.toBool(), repr),919 .simple_value => |simple_value| switch (simple_value) {
906 },920 .undefined,
907921 .void,
908 .int => {922 .null,
909 if (ty.isSignedInt(mod)) {923 .empty_struct,
910 return try self.constInt(result_ty_ref, val.toSignedInt(mod));924 .@"unreachable",
911 } else {925 .generic_poison,
912 return try self.constInt(result_ty_ref, val.toUnsignedInt(mod));926 => unreachable, // non-runtime values
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 }
964927
965 return try self.constructStruct(ty, &types, &constituents);928 .false, .true => break :cache try self.constBool(val.toBool(), repr),
966 },929 },
967 .enum_tag => {930 .int => {
968 const int_val = try val.intFromEnum(ty, mod);931 if (ty.isSignedInt(mod)) {
969 const int_ty = ty.intTagType(mod);932 break :cache try self.constInt(ty, val.toSignedInt(mod), repr);
970 return try self.constant(int_ty, int_val, repr);
971 },
972 .ptr => return self.constantPtr(ty, val),
973 .slice => |slice| {
974 const ptr_ty = ty.slicePtrFieldType(mod);
975 const ptr_id = try self.constantPtr(ptr_ty, Value.fromInterned(slice.ptr));
976 const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);
977 return self.constructStruct(
978 ty,
979 &.{ ptr_ty, Type.usize },
980 &.{ ptr_id, len_id },
981 );
982 },
983 .opt => {
984 const payload_ty = ty.optionalChild(mod);
985 const maybe_payload_val = val.optionalValue(mod);
986
987 if (!payload_ty.hasRuntimeBits(mod)) {
988 return try self.constBool(maybe_payload_val != null, .indirect);
989 } else if (ty.optionalReprIsPayload(mod)) {
990 // Optional representation is a nullable pointer or slice.
991 if (maybe_payload_val) |payload_val| {
992 return try self.constant(payload_ty, payload_val, .indirect);
993 } else {933 } else {
994 const ptr_ty_ref = try self.resolveType(ty, .indirect);934 break :cache try self.constInt(ty, val.toUnsignedInt(mod), repr);
995 return self.spv.constNull(ptr_ty_ref);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);
996 }977 }
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);979 const payload_val = Value.fromInterned(switch (error_union.val) {
1003 const payload_id = if (maybe_payload_val) |payload_val|980 .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }),
1004 try self.constant(payload_ty, payload_val, .indirect)981 .payload => |payload| payload,
1005 else982 });
1006 try self.spv.constUndef(try self.resolveType(payload_ty, .indirect));
1007983
1008 return try self.constructStruct(984 var constituents: [2]IdRef = undefined;
1009 ty,985 var types: [2]Type = undefined;
1010 &.{ payload_ty, Type.bool },986 if (eu_layout.error_first) {
1011 &.{ payload_id, has_pl_id },987 constituents[0] = try self.constant(err_ty, err_val, .indirect);
1012 );988 constituents[1] = try self.constant(payload_ty, payload_val, .indirect);
1013 },989 types = .{ err_ty, payload_ty };
1014 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {990 } else {
1015 inline .array_type, .vector_type => |array_type, tag| {991 constituents[0] = try self.constant(payload_ty, payload_val, .indirect);
1016 const elem_ty = Type.fromInterned(array_type.child);992 constituents[1] = try self.constant(err_ty, err_val, .indirect);
1017 const elem_ty_ref = try self.resolveType(elem_ty, .indirect);993 types = .{ payload_ty, err_ty };
1018
1019 const constituents = try self.gpa.alloc(IdRef, @intCast(ty.arrayLenIncludingSentinel(mod)));
1020 defer self.gpa.free(constituents);
1021
1022 switch (aggregate.storage) {
1023 .bytes => |bytes| {
1024 // TODO: This is really space inefficient, perhaps there is a better
1025 // way to do it?
1026 for (bytes, 0..) |byte, i| {
1027 constituents[i] = try self.constInt(elem_ty_ref, byte);
1028 }
1029 },
1030 .elems => |elems| {
1031 for (0..@as(usize, @intCast(array_type.len))) |i| {
1032 constituents[i] = try self.constant(elem_ty, Value.fromInterned(elems[i]), .indirect);
1033 }
1034 },
1035 .repeated_elem => |elem| {
1036 const val_id = try self.constant(elem_ty, Value.fromInterned(elem), .indirect);
1037 for (0..@as(usize, @intCast(array_type.len))) |i| {
1038 constituents[i] = val_id;
1039 }
1040 },
1041 }994 }
1042995
1043 switch (tag) {996 return try self.constructStruct(ty, &types, &constituents);
1044 inline .array_type => {997 },
1045 if (array_type.sentinel != .none) {998 .enum_tag => {
1046 const sentinel = Value.fromInterned(array_type.sentinel);999 const int_val = try val.intFromEnum(ty, mod);
1047 constituents[constituents.len - 1] = try self.constant(elem_ty, sentinel, .indirect);1000 const int_ty = ty.intTagType(mod);
1048 }1001 break :cache try self.constant(int_ty, int_val, repr);
1049 return self.constructArray(ty, constituents);
1050 },
1051 inline .vector_type => return self.constructVector(ty, constituents),
1052 else => unreachable,
1053 }
1054 },1002 },
1055 .struct_type => {1003 .ptr => return self.constantPtr(ty, val),
1056 const struct_type = mod.typeToStruct(ty).?;1004 .slice => |slice| {
1057 if (struct_type.layout == .@"packed") {1005 const ptr_ty = ty.slicePtrFieldType(mod);
1058 return self.todo("packed struct constants", .{});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 }
1059 }1027 }
10601028
1061 var types = std.ArrayList(Type).init(self.gpa);1029 // Optional representation is a structure.
1062 defer types.deinit();1030 // { Payload, Bool }
10631031
1064 var constituents = std.ArrayList(IdRef).init(self.gpa);1032 const has_pl_id = try self.constBool(maybe_payload_val != null, .indirect);
1065 defer constituents.deinit();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);1038 return try self.constructStruct(
1068 while (it.next()) |field_index| {1039 ty,
1069 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);1040 &.{ payload_ty, Type.bool },
1070 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {1041 &.{ payload_id, has_pl_id },
1071 // This is a zero-bit field - we only needed it for the alignment.1042 );
1072 continue;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 },
1073 }1070 }
10741071
1075 // TODO: Padding?1072 switch (tag) {
1076 const field_val = try val.fieldValue(mod, field_index);1073 inline .array_type => {
1077 const field_id = try self.constant(field_ty, field_val, .indirect);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);1090 var types = std.ArrayList(Type).init(self.gpa);
1080 try constituents.append(field_id);1091 defer types.deinit();
1081 }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,
1084 },1116 },
1085 .anon_struct_type => unreachable, // TODO1117 .un => |un| {
1086 else => unreachable,1118 const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), mod).?;
1087 },1119 const union_obj = mod.typeToUnion(ty).?;
1088 .un => |un| {1120 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[active_field]);
1089 const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), mod).?;1121 const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod))
1090 const union_obj = mod.typeToUnion(ty).?;1122 try self.constant(field_ty, Value.fromInterned(un.val), .direct)
1091 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[active_field]);1123 else
1092 const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod))1124 null;
1093 try self.constant(field_ty, Value.fromInterned(un.val), .direct)1125 return try self.unionInit(ty, active_field, payload);
1094 else1126 },
1095 null;1127 .memoized_call => unreachable,
1096 return try self.unionInit(ty, active_field, payload);1128 }
1097 },1129 };
1098 .memoized_call => unreachable,1130
1099 }1131 try self.intern_map.putNoClobber(self.gpa, .{ val.toIntern(), repr }, cacheable_id);
1132
1133 return cacheable_id;
1100 }1134 }
11011135
1102 fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) Error!IdRef {1136 fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) Error!IdRef {
1137 const result_ty_id = try self.resolveType2(ptr_ty, .direct);
1103 const result_ty_ref = try self.resolveType(ptr_ty, .direct);1138 const result_ty_ref = try self.resolveType(ptr_ty, .direct);
1104 const mod = self.module;1139 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
1108 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {1143 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
1109 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),1144 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),
...@@ -1126,8 +1161,7 @@ const DeclGen = struct {...@@ -1126,8 +1161,7 @@ const DeclGen = struct {
1126 .elem => |elem_ptr| {1161 .elem => |elem_ptr| {
1127 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));1162 const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));
1128 const parent_ptr_id = try self.constantPtr(parent_ptr_ty, Value.fromInterned(elem_ptr.base));1163 const parent_ptr_id = try self.constantPtr(parent_ptr_ty, Value.fromInterned(elem_ptr.base));
1129 const size_ty_ref = try self.sizeType();1164 const index_id = try self.constInt(Type.usize, elem_ptr.index, .direct);
1130 const index_id = try self.constInt(size_ty_ref, elem_ptr.index);
11311165
1132 const elem_ptr_id = try self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);1166 const elem_ptr_id = try self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);
11331167
...@@ -1181,7 +1215,7 @@ const DeclGen = struct {...@@ -1181,7 +1215,7 @@ const DeclGen = struct {
1181 // const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;1215 // const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
1182 if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {1216 if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
1183 // Pointer to nothing - return undefoined1217 // Pointer to nothing - return undefoined
1184 return self.spv.constUndef(ty_ref);1218 return self.spv.constUndef(self.typeId(ty_ref));
1185 }1219 }
11861220
1187 if (decl_ty.zigTypeTag(mod) == .Fn) {1221 if (decl_ty.zigTypeTag(mod) == .Fn) {
...@@ -1217,7 +1251,7 @@ const DeclGen = struct {...@@ -1217,7 +1251,7 @@ const DeclGen = struct {
1217 .func => {1251 .func => {
1218 // TODO: Properly lower function pointers. For now we are going to hack around it and1252 // TODO: Properly lower function pointers. For now we are going to hack around it and
1219 // just generate an empty pointer. Function pointers are represented by a pointer to usize.1253 // 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);
1221 },1255 },
1222 .extern_func => unreachable, // TODO1256 .extern_func => unreachable, // TODO
1223 else => {},1257 else => {},
...@@ -1225,7 +1259,7 @@ const DeclGen = struct {...@@ -1225,7 +1259,7 @@ const DeclGen = struct {
12251259
1226 if (!decl.typeOf(mod).isFnOrHasRuntimeBitsIgnoreComptime(mod)) {1260 if (!decl.typeOf(mod).isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
1227 // Pointer to nothing - return undefined.1261 // Pointer to nothing - return undefined.
1228 return self.spv.constUndef(ty_ref);1262 return self.spv.constUndef(ty_id);
1229 }1263 }
12301264
1231 const spv_decl_index = try self.object.resolveDecl(mod, decl_index);1265 const spv_decl_index = try self.object.resolveDecl(mod, decl_index);
...@@ -1274,6 +1308,14 @@ const DeclGen = struct {...@@ -1274,6 +1308,14 @@ const DeclGen = struct {
1274 return self.spv.resultId(type_ref);1308 return self.spv.resultId(type_ref);
1275 }1309 }
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
1277 fn typeId(self: *DeclGen, ty_ref: CacheRef) IdRef {1319 fn typeId(self: *DeclGen, ty_ref: CacheRef) IdRef {
1278 return self.spv.resultId(ty_ref);1320 return self.spv.resultId(ty_ref);
1279 }1321 }
...@@ -1297,11 +1339,6 @@ const DeclGen = struct {...@@ -1297,11 +1339,6 @@ const DeclGen = struct {
1297 return self.spv.intType(.unsigned, backing_bits);1339 return self.spv.intType(.unsigned, backing_bits);
1298 }1340 }
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
1305 fn ptrType(self: *DeclGen, child_ty: Type, storage_class: StorageClass) !CacheRef {1342 fn ptrType(self: *DeclGen, child_ty: Type, storage_class: StorageClass) !CacheRef {
1306 const key = .{ child_ty.toIntern(), storage_class };1343 const key = .{ child_ty.toIntern(), storage_class };
1307 const entry = try self.wip_pointers.getOrPut(self.gpa, key);1344 const entry = try self.wip_pointers.getOrPut(self.gpa, key);
...@@ -1367,7 +1404,7 @@ const DeclGen = struct {...@@ -1367,7 +1404,7 @@ const DeclGen = struct {
1367 var member_types: [4]CacheRef = undefined;1404 var member_types: [4]CacheRef = undefined;
1368 var member_names: [4]CacheString = undefined;1405 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
1372 if (layout.tag_size != 0) {1409 if (layout.tag_size != 0) {
1373 const tag_ty_ref = try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect);1410 const tag_ty_ref = try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect);
...@@ -1439,7 +1476,7 @@ const DeclGen = struct {...@@ -1439,7 +1476,7 @@ const DeclGen = struct {
1439 },1476 },
1440 .Bool => switch (repr) {1477 .Bool => switch (repr) {
1441 .direct => return try self.spv.resolve(.bool_type),1478 .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),
1443 },1480 },
1444 .Int => {1481 .Int => {
1445 const int_info = ty.intInfo(mod);1482 const int_info = ty.intInfo(mod);
...@@ -1548,7 +1585,7 @@ const DeclGen = struct {...@@ -1548,7 +1585,7 @@ const DeclGen = struct {
1548 .indirect => {1585 .indirect => {
1549 // TODO: Represent function pointers properly.1586 // TODO: Represent function pointers properly.
1550 // For now, just use an usize type.1587 // For now, just use an usize type.
1551 return try self.sizeType();1588 return try self.resolveType(Type.usize, .indirect);
1552 },1589 },
1553 },1590 },
1554 .Pointer => {1591 .Pointer => {
...@@ -1564,7 +1601,7 @@ const DeclGen = struct {...@@ -1564,7 +1601,7 @@ const DeclGen = struct {
1564 return ptr_ty_ref;1601 return ptr_ty_ref;
1565 }1602 }
15661603
1567 const size_ty_ref = try self.sizeType();1604 const size_ty_ref = try self.resolveType(Type.usize, .direct);
1568 return self.spv.resolve(.{ .struct_type = .{1605 return self.spv.resolve(.{ .struct_type = .{
1569 .member_types = &.{ ptr_ty_ref, size_ty_ref },1606 .member_types = &.{ ptr_ty_ref, size_ty_ref },
1570 .member_names = &.{1607 .member_names = &.{
...@@ -1680,7 +1717,7 @@ const DeclGen = struct {...@@ -1680,7 +1717,7 @@ const DeclGen = struct {
1680 return ty_ref;1717 return ty_ref;
1681 },1718 },
1682 .Union => return try self.resolveUnionType(ty),1719 .Union => return try self.resolveUnionType(ty),
1683 .ErrorSet => return try self.intType(.unsigned, 16),1720 .ErrorSet => return try self.resolveType(Type.u16, repr),
1684 .ErrorUnion => {1721 .ErrorUnion => {
1685 const payload_ty = ty.errorUnionPayload(mod);1722 const payload_ty = ty.errorUnionPayload(mod);
1686 const error_ty_ref = try self.resolveType(Type.anyerror, .indirect);1723 const error_ty_ref = try self.resolveType(Type.anyerror, .indirect);
...@@ -2202,12 +2239,12 @@ const DeclGen = struct {...@@ -2202,12 +2239,12 @@ const DeclGen = struct {
2202 }2239 }
2203 }2240 }
22042241
2205 fn intFromBool(self: *DeclGen, result_ty_ref: CacheRef, condition_id: IdRef) !IdRef {2242 fn intFromBool(self: *DeclGen, ty: Type, condition_id: IdRef) !IdRef {
2206 const zero_id = try self.constInt(result_ty_ref, 0);2243 const zero_id = try self.constInt(ty, 0, .direct);
2207 const one_id = try self.constInt(result_ty_ref, 1);2244 const one_id = try self.constInt(ty, 1, .direct);
2208 const result_id = self.spv.allocId();2245 const result_id = self.spv.allocId();
2209 try self.func.body.emit(self.spv.gpa, .OpSelect, .{2246 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),
2211 .id_result = result_id,2248 .id_result = result_id,
2212 .condition = condition_id,2249 .condition = condition_id,
2213 .object_1 = one_id,2250 .object_1 = one_id,
...@@ -2222,15 +2259,12 @@ const DeclGen = struct {...@@ -2222,15 +2259,12 @@ const DeclGen = struct {
2222 const mod = self.module;2259 const mod = self.module;
2223 return switch (ty.zigTypeTag(mod)) {2260 return switch (ty.zigTypeTag(mod)) {
2224 .Bool => blk: {2261 .Bool => blk: {
2225 const direct_bool_ty_ref = try self.resolveType(ty, .direct);
2226 const indirect_bool_ty_ref = try self.resolveType(ty, .indirect);
2227 const zero_id = try self.constInt(indirect_bool_ty_ref, 0);
2228 const result_id = self.spv.allocId();2262 const result_id = self.spv.allocId();
2229 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{2263 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),
2231 .id_result = result_id,2265 .id_result = result_id,
2232 .operand_1 = operand_id,2266 .operand_1 = operand_id,
2233 .operand_2 = zero_id,2267 .operand_2 = try self.constBool(false, .indirect),
2234 });2268 });
2235 break :blk result_id;2269 break :blk result_id;
2236 },2270 },
...@@ -2243,10 +2277,7 @@ const DeclGen = struct {...@@ -2243,10 +2277,7 @@ const DeclGen = struct {
2243 fn convertToIndirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef {2277 fn convertToIndirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef {
2244 const mod = self.module;2278 const mod = self.module;
2245 return switch (ty.zigTypeTag(mod)) {2279 return switch (ty.zigTypeTag(mod)) {
2246 .Bool => blk: {2280 .Bool => try self.intFromBool(Type.u1, operand_id),
2247 const indirect_bool_ty_ref = try self.resolveType(ty, .indirect);
2248 break :blk self.intFromBool(indirect_bool_ty_ref, operand_id);
2249 },
2250 else => operand_id,2281 else => operand_id,
2251 };2282 };
2252 }2283 }
...@@ -2529,7 +2560,7 @@ const DeclGen = struct {...@@ -2529,7 +2560,7 @@ const DeclGen = struct {
2529 try self.func.body.emit(self.spv.gpa, unsigned, args);2560 try self.func.body.emit(self.spv.gpa, unsigned, args);
2530 }2561 }
25312562
2532 result_id.* = try self.normalize(wip.ty_ref, value_id, info);2563 result_id.* = try self.normalize(wip.ty, value_id, info);
2533 }2564 }
2534 return try wip.finalize();2565 return try wip.finalize();
2535 }2566 }
...@@ -2622,7 +2653,7 @@ const DeclGen = struct {...@@ -2622,7 +2653,7 @@ const DeclGen = struct {
2622 /// - Signed integers are also sign extended if they are negative.2653 /// - Signed integers are also sign extended if they are negative.
2623 /// All other values are returned unmodified (this makes strange integer2654 /// All other values are returned unmodified (this makes strange integer
2624 /// wrapping easier to use in generic operations).2655 /// 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 {
2626 switch (info.class) {2657 switch (info.class) {
2627 .integer, .bool, .float => return value_id,2658 .integer, .bool, .float => return value_id,
2628 .composite_integer => unreachable, // TODO2659 .composite_integer => unreachable, // TODO
...@@ -2630,9 +2661,9 @@ const DeclGen = struct {...@@ -2630,9 +2661,9 @@ const DeclGen = struct {
2630 .unsigned => {2661 .unsigned => {
2631 const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1;2662 const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1;
2632 const result_id = self.spv.allocId();2663 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);
2634 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{2665 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),
2636 .id_result = result_id,2667 .id_result = result_id,
2637 .operand_1 = value_id,2668 .operand_1 = value_id,
2638 .operand_2 = mask_id,2669 .operand_2 = mask_id,
...@@ -2641,17 +2672,17 @@ const DeclGen = struct {...@@ -2641,17 +2672,17 @@ const DeclGen = struct {
2641 },2672 },
2642 .signed => {2673 .signed => {
2643 // Shift left and right so that we can copy the sight bit that way.2674 // 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);
2645 const left_id = self.spv.allocId();2676 const left_id = self.spv.allocId();
2646 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{2677 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),
2648 .id_result = left_id,2679 .id_result = left_id,
2649 .base = value_id,2680 .base = value_id,
2650 .shift = shift_amt_id,2681 .shift = shift_amt_id,
2651 });2682 });
2652 const right_id = self.spv.allocId();2683 const right_id = self.spv.allocId();
2653 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{2684 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),
2655 .id_result = right_id,2686 .id_result = right_id,
2656 .base = left_id,2687 .base = left_id,
2657 .shift = shift_amt_id,2688 .shift = shift_amt_id,
...@@ -2667,13 +2698,13 @@ const DeclGen = struct {...@@ -2667,13 +2698,13 @@ const DeclGen = struct {
2667 const lhs_id = try self.resolve(bin_op.lhs);2698 const lhs_id = try self.resolve(bin_op.lhs);
2668 const rhs_id = try self.resolve(bin_op.rhs);2699 const rhs_id = try self.resolve(bin_op.rhs);
2669 const ty = self.typeOfIndex(inst);2700 const ty = self.typeOfIndex(inst);
2670 const ty_ref = try self.resolveType(ty, .direct);2701 const ty_id = try self.resolveType2(ty, .direct);
2671 const info = self.arithmeticTypeInfo(ty);2702 const info = self.arithmeticTypeInfo(ty);
2672 switch (info.class) {2703 switch (info.class) {
2673 .composite_integer => unreachable, // TODO2704 .composite_integer => unreachable, // TODO
2674 .integer, .strange_integer => {2705 .integer, .strange_integer => {
2675 const zero_id = try self.constInt(ty_ref, 0);2706 const zero_id = try self.constInt(ty, 0, .direct);
2676 const one_id = try self.constInt(ty_ref, 1);2707 const one_id = try self.constInt(ty, 1, .direct);
26772708
2678 // (a ^ b) > 02709 // (a ^ b) > 0
2679 const bin_bitwise_id = try self.binOpSimple(ty, lhs_id, rhs_id, .OpBitwiseXor);2710 const bin_bitwise_id = try self.binOpSimple(ty, lhs_id, rhs_id, .OpBitwiseXor);
...@@ -2696,14 +2727,14 @@ const DeclGen = struct {...@@ -2696,14 +2727,14 @@ const DeclGen = struct {
2696 const negative_div_id = try self.arithOp(ty, negative_div_lhs, rhs_abs, .OpFDiv, .OpSDiv, .OpUDiv);2727 const negative_div_id = try self.arithOp(ty, negative_div_lhs, rhs_abs, .OpFDiv, .OpSDiv, .OpUDiv);
2697 const negated_negative_div_id = self.spv.allocId();2728 const negated_negative_div_id = self.spv.allocId();
2698 try self.func.body.emit(self.spv.gpa, .OpSNegate, .{2729 try self.func.body.emit(self.spv.gpa, .OpSNegate, .{
2699 .id_result_type = self.typeId(ty_ref),2730 .id_result_type = ty_id,
2700 .id_result = negated_negative_div_id,2731 .id_result = negated_negative_div_id,
2701 .operand = negative_div_id,2732 .operand = negative_div_id,
2702 });2733 });
27032734
2704 const result_id = self.spv.allocId();2735 const result_id = self.spv.allocId();
2705 try self.func.body.emit(self.spv.gpa, .OpSelect, .{2736 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
2706 .id_result_type = self.typeId(ty_ref),2737 .id_result_type = ty_id,
2707 .id_result = result_id,2738 .id_result = result_id,
2708 .condition = is_positive_id,2739 .condition = is_positive_id,
2709 .object_1 = positive_div_id,2740 .object_1 = positive_div_id,
...@@ -2819,7 +2850,7 @@ const DeclGen = struct {...@@ -2819,7 +2850,7 @@ const DeclGen = struct {
28192850
2820 // TODO: Trap on overflow? Probably going to be annoying.2851 // TODO: Trap on overflow? Probably going to be annoying.
2821 // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap.2852 // 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);
2823 }2854 }
28242855
2825 return try wip.finalize();2856 return try wip.finalize();
...@@ -2929,7 +2960,7 @@ const DeclGen = struct {...@@ -2929,7 +2960,7 @@ const DeclGen = struct {
2929 });2960 });
29302961
2931 // Normalize the result so that the comparisons go well2962 // 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
2934 const overflowed_id = switch (info.signedness) {2965 const overflowed_id = switch (info.signedness) {
2935 .unsigned => blk: {2966 .unsigned => blk: {
...@@ -2963,7 +2994,7 @@ const DeclGen = struct {...@@ -2963,7 +2994,7 @@ const DeclGen = struct {
2963 // = (rhs < 0) == (lhs > value)2994 // = (rhs < 0) == (lhs > value)
29642995
2965 const rhs_lt_zero_id = self.spv.allocId();2996 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);
2967 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{2998 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{
2968 .id_result_type = self.typeId(cmp_ty_ref),2999 .id_result_type = self.typeId(cmp_ty_ref),
2969 .id_result = rhs_lt_zero_id,3000 .id_result = rhs_lt_zero_id,
...@@ -2990,7 +3021,7 @@ const DeclGen = struct {...@@ -2990,7 +3021,7 @@ const DeclGen = struct {
2990 },3021 },
2991 };3022 };
29923023
2993 ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id);3024 ov_id.* = try self.intFromBool(wip_ov.ty, overflowed_id);
2994 }3025 }
29953026
2996 return try self.constructStruct(3027 return try self.constructStruct(
...@@ -3022,9 +3053,9 @@ const DeclGen = struct {...@@ -3022,9 +3053,9 @@ const DeclGen = struct {
3022 var wip_ov = try self.elementWise(ov_ty, true);3053 var wip_ov = try self.elementWise(ov_ty, true);
3023 defer wip_ov.deinit();3054 defer wip_ov.deinit();
30243055
3025 const zero_id = try self.constInt(wip_result.ty_ref, 0);3056 const zero_id = try self.constInt(wip_result.ty, 0, .direct);
3026 const zero_ov_id = try self.constInt(wip_ov.ty_ref, 0);3057 const zero_ov_id = try self.constInt(wip_ov.ty, 0, .direct);
3027 const one_ov_id = try self.constInt(wip_ov.ty_ref, 1);3058 const one_ov_id = try self.constInt(wip_ov.ty, 1, .direct);
30283059
3029 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {3060 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {
3030 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);3061 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);
...@@ -3109,7 +3140,7 @@ const DeclGen = struct {...@@ -3109,7 +3140,7 @@ const DeclGen = struct {
3109 .base = lhs_elem_id,3140 .base = lhs_elem_id,
3110 .shift = shift_id,3141 .shift = shift_id,
3111 });3142 });
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
3114 const right_shift_id = self.spv.allocId();3145 const right_shift_id = self.spv.allocId();
3115 switch (info.signedness) {3146 switch (info.signedness) {
...@@ -3139,7 +3170,7 @@ const DeclGen = struct {...@@ -3139,7 +3170,7 @@ const DeclGen = struct {
3139 .operand_2 = right_shift_id,3170 .operand_2 = right_shift_id,
3140 });3171 });
31413172
3142 ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id);3173 ov_id.* = try self.intFromBool(wip_ov.ty, overflowed_id);
3143 }3174 }
31443175
3145 return try self.constructStruct(3176 return try self.constructStruct(
...@@ -3351,7 +3382,7 @@ const DeclGen = struct {...@@ -3351,7 +3382,7 @@ const DeclGen = struct {
3351 for (wip.results, 0..) |*result_id, i| {3382 for (wip.results, 0..) |*result_id, i| {
3352 const elem = try mask.elemValue(mod, i);3383 const elem = try mask.elemValue(mod, i);
3353 if (elem.isUndef(mod)) {3384 if (elem.isUndef(mod)) {
3354 result_id.* = try self.spv.constUndef(wip.ty_ref);3385 result_id.* = try self.spv.constUndef(wip.ty_id);
3355 continue;3386 continue;
3356 }3387 }
33573388
...@@ -3366,11 +3397,10 @@ const DeclGen = struct {...@@ -3366,11 +3397,10 @@ const DeclGen = struct {
3366 }3397 }
33673398
3368 fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef {3399 fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef {
3369 const index_ty_ref = try self.intType(.unsigned, 32);
3370 const ids = try self.gpa.alloc(IdRef, indices.len);3400 const ids = try self.gpa.alloc(IdRef, indices.len);
3371 errdefer self.gpa.free(ids);3401 errdefer self.gpa.free(ids);
3372 for (indices, ids) |index, *id| {3402 for (indices, ids) |index, *id| {
3373 id.* = try self.constInt(index_ty_ref, index);3403 id.* = try self.constInt(Type.u32, index, .direct);
3374 }3404 }
33753405
3376 return ids;3406 return ids;
...@@ -3502,7 +3532,7 @@ const DeclGen = struct {...@@ -3502,7 +3532,7 @@ const DeclGen = struct {
3502 cmp_lhs_id = self.spv.allocId();3532 cmp_lhs_id = self.spv.allocId();
3503 cmp_rhs_id = self.spv.allocId();3533 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
3507 try self.func.body.emit(self.spv.gpa, .OpConvertPtrToU, .{3537 try self.func.body.emit(self.spv.gpa, .OpConvertPtrToU, .{
3508 .id_result_type = usize_ty_id,3538 .id_result_type = usize_ty_id,
...@@ -3761,7 +3791,7 @@ const DeclGen = struct {...@@ -3761,7 +3791,7 @@ const DeclGen = struct {
3761 // should we change the representation of strange integers?3791 // should we change the representation of strange integers?
3762 if (dst_ty.zigTypeTag(mod) == .Int) {3792 if (dst_ty.zigTypeTag(mod) == .Int) {
3763 const info = self.arithmeticTypeInfo(dst_ty);3793 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);
3765 }3795 }
37663796
3767 return result_id;3797 return result_id;
...@@ -3811,7 +3841,7 @@ const DeclGen = struct {...@@ -3811,7 +3841,7 @@ const DeclGen = struct {
3811 // type, we don't need to normalize when growing the type. The3841 // type, we don't need to normalize when growing the type. The
3812 // representation is already the same.3842 // representation is already the same.
3813 if (dst_info.bits < src_info.bits) {3843 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);
3815 } else {3845 } else {
3816 result_id.* = value_id;3846 result_id.* = value_id;
3817 }3847 }
...@@ -3898,7 +3928,7 @@ const DeclGen = struct {...@@ -3898,7 +3928,7 @@ const DeclGen = struct {
3898 defer wip.deinit();3928 defer wip.deinit();
3899 for (wip.results, 0..) |*result_id, i| {3929 for (wip.results, 0..) |*result_id, i| {
3900 const elem_id = try wip.elementAt(Type.bool, operand_id, i);3930 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);
3902 }3932 }
3903 return try wip.finalize();3933 return try wip.finalize();
3904 }3934 }
...@@ -3958,10 +3988,9 @@ const DeclGen = struct {...@@ -3958,10 +3988,9 @@ const DeclGen = struct {
3958 const elem_ptr_ty = slice_ty.slicePtrFieldType(mod);3988 const elem_ptr_ty = slice_ty.slicePtrFieldType(mod);
39593989
3960 const elem_ptr_ty_ref = try self.resolveType(elem_ptr_ty, .direct);3990 const elem_ptr_ty_ref = try self.resolveType(elem_ptr_ty, .direct);
3961 const size_ty_ref = try self.sizeType();
39623991
3963 const array_ptr_id = try self.resolve(ty_op.operand);3992 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
3966 const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))3995 const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))
3967 // Note: The pointer is something like *opaque{}, so we need to bitcast it to the element type.3996 // Note: The pointer is something like *opaque{}, so we need to bitcast it to the element type.
...@@ -4092,8 +4121,8 @@ const DeclGen = struct {...@@ -4092,8 +4121,8 @@ const DeclGen = struct {
4092 const array_ty = ty.childType(mod);4121 const array_ty = ty.childType(mod);
4093 const elem_ty = array_ty.childType(mod);4122 const elem_ty = array_ty.childType(mod);
4094 const abi_size = elem_ty.abiSize(mod);4123 const abi_size = elem_ty.abiSize(mod);
4095 const usize_ty_ref = try self.resolveType(Type.usize, .direct);4124 const size = array_ty.arrayLenIncludingSentinel(mod) * abi_size;
4096 return self.spv.constInt(usize_ty_ref, array_ty.arrayLenIncludingSentinel(mod) * abi_size);4125 return try self.constInt(Type.usize, size, .direct);
4097 },4126 },
4098 .Many, .C => unreachable,4127 .Many, .C => unreachable,
4099 }4128 }
...@@ -4298,6 +4327,8 @@ const DeclGen = struct {...@@ -4298,6 +4327,8 @@ const DeclGen = struct {
4298 // union type, then get the field pointer and pointer-cast it to the4327 // union type, then get the field pointer and pointer-cast it to the
4299 // right type to store it. Finally load the entire union.4328 // 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
4301 const mod = self.module;4332 const mod = self.module;
4302 const ip = &mod.intern_pool;4333 const ip = &mod.intern_pool;
4303 const union_ty = mod.typeToUnion(ty).?;4334 const union_ty = mod.typeToUnion(ty).?;
...@@ -4316,17 +4347,15 @@ const DeclGen = struct {...@@ -4316,17 +4347,15 @@ const DeclGen = struct {
4316 } else 0;4347 } else 0;
43174348
4318 if (!layout.has_payload) {4349 if (!layout.has_payload) {
4319 const tag_ty_ref = try self.resolveType(tag_ty, .direct);4350 return try self.constInt(tag_ty, tag_int, .direct);
4320 return try self.constInt(tag_ty_ref, tag_int);
4321 }4351 }
43224352
4323 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });4353 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });
43244354
4325 if (layout.tag_size != 0) {4355 if (layout.tag_size != 0) {
4326 const tag_ty_ref = try self.resolveType(tag_ty, .direct);
4327 const tag_ptr_ty_ref = try self.ptrType(tag_ty, .Function);4356 const tag_ptr_ty_ref = try self.ptrType(tag_ty, .Function);
4328 const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});4357 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);
4330 try self.store(tag_ty, ptr_id, tag_id, .{});4359 try self.store(tag_ty, ptr_id, tag_id, .{});
4331 }4360 }
43324361
...@@ -4420,8 +4449,6 @@ const DeclGen = struct {...@@ -4420,8 +4449,6 @@ const DeclGen = struct {
44204449
4421 const parent_ty = ty_pl.ty.toType().childType(mod);4450 const parent_ty = ty_pl.ty.toType().childType(mod);
4422 const res_ty = try self.resolveType(ty_pl.ty.toType(), .indirect);4451 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
4426 const field_ptr = try self.resolve(extra.field_ptr);4453 const field_ptr = try self.resolve(extra.field_ptr);
4427 const field_ptr_int = try self.intFromPtr(field_ptr);4454 const field_ptr_int = try self.intFromPtr(field_ptr);
...@@ -4430,8 +4457,8 @@ const DeclGen = struct {...@@ -4430,8 +4457,8 @@ const DeclGen = struct {
4430 const base_ptr_int = base_ptr_int: {4457 const base_ptr_int = base_ptr_int: {
4431 if (field_offset == 0) break :base_ptr_int field_ptr_int;4458 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);4460 const field_offset_id = try self.constInt(Type.usize, field_offset, .direct);
4434 break :base_ptr_int try self.binOpSimple(usize_ty, field_ptr_int, field_offset_id, .OpISub);4461 break :base_ptr_int try self.binOpSimple(Type.usize, field_ptr_int, field_offset_id, .OpISub);
4435 };4462 };
44364463
4437 const base_ptr = self.spv.allocId();4464 const base_ptr = self.spv.allocId();
...@@ -4469,7 +4496,7 @@ const DeclGen = struct {...@@ -4469,7 +4496,7 @@ const DeclGen = struct {
4469 if (!layout.has_payload) {4496 if (!layout.has_payload) {
4470 // Asked to get a pointer to a zero-sized field. Just lower this4497 // Asked to get a pointer to a zero-sized field. Just lower this
4471 // to undefined, there is no reason to make it be a valid pointer.4498 // 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));
4473 }4500 }
44744501
4475 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(mod));4502 const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(mod));
...@@ -4563,7 +4590,7 @@ const DeclGen = struct {...@@ -4563,7 +4590,7 @@ const DeclGen = struct {
4563 assert(self.control_flow == .structured);4590 assert(self.control_flow == .structured);
45644591
4565 const result_id = self.spv.allocId();4592 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);
4567 try self.func.body.emitRaw(self.spv.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent...4594 try self.func.body.emitRaw(self.spv.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent...
4568 self.func.body.writeOperand(spec.IdResultType, self.typeId(block_id_ty_ref));4595 self.func.body.writeOperand(spec.IdResultType, self.typeId(block_id_ty_ref));
4569 self.func.body.writeOperand(spec.IdRef, result_id);4596 self.func.body.writeOperand(spec.IdRef, result_id);
...@@ -4663,8 +4690,8 @@ const DeclGen = struct {...@@ -4663,8 +4690,8 @@ const DeclGen = struct {
4663 // Make sure that we are still in a block when exiting the function.4690 // Make sure that we are still in a block when exiting the function.
4664 // TODO: Can we get rid of that?4691 // TODO: Can we get rid of that?
4665 try self.beginSpvBlock(self.spv.allocId());4692 try self.beginSpvBlock(self.spv.allocId());
4666 const block_id_ty_ref = try self.intType(.unsigned, 32);4693 const block_id_ty_ref = try self.resolveType(Type.u32, .direct);
4667 return try self.spv.constUndef(block_id_ty_ref);4694 return try self.spv.constUndef(self.typeId(block_id_ty_ref));
4668 }4695 }
46694696
4670 // The top-most merge actually only has a single source, the4697 // The top-most merge actually only has a single source, the
...@@ -4781,8 +4808,7 @@ const DeclGen = struct {...@@ -4781,8 +4808,7 @@ const DeclGen = struct {
4781 assert(cf.block_stack.items.len > 0);4808 assert(cf.block_stack.items.len > 0);
47824809
4783 // Check if the target of the branch was this current block.4810 // Check if the target of the branch was this current block.
4784 const block_id_ty_ref = try self.intType(.unsigned, 32);4811 const this_block = try self.constInt(Type.u32, @intFromEnum(inst), .direct);
4785 const this_block = try self.constInt(block_id_ty_ref, @intFromEnum(inst));
4786 const jump_to_this_block_id = self.spv.allocId();4812 const jump_to_this_block_id = self.spv.allocId();
4787 const bool_ty_ref = try self.resolveType(Type.bool, .direct);4813 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
4788 try self.func.body.emit(self.spv.gpa, .OpIEqual, .{4814 try self.func.body.emit(self.spv.gpa, .OpIEqual, .{
...@@ -4862,8 +4888,7 @@ const DeclGen = struct {...@@ -4862,8 +4888,7 @@ const DeclGen = struct {
4862 try self.store(operand_ty, block_result_var_id, operand_id, .{});4888 try self.store(operand_ty, block_result_var_id, operand_id, .{});
4863 }4889 }
48644890
4865 const block_id_ty_ref = try self.intType(.unsigned, 32);4891 const next_block = try self.constInt(Type.u32, @intFromEnum(br.block_inst), .direct);
4866 const next_block = try self.constInt(block_id_ty_ref, @intFromEnum(br.block_inst));
4867 try self.structuredBreak(next_block);4892 try self.structuredBreak(next_block);
4868 },4893 },
4869 .unstructured => |cf| {4894 .unstructured => |cf| {
...@@ -5026,8 +5051,7 @@ const DeclGen = struct {...@@ -5026,8 +5051,7 @@ const DeclGen = struct {
5026 // Functions with an empty error set are emitted with an error code5051 // Functions with an empty error set are emitted with an error code
5027 // return type and return zero so they can be function pointers coerced5052 // return type and return zero so they can be function pointers coerced
5028 // to functions that return anyerror.5053 // to functions that return anyerror.
5029 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);5054 const no_err_id = try self.constInt(Type.anyerror, 0, .direct);
5030 const no_err_id = try self.constInt(err_ty_ref, 0);
5031 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });5055 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });
5032 } else {5056 } else {
5033 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});5057 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});
...@@ -5051,8 +5075,7 @@ const DeclGen = struct {...@@ -5051,8 +5075,7 @@ const DeclGen = struct {
5051 // Functions with an empty error set are emitted with an error code5075 // Functions with an empty error set are emitted with an error code
5052 // return type and return zero so they can be function pointers coerced5076 // return type and return zero so they can be function pointers coerced
5053 // to functions that return anyerror.5077 // to functions that return anyerror.
5054 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);5078 const no_err_id = try self.constInt(Type.anyerror, 0, .direct);
5055 const no_err_id = try self.constInt(err_ty_ref, 0);
5056 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });5079 return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id });
5057 } else {5080 } else {
5058 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});5081 return try self.func.body.emit(self.spv.gpa, .OpReturn, {});
...@@ -5076,7 +5099,6 @@ const DeclGen = struct {...@@ -5076,7 +5099,6 @@ const DeclGen = struct {
5076 const err_union_ty = self.typeOf(pl_op.operand);5099 const err_union_ty = self.typeOf(pl_op.operand);
5077 const payload_ty = self.typeOfIndex(inst);5100 const payload_ty = self.typeOfIndex(inst);
50785101
5079 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
5080 const bool_ty_ref = try self.resolveType(Type.bool, .direct);5102 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
50815103
5082 const eu_layout = self.errorUnionLayout(payload_ty);5104 const eu_layout = self.errorUnionLayout(payload_ty);
...@@ -5087,7 +5109,7 @@ const DeclGen = struct {...@@ -5087,7 +5109,7 @@ const DeclGen = struct {
5087 else5109 else
5088 err_union_id;5110 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);
5091 const is_err_id = self.spv.allocId();5113 const is_err_id = self.spv.allocId();
5092 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{5114 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
5093 .id_result_type = self.typeId(bool_ty_ref),5115 .id_result_type = self.typeId(bool_ty_ref),
...@@ -5146,7 +5168,7 @@ const DeclGen = struct {...@@ -5146,7 +5168,7 @@ const DeclGen = struct {
51465168
5147 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {5169 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
5148 // No error possible, so just return undefined.5170 // 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));
5150 }5172 }
51515173
5152 const payload_ty = err_union_ty.errorUnionPayload(mod);5174 const payload_ty = err_union_ty.errorUnionPayload(mod);
...@@ -5189,7 +5211,7 @@ const DeclGen = struct {...@@ -5189,7 +5211,7 @@ const DeclGen = struct {
51895211
5190 var members: [2]IdRef = undefined;5212 var members: [2]IdRef = undefined;
5191 members[eu_layout.errorFieldIndex()] = operand_id;5213 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
5194 var types: [2]Type = undefined;5216 var types: [2]Type = undefined;
5195 types[eu_layout.errorFieldIndex()] = Type.anyerror;5217 types[eu_layout.errorFieldIndex()] = Type.anyerror;
...@@ -5203,15 +5225,14 @@ const DeclGen = struct {...@@ -5203,15 +5225,14 @@ const DeclGen = struct {
5203 const err_union_ty = self.typeOfIndex(inst);5225 const err_union_ty = self.typeOfIndex(inst);
5204 const operand_id = try self.resolve(ty_op.operand);5226 const operand_id = try self.resolve(ty_op.operand);
5205 const payload_ty = self.typeOf(ty_op.operand);5227 const payload_ty = self.typeOf(ty_op.operand);
5206 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
5207 const eu_layout = self.errorUnionLayout(payload_ty);5228 const eu_layout = self.errorUnionLayout(payload_ty);
52085229
5209 if (!eu_layout.payload_has_bits) {5230 if (!eu_layout.payload_has_bits) {
5210 return try self.constInt(err_ty_ref, 0);5231 return try self.constInt(Type.anyerror, 0, .direct);
5211 }5232 }
52125233
5213 var members: [2]IdRef = undefined;5234 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);
5215 members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id);5236 members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id);
52165237
5217 var types: [2]Type = undefined;5238 var types: [2]Type = undefined;
...@@ -5248,8 +5269,8 @@ const DeclGen = struct {...@@ -5248,8 +5269,8 @@ const DeclGen = struct {
5248 else5269 else
5249 loaded_id;5270 loaded_id;
52505271
5251 const payload_ty_ref = try self.resolveType(ptr_ty, .direct);5272 const payload_ty_id = try self.resolveType2(ptr_ty, .direct);
5252 const null_id = try self.spv.constNull(payload_ty_ref);5273 const null_id = try self.spv.constNull(payload_ty_id);
5253 const op: std.math.CompareOperator = switch (pred) {5274 const op: std.math.CompareOperator = switch (pred) {
5254 .is_null => .eq,5275 .is_null => .eq,
5255 .is_non_null => .neq,5276 .is_non_null => .neq,
...@@ -5306,7 +5327,6 @@ const DeclGen = struct {...@@ -5306,7 +5327,6 @@ const DeclGen = struct {
5306 const payload_ty = err_union_ty.errorUnionPayload(mod);5327 const payload_ty = err_union_ty.errorUnionPayload(mod);
5307 const eu_layout = self.errorUnionLayout(payload_ty);5328 const eu_layout = self.errorUnionLayout(payload_ty);
5308 const bool_ty_ref = try self.resolveType(Type.bool, .direct);5329 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
5309 const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
53105330
5311 const error_id = if (!eu_layout.payload_has_bits)5331 const error_id = if (!eu_layout.payload_has_bits)
5312 operand_id5332 operand_id
...@@ -5318,7 +5338,7 @@ const DeclGen = struct {...@@ -5318,7 +5338,7 @@ const DeclGen = struct {
5318 .id_result_type = self.typeId(bool_ty_ref),5338 .id_result_type = self.typeId(bool_ty_ref),
5319 .id_result = result_id,5339 .id_result = result_id,
5320 .operand_1 = error_id,5340 .operand_1 = error_id,
5321 .operand_2 = try self.constInt(err_ty_ref, 0),5341 .operand_2 = try self.constInt(Type.anyerror, 0, .direct),
5322 };5342 };
5323 switch (pred) {5343 switch (pred) {
5324 .is_err => try self.func.body.emit(self.spv.gpa, .OpINotEqual, operands),5344 .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 {...@@ -435,28 +435,22 @@ pub fn arrayType(self: *Module, len: u32, elem_ty_ref: CacheRef) !CacheRef {
435 } });435 } });
436}436}
437437
438pub fn constInt(self: *Module, ty_ref: CacheRef, value: anytype) !IdRef {438pub fn constUndef(self: *Module, ty_id: IdRef) !IdRef {
439 const ty = self.cache.lookup(ty_ref).int_type;439 const result_id = self.allocId();
440 const Value = Cache.Key.Int.Value;440 try self.sections.types_globals_constants.emit(self.gpa, .OpUndef, .{
441 return try self.resolveId(.{ .int = .{441 .id_result_type = ty_id,
442 .ty = ty_ref,442 .id_result = result_id,
443 .value = switch (ty.signedness) {443 });
444 .signed => Value{ .int64 = @intCast(value) },444 return result_id;
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 } });
456}445}
457446
458pub fn constBool(self: *Module, ty_ref: CacheRef, value: bool) !IdRef {447pub fn constNull(self: *Module, ty_id: IdRef) !IdRef {
459 return try self.resolveId(.{ .bool = .{ .ty = ty_ref, .value = value } });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;
460}454}
461455
462pub fn constComposite(self: *Module, ty_ref: CacheRef, members: []const IdRef) !IdRef {456pub fn constComposite(self: *Module, ty_ref: CacheRef, members: []const IdRef) !IdRef {