| ... | ... | @@ -41,6 +41,8 @@ const SpvTypeInfo = struct { |
| 41 | 41 | |
| 42 | 42 | const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, SpvTypeInfo); |
| 43 | 43 | |
| 44 | const InternMap = std.AutoHashMapUnmanaged(struct { InternPool.Index, DeclGen.Repr }, IdResult); |
| 45 | |
| 44 | 46 | const ControlFlow = union(enum) { |
| 45 | 47 | const Structured = struct { |
| 46 | 48 | /// This type indicates the way that a block is terminated. The |
| ... | ... | @@ -171,6 +173,8 @@ pub const Object = struct { |
| 171 | 173 | /// of the SPIR-V module. |
| 172 | 174 | type_map: TypeMap = .{}, |
| 173 | 175 | |
| 176 | intern_map: InternMap = .{}, |
| 177 | |
| 174 | 178 | pub fn init(gpa: Allocator) Object { |
| 175 | 179 | return .{ |
| 176 | 180 | .gpa = gpa, |
| ... | ... | @@ -183,6 +187,7 @@ pub const Object = struct { |
| 183 | 187 | self.decl_link.deinit(self.gpa); |
| 184 | 188 | self.anon_decl_link.deinit(self.gpa); |
| 185 | 189 | self.type_map.deinit(self.gpa); |
| 190 | self.intern_map.deinit(self.gpa); |
| 186 | 191 | } |
| 187 | 192 | |
| 188 | 193 | fn genDecl( |
| ... | ... | @@ -205,6 +210,7 @@ pub const Object = struct { |
| 205 | 210 | .air = air, |
| 206 | 211 | .liveness = liveness, |
| 207 | 212 | .type_map = &self.type_map, |
| 213 | .intern_map = &self.intern_map, |
| 208 | 214 | .control_flow = switch (structured_cfg) { |
| 209 | 215 | true => .{ .structured = .{} }, |
| 210 | 216 | false => .{ .unstructured = .{} }, |
| ... | ... | @@ -313,6 +319,8 @@ const DeclGen = struct { |
| 313 | 319 | /// See Object.type_map |
| 314 | 320 | type_map: *TypeMap, |
| 315 | 321 | |
| 322 | intern_map: *InternMap, |
| 323 | |
| 316 | 324 | /// Child types of pointers that are currently in progress of being resolved. If a pointer |
| 317 | 325 | /// is already in this map, its recursive. |
| 318 | 326 | wip_pointers: std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, CacheRef) = .{}, |
| ... | ... | @@ -696,14 +704,25 @@ const DeclGen = struct { |
| 696 | 704 | |
| 697 | 705 | /// Emits a bool constant in a particular representation. |
| 698 | 706 | fn constBool(self: *DeclGen, value: bool, repr: Repr) !IdRef { |
| 707 | // TODO: Cache? |
| 708 | |
| 709 | const section = &self.spv.sections.types_globals_constants; |
| 699 | 710 | switch (repr) { |
| 700 | 711 | .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); |
| 703 | 713 | }, |
| 704 | 714 | .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; |
| 707 | 726 | }, |
| 708 | 727 | } |
| 709 | 728 | } |
| ... | ... | @@ -711,68 +730,63 @@ const DeclGen = struct { |
| 711 | 730 | /// Emits an integer constant. |
| 712 | 731 | /// This function, unlike SpvModule.constInt, takes care to bitcast |
| 713 | 732 | /// 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 | }; |
| 732 | 747 | |
| 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 |
| 745 | 771 | } |
| 746 | | } |
| 747 | 772 | |
| 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; |
| 766 | 775 | } |
| 767 | 776 | |
| 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; |
| 776 | 790 | } |
| 777 | 791 | |
| 778 | 792 | /// Construct a struct at runtime. |
| ... | ... | @@ -852,258 +866,279 @@ const DeclGen = struct { |
| 852 | 866 | /// is done by emitting a sequence of instructions that initialize the value. |
| 853 | 867 | // |
| 854 | 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 | 877 | const mod = self.module; |
| 857 | 878 | const target = self.getTarget(); |
| 858 | 879 | const result_ty_ref = try self.resolveType(ty, repr); |
| 880 | const result_ty_id = self.typeId(result_ty_ref); |
| 859 | 881 | const ip = &mod.intern_pool; |
| 860 | 882 | |
| 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) }); |
| 864 | 884 | 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, |
| 903 | 917 | => unreachable, // non-runtime values |
| 904 | 918 | |
| 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 |
| 964 | 927 | |
| 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); |
| 993 | 933 | } 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); |
| 996 | 977 | } |
| 997 | | } |
| 998 | | |
| 999 | | // Optional representation is a structure. |
| 1000 | | // { Payload, Bool } |
| 1001 | 978 | |
| 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 | }); |
| 1007 | 983 | |
| 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 }; |
| 1041 | 994 | } |
| 1042 | 995 | |
| 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); |
| 1054 | 1002 | }, |
| 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 | } |
| 1059 | 1027 | } |
| 1060 | 1028 | |
| 1061 | | var types = std.ArrayList(Type).init(self.gpa); |
| 1062 | | defer types.deinit(); |
| 1029 | // Optional representation is a structure. |
| 1030 | // { Payload, Bool } |
| 1063 | 1031 | |
| 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)); |
| 1066 | 1037 | |
| 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 | }, |
| 1073 | 1070 | } |
| 1074 | 1071 | |
| 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 | } |
| 1078 | 1089 | |
| 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); |
| 1082 | 1107 | |
| 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, // 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; |
| 1100 | 1134 | } |
| 1101 | 1135 | |
| 1102 | 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 | 1138 | const result_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 1104 | 1139 | const mod = self.module; |
| 1105 | 1140 | |
| 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); |
| 1107 | 1142 | |
| 1108 | 1143 | switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { |
| 1109 | 1144 | .decl => |decl| return try self.constantDeclRef(ptr_ty, decl), |
| ... | ... | @@ -1126,8 +1161,7 @@ const DeclGen = struct { |
| 1126 | 1161 | .elem => |elem_ptr| { |
| 1127 | 1162 | const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base)); |
| 1128 | 1163 | 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); |
| 1131 | 1165 | |
| 1132 | 1166 | const elem_ptr_id = try self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id); |
| 1133 | 1167 | |
| ... | ... | @@ -1181,7 +1215,7 @@ const DeclGen = struct { |
| 1181 | 1215 | // const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn; |
| 1182 | 1216 | if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { |
| 1183 | 1217 | // Pointer to nothing - return undefoined |
| 1184 | | return self.spv.constUndef(ty_ref); |
| 1218 | return self.spv.constUndef(self.typeId(ty_ref)); |
| 1185 | 1219 | } |
| 1186 | 1220 | |
| 1187 | 1221 | if (decl_ty.zigTypeTag(mod) == .Fn) { |
| ... | ... | @@ -1217,7 +1251,7 @@ const DeclGen = struct { |
| 1217 | 1251 | .func => { |
| 1218 | 1252 | // TODO: Properly lower function pointers. For now we are going to hack around it and |
| 1219 | 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 | 1256 | .extern_func => unreachable, // TODO |
| 1223 | 1257 | else => {}, |
| ... | ... | @@ -1225,7 +1259,7 @@ const DeclGen = struct { |
| 1225 | 1259 | |
| 1226 | 1260 | if (!decl.typeOf(mod).isFnOrHasRuntimeBitsIgnoreComptime(mod)) { |
| 1227 | 1261 | // Pointer to nothing - return undefined. |
| 1228 | | return self.spv.constUndef(ty_ref); |
| 1262 | return self.spv.constUndef(ty_id); |
| 1229 | 1263 | } |
| 1230 | 1264 | |
| 1231 | 1265 | const spv_decl_index = try self.object.resolveDecl(mod, decl_index); |
| ... | ... | @@ -1274,6 +1308,14 @@ const DeclGen = struct { |
| 1274 | 1308 | return self.spv.resultId(type_ref); |
| 1275 | 1309 | } |
| 1276 | 1310 | |
| 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 | 1319 | fn typeId(self: *DeclGen, ty_ref: CacheRef) IdRef { |
| 1278 | 1320 | return self.spv.resultId(ty_ref); |
| 1279 | 1321 | } |
| ... | ... | @@ -1297,11 +1339,6 @@ const DeclGen = struct { |
| 1297 | 1339 | return self.spv.intType(.unsigned, backing_bits); |
| 1298 | 1340 | } |
| 1299 | 1341 | |
| 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 | 1342 | fn ptrType(self: *DeclGen, child_ty: Type, storage_class: StorageClass) !CacheRef { |
| 1306 | 1343 | const key = .{ child_ty.toIntern(), storage_class }; |
| 1307 | 1344 | const entry = try self.wip_pointers.getOrPut(self.gpa, key); |
| ... | ... | @@ -1367,7 +1404,7 @@ const DeclGen = struct { |
| 1367 | 1404 | var member_types: [4]CacheRef = undefined; |
| 1368 | 1405 | var member_names: [4]CacheString = undefined; |
| 1369 | 1406 | |
| 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? |
| 1371 | 1408 | |
| 1372 | 1409 | if (layout.tag_size != 0) { |
| 1373 | 1410 | const tag_ty_ref = try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect); |
| ... | ... | @@ -1439,7 +1476,7 @@ const DeclGen = struct { |
| 1439 | 1476 | }, |
| 1440 | 1477 | .Bool => switch (repr) { |
| 1441 | 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 | 1481 | .Int => { |
| 1445 | 1482 | const int_info = ty.intInfo(mod); |
| ... | ... | @@ -1548,7 +1585,7 @@ const DeclGen = struct { |
| 1548 | 1585 | .indirect => { |
| 1549 | 1586 | // TODO: Represent function pointers properly. |
| 1550 | 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 | 1591 | .Pointer => { |
| ... | ... | @@ -1564,7 +1601,7 @@ const DeclGen = struct { |
| 1564 | 1601 | return ptr_ty_ref; |
| 1565 | 1602 | } |
| 1566 | 1603 | |
| 1567 | | const size_ty_ref = try self.sizeType(); |
| 1604 | const size_ty_ref = try self.resolveType(Type.usize, .direct); |
| 1568 | 1605 | return self.spv.resolve(.{ .struct_type = .{ |
| 1569 | 1606 | .member_types = &.{ ptr_ty_ref, size_ty_ref }, |
| 1570 | 1607 | .member_names = &.{ |
| ... | ... | @@ -1680,7 +1717,7 @@ const DeclGen = struct { |
| 1680 | 1717 | return ty_ref; |
| 1681 | 1718 | }, |
| 1682 | 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 | 1721 | .ErrorUnion => { |
| 1685 | 1722 | const payload_ty = ty.errorUnionPayload(mod); |
| 1686 | 1723 | const error_ty_ref = try self.resolveType(Type.anyerror, .indirect); |
| ... | ... | @@ -2202,12 +2239,12 @@ const DeclGen = struct { |
| 2202 | 2239 | } |
| 2203 | 2240 | } |
| 2204 | 2241 | |
| 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); |
| 2208 | 2245 | const result_id = self.spv.allocId(); |
| 2209 | 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 | 2248 | .id_result = result_id, |
| 2212 | 2249 | .condition = condition_id, |
| 2213 | 2250 | .object_1 = one_id, |
| ... | ... | @@ -2222,15 +2259,12 @@ const DeclGen = struct { |
| 2222 | 2259 | const mod = self.module; |
| 2223 | 2260 | return switch (ty.zigTypeTag(mod)) { |
| 2224 | 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 | 2262 | const result_id = self.spv.allocId(); |
| 2229 | 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 | 2265 | .id_result = result_id, |
| 2232 | 2266 | .operand_1 = operand_id, |
| 2233 | | .operand_2 = zero_id, |
| 2267 | .operand_2 = try self.constBool(false, .indirect), |
| 2234 | 2268 | }); |
| 2235 | 2269 | break :blk result_id; |
| 2236 | 2270 | }, |
| ... | ... | @@ -2243,10 +2277,7 @@ const DeclGen = struct { |
| 2243 | 2277 | fn convertToIndirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef { |
| 2244 | 2278 | const mod = self.module; |
| 2245 | 2279 | 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), |
| 2250 | 2281 | else => operand_id, |
| 2251 | 2282 | }; |
| 2252 | 2283 | } |
| ... | ... | @@ -2529,7 +2560,7 @@ const DeclGen = struct { |
| 2529 | 2560 | try self.func.body.emit(self.spv.gpa, unsigned, args); |
| 2530 | 2561 | } |
| 2531 | 2562 | |
| 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 | 2565 | return try wip.finalize(); |
| 2535 | 2566 | } |
| ... | ... | @@ -2622,7 +2653,7 @@ const DeclGen = struct { |
| 2622 | 2653 | /// - Signed integers are also sign extended if they are negative. |
| 2623 | 2654 | /// All other values are returned unmodified (this makes strange integer |
| 2624 | 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 | 2657 | switch (info.class) { |
| 2627 | 2658 | .integer, .bool, .float => return value_id, |
| 2628 | 2659 | .composite_integer => unreachable, // TODO |
| ... | ... | @@ -2630,9 +2661,9 @@ const DeclGen = struct { |
| 2630 | 2661 | .unsigned => { |
| 2631 | 2662 | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; |
| 2632 | 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 | 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 | 2667 | .id_result = result_id, |
| 2637 | 2668 | .operand_1 = value_id, |
| 2638 | 2669 | .operand_2 = mask_id, |
| ... | ... | @@ -2641,17 +2672,17 @@ const DeclGen = struct { |
| 2641 | 2672 | }, |
| 2642 | 2673 | .signed => { |
| 2643 | 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 | 2676 | const left_id = self.spv.allocId(); |
| 2646 | 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 | 2679 | .id_result = left_id, |
| 2649 | 2680 | .base = value_id, |
| 2650 | 2681 | .shift = shift_amt_id, |
| 2651 | 2682 | }); |
| 2652 | 2683 | const right_id = self.spv.allocId(); |
| 2653 | 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 | 2686 | .id_result = right_id, |
| 2656 | 2687 | .base = left_id, |
| 2657 | 2688 | .shift = shift_amt_id, |
| ... | ... | @@ -2667,13 +2698,13 @@ const DeclGen = struct { |
| 2667 | 2698 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2668 | 2699 | const rhs_id = try self.resolve(bin_op.rhs); |
| 2669 | 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 | 2702 | const info = self.arithmeticTypeInfo(ty); |
| 2672 | 2703 | switch (info.class) { |
| 2673 | 2704 | .composite_integer => unreachable, // TODO |
| 2674 | 2705 | .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); |
| 2677 | 2708 | |
| 2678 | 2709 | // (a ^ b) > 0 |
| 2679 | 2710 | const bin_bitwise_id = try self.binOpSimple(ty, lhs_id, rhs_id, .OpBitwiseXor); |
| ... | ... | @@ -2696,14 +2727,14 @@ const DeclGen = struct { |
| 2696 | 2727 | const negative_div_id = try self.arithOp(ty, negative_div_lhs, rhs_abs, .OpFDiv, .OpSDiv, .OpUDiv); |
| 2697 | 2728 | const negated_negative_div_id = self.spv.allocId(); |
| 2698 | 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 | 2731 | .id_result = negated_negative_div_id, |
| 2701 | 2732 | .operand = negative_div_id, |
| 2702 | 2733 | }); |
| 2703 | 2734 | |
| 2704 | 2735 | const result_id = self.spv.allocId(); |
| 2705 | 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 | 2738 | .id_result = result_id, |
| 2708 | 2739 | .condition = is_positive_id, |
| 2709 | 2740 | .object_1 = positive_div_id, |
| ... | ... | @@ -2819,7 +2850,7 @@ const DeclGen = struct { |
| 2819 | 2850 | |
| 2820 | 2851 | // TODO: Trap on overflow? Probably going to be annoying. |
| 2821 | 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 | } |
| 2824 | 2855 | |
| 2825 | 2856 | return try wip.finalize(); |
| ... | ... | @@ -2929,7 +2960,7 @@ const DeclGen = struct { |
| 2929 | 2960 | }); |
| 2930 | 2961 | |
| 2931 | 2962 | // 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); |
| 2933 | 2964 | |
| 2934 | 2965 | const overflowed_id = switch (info.signedness) { |
| 2935 | 2966 | .unsigned => blk: { |
| ... | ... | @@ -2963,7 +2994,7 @@ const DeclGen = struct { |
| 2963 | 2994 | // = (rhs < 0) == (lhs > value) |
| 2964 | 2995 | |
| 2965 | 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 | 2998 | try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{ |
| 2968 | 2999 | .id_result_type = self.typeId(cmp_ty_ref), |
| 2969 | 3000 | .id_result = rhs_lt_zero_id, |
| ... | ... | @@ -2990,7 +3021,7 @@ const DeclGen = struct { |
| 2990 | 3021 | }, |
| 2991 | 3022 | }; |
| 2992 | 3023 | |
| 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 | } |
| 2995 | 3026 | |
| 2996 | 3027 | return try self.constructStruct( |
| ... | ... | @@ -3022,9 +3053,9 @@ const DeclGen = struct { |
| 3022 | 3053 | var wip_ov = try self.elementWise(ov_ty, true); |
| 3023 | 3054 | defer wip_ov.deinit(); |
| 3024 | 3055 | |
| 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); |
| 3028 | 3059 | |
| 3029 | 3060 | for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| { |
| 3030 | 3061 | const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i); |
| ... | ... | @@ -3109,7 +3140,7 @@ const DeclGen = struct { |
| 3109 | 3140 | .base = lhs_elem_id, |
| 3110 | 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); |
| 3113 | 3144 | |
| 3114 | 3145 | const right_shift_id = self.spv.allocId(); |
| 3115 | 3146 | switch (info.signedness) { |
| ... | ... | @@ -3139,7 +3170,7 @@ const DeclGen = struct { |
| 3139 | 3170 | .operand_2 = right_shift_id, |
| 3140 | 3171 | }); |
| 3141 | 3172 | |
| 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 | } |
| 3144 | 3175 | |
| 3145 | 3176 | return try self.constructStruct( |
| ... | ... | @@ -3351,7 +3382,7 @@ const DeclGen = struct { |
| 3351 | 3382 | for (wip.results, 0..) |*result_id, i| { |
| 3352 | 3383 | const elem = try mask.elemValue(mod, i); |
| 3353 | 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 | 3386 | continue; |
| 3356 | 3387 | } |
| 3357 | 3388 | |
| ... | ... | @@ -3366,11 +3397,10 @@ const DeclGen = struct { |
| 3366 | 3397 | } |
| 3367 | 3398 | |
| 3368 | 3399 | fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef { |
| 3369 | | const index_ty_ref = try self.intType(.unsigned, 32); |
| 3370 | 3400 | const ids = try self.gpa.alloc(IdRef, indices.len); |
| 3371 | 3401 | errdefer self.gpa.free(ids); |
| 3372 | 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 | } |
| 3375 | 3405 | |
| 3376 | 3406 | return ids; |
| ... | ... | @@ -3502,7 +3532,7 @@ const DeclGen = struct { |
| 3502 | 3532 | cmp_lhs_id = self.spv.allocId(); |
| 3503 | 3533 | cmp_rhs_id = self.spv.allocId(); |
| 3504 | 3534 | |
| 3505 | | const usize_ty_id = self.typeId(try self.sizeType()); |
| 3535 | const usize_ty_id = try self.resolveType2(Type.usize, .direct); |
| 3506 | 3536 | |
| 3507 | 3537 | try self.func.body.emit(self.spv.gpa, .OpConvertPtrToU, .{ |
| 3508 | 3538 | .id_result_type = usize_ty_id, |
| ... | ... | @@ -3761,7 +3791,7 @@ const DeclGen = struct { |
| 3761 | 3791 | // should we change the representation of strange integers? |
| 3762 | 3792 | if (dst_ty.zigTypeTag(mod) == .Int) { |
| 3763 | 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 | } |
| 3766 | 3796 | |
| 3767 | 3797 | return result_id; |
| ... | ... | @@ -3811,7 +3841,7 @@ const DeclGen = struct { |
| 3811 | 3841 | // type, we don't need to normalize when growing the type. The |
| 3812 | 3842 | // representation is already the same. |
| 3813 | 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 | 3845 | } else { |
| 3816 | 3846 | result_id.* = value_id; |
| 3817 | 3847 | } |
| ... | ... | @@ -3898,7 +3928,7 @@ const DeclGen = struct { |
| 3898 | 3928 | defer wip.deinit(); |
| 3899 | 3929 | for (wip.results, 0..) |*result_id, i| { |
| 3900 | 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 | 3933 | return try wip.finalize(); |
| 3904 | 3934 | } |
| ... | ... | @@ -3958,10 +3988,9 @@ const DeclGen = struct { |
| 3958 | 3988 | const elem_ptr_ty = slice_ty.slicePtrFieldType(mod); |
| 3959 | 3989 | |
| 3960 | 3990 | const elem_ptr_ty_ref = try self.resolveType(elem_ptr_ty, .direct); |
| 3961 | | const size_ty_ref = try self.sizeType(); |
| 3962 | 3991 | |
| 3963 | 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); |
| 3965 | 3994 | |
| 3966 | 3995 | const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 3967 | 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 | 4121 | const array_ty = ty.childType(mod); |
| 4093 | 4122 | const elem_ty = array_ty.childType(mod); |
| 4094 | 4123 | 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); |
| 4097 | 4126 | }, |
| 4098 | 4127 | .Many, .C => unreachable, |
| 4099 | 4128 | } |
| ... | ... | @@ -4298,6 +4327,8 @@ const DeclGen = struct { |
| 4298 | 4327 | // union type, then get the field pointer and pointer-cast it to the |
| 4299 | 4328 | // right type to store it. Finally load the entire union. |
| 4300 | 4329 | |
| 4330 | // Note: The result here is not cached, because it generates runtime code. |
| 4331 | |
| 4301 | 4332 | const mod = self.module; |
| 4302 | 4333 | const ip = &mod.intern_pool; |
| 4303 | 4334 | const union_ty = mod.typeToUnion(ty).?; |
| ... | ... | @@ -4316,17 +4347,15 @@ const DeclGen = struct { |
| 4316 | 4347 | } else 0; |
| 4317 | 4348 | |
| 4318 | 4349 | 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); |
| 4321 | 4351 | } |
| 4322 | 4352 | |
| 4323 | 4353 | const tmp_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| 4324 | 4354 | |
| 4325 | 4355 | if (layout.tag_size != 0) { |
| 4326 | | const tag_ty_ref = try self.resolveType(tag_ty, .direct); |
| 4327 | 4356 | const tag_ptr_ty_ref = try self.ptrType(tag_ty, .Function); |
| 4328 | 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 | 4359 | try self.store(tag_ty, ptr_id, tag_id, .{}); |
| 4331 | 4360 | } |
| 4332 | 4361 | |
| ... | ... | @@ -4420,8 +4449,6 @@ const DeclGen = struct { |
| 4420 | 4449 | |
| 4421 | 4450 | const parent_ty = ty_pl.ty.toType().childType(mod); |
| 4422 | 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); |
| 4425 | 4452 | |
| 4426 | 4453 | const field_ptr = try self.resolve(extra.field_ptr); |
| 4427 | 4454 | const field_ptr_int = try self.intFromPtr(field_ptr); |
| ... | ... | @@ -4430,8 +4457,8 @@ const DeclGen = struct { |
| 4430 | 4457 | const base_ptr_int = base_ptr_int: { |
| 4431 | 4458 | if (field_offset == 0) break :base_ptr_int field_ptr_int; |
| 4432 | 4459 | |
| 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); |
| 4435 | 4462 | }; |
| 4436 | 4463 | |
| 4437 | 4464 | const base_ptr = self.spv.allocId(); |
| ... | ... | @@ -4469,7 +4496,7 @@ const DeclGen = struct { |
| 4469 | 4496 | if (!layout.has_payload) { |
| 4470 | 4497 | // Asked to get a pointer to a zero-sized field. Just lower this |
| 4471 | 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 | } |
| 4474 | 4501 | |
| 4475 | 4502 | const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(mod)); |
| ... | ... | @@ -4563,7 +4590,7 @@ const DeclGen = struct { |
| 4563 | 4590 | assert(self.control_flow == .structured); |
| 4564 | 4591 | |
| 4565 | 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 | 4594 | try self.func.body.emitRaw(self.spv.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent... |
| 4568 | 4595 | self.func.body.writeOperand(spec.IdResultType, self.typeId(block_id_ty_ref)); |
| 4569 | 4596 | self.func.body.writeOperand(spec.IdRef, result_id); |
| ... | ... | @@ -4663,8 +4690,8 @@ const DeclGen = struct { |
| 4663 | 4690 | // Make sure that we are still in a block when exiting the function. |
| 4664 | 4691 | // TODO: Can we get rid of that? |
| 4665 | 4692 | 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)); |
| 4668 | 4695 | } |
| 4669 | 4696 | |
| 4670 | 4697 | // The top-most merge actually only has a single source, the |
| ... | ... | @@ -4781,8 +4808,7 @@ const DeclGen = struct { |
| 4781 | 4808 | assert(cf.block_stack.items.len > 0); |
| 4782 | 4809 | |
| 4783 | 4810 | // 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); |
| 4786 | 4812 | const jump_to_this_block_id = self.spv.allocId(); |
| 4787 | 4813 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| 4788 | 4814 | try self.func.body.emit(self.spv.gpa, .OpIEqual, .{ |
| ... | ... | @@ -4862,8 +4888,7 @@ const DeclGen = struct { |
| 4862 | 4888 | try self.store(operand_ty, block_result_var_id, operand_id, .{}); |
| 4863 | 4889 | } |
| 4864 | 4890 | |
| 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); |
| 4867 | 4892 | try self.structuredBreak(next_block); |
| 4868 | 4893 | }, |
| 4869 | 4894 | .unstructured => |cf| { |
| ... | ... | @@ -5026,8 +5051,7 @@ const DeclGen = struct { |
| 5026 | 5051 | // Functions with an empty error set are emitted with an error code |
| 5027 | 5052 | // return type and return zero so they can be function pointers coerced |
| 5028 | 5053 | // 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); |
| 5031 | 5055 | return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id }); |
| 5032 | 5056 | } else { |
| 5033 | 5057 | return try self.func.body.emit(self.spv.gpa, .OpReturn, {}); |
| ... | ... | @@ -5051,8 +5075,7 @@ const DeclGen = struct { |
| 5051 | 5075 | // Functions with an empty error set are emitted with an error code |
| 5052 | 5076 | // return type and return zero so they can be function pointers coerced |
| 5053 | 5077 | // 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); |
| 5056 | 5079 | return try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = no_err_id }); |
| 5057 | 5080 | } else { |
| 5058 | 5081 | return try self.func.body.emit(self.spv.gpa, .OpReturn, {}); |
| ... | ... | @@ -5076,7 +5099,6 @@ const DeclGen = struct { |
| 5076 | 5099 | const err_union_ty = self.typeOf(pl_op.operand); |
| 5077 | 5100 | const payload_ty = self.typeOfIndex(inst); |
| 5078 | 5101 | |
| 5079 | | const err_ty_ref = try self.resolveType(Type.anyerror, .direct); |
| 5080 | 5102 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| 5081 | 5103 | |
| 5082 | 5104 | const eu_layout = self.errorUnionLayout(payload_ty); |
| ... | ... | @@ -5087,7 +5109,7 @@ const DeclGen = struct { |
| 5087 | 5109 | else |
| 5088 | 5110 | err_union_id; |
| 5089 | 5111 | |
| 5090 | | const zero_id = try self.constInt(err_ty_ref, 0); |
| 5112 | const zero_id = try self.constInt(Type.anyerror, 0, .direct); |
| 5091 | 5113 | const is_err_id = self.spv.allocId(); |
| 5092 | 5114 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ |
| 5093 | 5115 | .id_result_type = self.typeId(bool_ty_ref), |
| ... | ... | @@ -5146,7 +5168,7 @@ const DeclGen = struct { |
| 5146 | 5168 | |
| 5147 | 5169 | if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 5148 | 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 | } |
| 5151 | 5173 | |
| 5152 | 5174 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| ... | ... | @@ -5189,7 +5211,7 @@ const DeclGen = struct { |
| 5189 | 5211 | |
| 5190 | 5212 | var members: [2]IdRef = undefined; |
| 5191 | 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)); |
| 5193 | 5215 | |
| 5194 | 5216 | var types: [2]Type = undefined; |
| 5195 | 5217 | types[eu_layout.errorFieldIndex()] = Type.anyerror; |
| ... | ... | @@ -5203,15 +5225,14 @@ const DeclGen = struct { |
| 5203 | 5225 | const err_union_ty = self.typeOfIndex(inst); |
| 5204 | 5226 | const operand_id = try self.resolve(ty_op.operand); |
| 5205 | 5227 | const payload_ty = self.typeOf(ty_op.operand); |
| 5206 | | const err_ty_ref = try self.resolveType(Type.anyerror, .direct); |
| 5207 | 5228 | const eu_layout = self.errorUnionLayout(payload_ty); |
| 5208 | 5229 | |
| 5209 | 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 | } |
| 5212 | 5233 | |
| 5213 | 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 | 5236 | members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id); |
| 5216 | 5237 | |
| 5217 | 5238 | var types: [2]Type = undefined; |
| ... | ... | @@ -5248,8 +5269,8 @@ const DeclGen = struct { |
| 5248 | 5269 | else |
| 5249 | 5270 | loaded_id; |
| 5250 | 5271 | |
| 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); |
| 5253 | 5274 | const op: std.math.CompareOperator = switch (pred) { |
| 5254 | 5275 | .is_null => .eq, |
| 5255 | 5276 | .is_non_null => .neq, |
| ... | ... | @@ -5306,7 +5327,6 @@ const DeclGen = struct { |
| 5306 | 5327 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 5307 | 5328 | const eu_layout = self.errorUnionLayout(payload_ty); |
| 5308 | 5329 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| 5309 | | const err_ty_ref = try self.resolveType(Type.anyerror, .direct); |
| 5310 | 5330 | |
| 5311 | 5331 | const error_id = if (!eu_layout.payload_has_bits) |
| 5312 | 5332 | operand_id |
| ... | ... | @@ -5318,7 +5338,7 @@ const DeclGen = struct { |
| 5318 | 5338 | .id_result_type = self.typeId(bool_ty_ref), |
| 5319 | 5339 | .id_result = result_id, |
| 5320 | 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 | 5343 | switch (pred) { |
| 5324 | 5344 | .is_err => try self.func.body.emit(self.spv.gpa, .OpINotEqual, operands), |