| ... | ... | @@ -581,45 +581,30 @@ const DeclGen = struct { |
| 581 | 581 | } |
| 582 | 582 | |
| 583 | 583 | /// Construct a struct at runtime. |
| 584 | | /// result_ty_ref must be a struct type. |
| 584 | /// ty must be a struct type. |
| 585 | 585 | /// Constituents should be in `indirect` representation (as the elements of a struct should be). |
| 586 | 586 | /// Result is in `direct` representation. |
| 587 | | fn constructStruct(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef { |
| 587 | fn constructStruct(self: *DeclGen, ty: Type, types: []const Type, constituents: []const IdRef) !IdRef { |
| 588 | assert(types.len == constituents.len); |
| 588 | 589 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 589 | 590 | // operands are not constant. |
| 590 | 591 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 591 | 592 | // For now, just initialize the struct by setting the fields manually... |
| 592 | 593 | // TODO: Make this OpCompositeConstruct when we can |
| 593 | | const ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); |
| 594 | | const ptr_composite_id = self.spv.allocId(); |
| 595 | | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| 596 | | .id_result_type = self.typeId(ptr_ty_ref), |
| 597 | | .id_result = ptr_composite_id, |
| 598 | | .storage_class = .Function, |
| 599 | | }); |
| 600 | | |
| 601 | | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).struct_type; |
| 602 | | const member_types = spv_composite_ty.member_types; |
| 603 | | |
| 604 | | for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| { |
| 605 | | const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Function); |
| 594 | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| 595 | for (constituents, types, 0..) |constitent_id, member_ty, index| { |
| 596 | const ptr_member_ty_ref = try self.ptrType(member_ty, .Function); |
| 606 | 597 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 607 | 598 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 608 | 599 | .pointer = ptr_id, |
| 609 | 600 | .object = constitent_id, |
| 610 | 601 | }); |
| 611 | 602 | } |
| 612 | | const result_id = self.spv.allocId(); |
| 613 | | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 614 | | .id_result_type = self.typeId(result_ty_ref), |
| 615 | | .id_result = result_id, |
| 616 | | .pointer = ptr_composite_id, |
| 617 | | }); |
| 618 | | return result_id; |
| 603 | return try self.load(ty, ptr_composite_id, .{}); |
| 619 | 604 | } |
| 620 | 605 | |
| 621 | 606 | /// Construct an array at runtime. |
| 622 | | /// result_ty_ref must be an array type. |
| 607 | /// ty must be an array type. |
| 623 | 608 | /// Constituents should be in `indirect` representation (as the elements of an array should be). |
| 624 | 609 | /// Result is in `direct` representation. |
| 625 | 610 | fn constructArray(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| ... | ... | @@ -750,15 +735,18 @@ const DeclGen = struct { |
| 750 | 735 | }.toValue(); |
| 751 | 736 | |
| 752 | 737 | var constituents: [2]IdRef = undefined; |
| 738 | var types: [2]Type = undefined; |
| 753 | 739 | if (eu_layout.error_first) { |
| 754 | 740 | constituents[0] = try self.constant(err_ty, err_val, .indirect); |
| 755 | 741 | constituents[1] = try self.constant(payload_ty, payload_val, .indirect); |
| 742 | types = .{ err_ty, payload_ty }; |
| 756 | 743 | } else { |
| 757 | 744 | constituents[0] = try self.constant(payload_ty, payload_val, .indirect); |
| 758 | 745 | constituents[1] = try self.constant(err_ty, err_val, .indirect); |
| 746 | types = .{ payload_ty, err_ty }; |
| 759 | 747 | } |
| 760 | 748 | |
| 761 | | return try self.constructStruct(result_ty_ref, &constituents); |
| 749 | return try self.constructStruct(ty, &types, &constituents); |
| 762 | 750 | }, |
| 763 | 751 | .enum_tag => { |
| 764 | 752 | const int_val = try val.intFromEnum(ty, mod); |
| ... | ... | @@ -776,7 +764,11 @@ const DeclGen = struct { |
| 776 | 764 | } |
| 777 | 765 | |
| 778 | 766 | const len_id = try self.constant(Type.usize, ptr.len.toValue(), .indirect); |
| 779 | | return try self.constructStruct(result_ty_ref, &.{ ptr_id, len_id }); |
| 767 | return try self.constructStruct( |
| 768 | ty, |
| 769 | &.{ ptr_ty, Type.usize }, |
| 770 | &.{ ptr_id, len_id }, |
| 771 | ); |
| 780 | 772 | }, |
| 781 | 773 | .opt => { |
| 782 | 774 | const payload_ty = ty.optionalChild(mod); |
| ... | ... | @@ -803,7 +795,11 @@ const DeclGen = struct { |
| 803 | 795 | else |
| 804 | 796 | try self.spv.constUndef(try self.resolveType(payload_ty, .indirect)); |
| 805 | 797 | |
| 806 | | return try self.constructStruct(result_ty_ref, &.{ payload_id, has_pl_id }); |
| 798 | return try self.constructStruct( |
| 799 | ty, |
| 800 | &.{ payload_ty, Type.bool }, |
| 801 | &.{ payload_id, has_pl_id }, |
| 802 | ); |
| 807 | 803 | }, |
| 808 | 804 | .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { |
| 809 | 805 | inline .array_type, .vector_type => |array_type, tag| { |
| ... | ... | @@ -849,6 +845,9 @@ const DeclGen = struct { |
| 849 | 845 | return self.todo("packed struct constants", .{}); |
| 850 | 846 | } |
| 851 | 847 | |
| 848 | var types = std.ArrayList(Type).init(self.gpa); |
| 849 | defer types.deinit(); |
| 850 | |
| 852 | 851 | var constituents = std.ArrayList(IdRef).init(self.gpa); |
| 853 | 852 | defer constituents.deinit(); |
| 854 | 853 | |
| ... | ... | @@ -864,10 +863,11 @@ const DeclGen = struct { |
| 864 | 863 | const field_val = try val.fieldValue(mod, field_index); |
| 865 | 864 | const field_id = try self.constant(field_ty, field_val, .indirect); |
| 866 | 865 | |
| 866 | try types.append(field_ty); |
| 867 | 867 | try constituents.append(field_id); |
| 868 | 868 | } |
| 869 | 869 | |
| 870 | | return try self.constructStruct(result_ty_ref, constituents.items); |
| 870 | return try self.constructStruct(ty, types.items, constituents.items); |
| 871 | 871 | }, |
| 872 | 872 | .anon_struct_type => unreachable, // TODO |
| 873 | 873 | else => unreachable, |
| ... | ... | @@ -2449,11 +2449,11 @@ const DeclGen = struct { |
| 2449 | 2449 | // Construct the struct that Zig wants as result. |
| 2450 | 2450 | // The value should already be the correct type. |
| 2451 | 2451 | const ov_id = try self.intFromBool(ov_ty_ref, overflowed_id); |
| 2452 | | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 2453 | | return try self.constructStruct(result_ty_ref, &.{ |
| 2454 | | value_id, |
| 2455 | | ov_id, |
| 2456 | | }); |
| 2452 | return try self.constructStruct( |
| 2453 | result_ty, |
| 2454 | &.{ operand_ty, ov_ty }, |
| 2455 | &.{ value_id, ov_id }, |
| 2456 | ); |
| 2457 | 2457 | } |
| 2458 | 2458 | |
| 2459 | 2459 | fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | ... | @@ -3032,7 +3032,6 @@ const DeclGen = struct { |
| 3032 | 3032 | const elem_ptr_ty = slice_ty.slicePtrFieldType(mod); |
| 3033 | 3033 | |
| 3034 | 3034 | const elem_ptr_ty_ref = try self.resolveType(elem_ptr_ty, .direct); |
| 3035 | | const slice_ty_ref = try self.resolveType(slice_ty, .direct); |
| 3036 | 3035 | const size_ty_ref = try self.sizeType(); |
| 3037 | 3036 | |
| 3038 | 3037 | const array_ptr_id = try self.resolve(ty_op.operand); |
| ... | ... | @@ -3045,7 +3044,11 @@ const DeclGen = struct { |
| 3045 | 3044 | // Convert the pointer-to-array to a pointer to the first element. |
| 3046 | 3045 | try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0}); |
| 3047 | 3046 | |
| 3048 | | return try self.constructStruct(slice_ty_ref, &.{ elem_ptr_id, len_id }); |
| 3047 | return try self.constructStruct( |
| 3048 | slice_ty, |
| 3049 | &.{ elem_ptr_ty, Type.usize }, |
| 3050 | &.{ elem_ptr_id, len_id }, |
| 3051 | ); |
| 3049 | 3052 | } |
| 3050 | 3053 | |
| 3051 | 3054 | fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | ... | @@ -3055,13 +3058,16 @@ const DeclGen = struct { |
| 3055 | 3058 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3056 | 3059 | const ptr_id = try self.resolve(bin_op.lhs); |
| 3057 | 3060 | const len_id = try self.resolve(bin_op.rhs); |
| 3061 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 3058 | 3062 | const slice_ty = self.typeOfIndex(inst); |
| 3059 | | const slice_ty_ref = try self.resolveType(slice_ty, .direct); |
| 3060 | 3063 | |
| 3061 | | return try self.constructStruct(slice_ty_ref, &.{ |
| 3062 | | ptr_id, // Note: Type should not need to be converted to direct. |
| 3063 | | len_id, // Note: Type should not need to be converted to direct. |
| 3064 | | }); |
| 3064 | // Note: Types should not need to be converted to direct, these types |
| 3065 | // dont need to be converted. |
| 3066 | return try self.constructStruct( |
| 3067 | slice_ty, |
| 3068 | &.{ ptr_ty, Type.usize }, |
| 3069 | &.{ ptr_id, len_id }, |
| 3070 | ); |
| 3065 | 3071 | } |
| 3066 | 3072 | |
| 3067 | 3073 | fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | ... | @@ -3071,7 +3077,6 @@ const DeclGen = struct { |
| 3071 | 3077 | const ip = &mod.intern_pool; |
| 3072 | 3078 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3073 | 3079 | const result_ty = self.typeOfIndex(inst); |
| 3074 | | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 3075 | 3080 | const len: usize = @intCast(result_ty.arrayLen(mod)); |
| 3076 | 3081 | const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]); |
| 3077 | 3082 | |
| ... | ... | @@ -3083,6 +3088,8 @@ const DeclGen = struct { |
| 3083 | 3088 | unreachable; // TODO |
| 3084 | 3089 | } |
| 3085 | 3090 | |
| 3091 | const types = try self.gpa.alloc(Type, elements.len); |
| 3092 | defer self.gpa.free(types); |
| 3086 | 3093 | const constituents = try self.gpa.alloc(IdRef, elements.len); |
| 3087 | 3094 | defer self.gpa.free(constituents); |
| 3088 | 3095 | var index: usize = 0; |
| ... | ... | @@ -3094,6 +3101,7 @@ const DeclGen = struct { |
| 3094 | 3101 | assert(field_ty.toType().hasRuntimeBits(mod)); |
| 3095 | 3102 | |
| 3096 | 3103 | const id = try self.resolve(element); |
| 3104 | types[index] = field_ty.toType(); |
| 3097 | 3105 | constituents[index] = try self.convertToIndirect(field_ty.toType(), id); |
| 3098 | 3106 | index += 1; |
| 3099 | 3107 | } |
| ... | ... | @@ -3107,6 +3115,7 @@ const DeclGen = struct { |
| 3107 | 3115 | assert(field_ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 3108 | 3116 | |
| 3109 | 3117 | const id = try self.resolve(element); |
| 3118 | types[index] = field_ty; |
| 3110 | 3119 | constituents[index] = try self.convertToIndirect(field_ty, id); |
| 3111 | 3120 | index += 1; |
| 3112 | 3121 | } |
| ... | ... | @@ -3114,7 +3123,11 @@ const DeclGen = struct { |
| 3114 | 3123 | else => unreachable, |
| 3115 | 3124 | } |
| 3116 | 3125 | |
| 3117 | | return try self.constructStruct(result_ty_ref, constituents[0..index]); |
| 3126 | return try self.constructStruct( |
| 3127 | result_ty, |
| 3128 | types[0..index], |
| 3129 | constituents[0..index], |
| 3130 | ); |
| 3118 | 3131 | }, |
| 3119 | 3132 | .Array => { |
| 3120 | 3133 | const array_info = result_ty.arrayInfo(mod); |
| ... | ... | @@ -3912,8 +3925,11 @@ const DeclGen = struct { |
| 3912 | 3925 | members[eu_layout.errorFieldIndex()] = operand_id; |
| 3913 | 3926 | members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref); |
| 3914 | 3927 | |
| 3915 | | const err_union_ty_ref = try self.resolveType(err_union_ty, .direct); |
| 3916 | | return try self.constructStruct(err_union_ty_ref, &members); |
| 3928 | var types: [2]Type = undefined; |
| 3929 | types[eu_layout.errorFieldIndex()] = Type.anyerror; |
| 3930 | types[eu_layout.payloadFieldIndex()] = payload_ty; |
| 3931 | |
| 3932 | return try self.constructStruct(err_union_ty, &types, &members); |
| 3917 | 3933 | } |
| 3918 | 3934 | |
| 3919 | 3935 | fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | ... | @@ -3934,8 +3950,11 @@ const DeclGen = struct { |
| 3934 | 3950 | members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0); |
| 3935 | 3951 | members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id); |
| 3936 | 3952 | |
| 3937 | | const err_union_ty_ref = try self.resolveType(err_union_ty, .direct); |
| 3938 | | return try self.constructStruct(err_union_ty_ref, &members); |
| 3953 | var types: [2]Type = undefined; |
| 3954 | types[eu_layout.errorFieldIndex()] = Type.anyerror; |
| 3955 | types[eu_layout.payloadFieldIndex()] = payload_ty; |
| 3956 | |
| 3957 | return try self.constructStruct(err_union_ty, &types, &members); |
| 3939 | 3958 | } |
| 3940 | 3959 | |
| 3941 | 3960 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { |
| ... | ... | @@ -4067,10 +4086,10 @@ const DeclGen = struct { |
| 4067 | 4086 | return operand_id; |
| 4068 | 4087 | } |
| 4069 | 4088 | |
| 4070 | | const optional_ty_ref = try self.resolveType(optional_ty, .direct); |
| 4071 | 4089 | const payload_id = try self.convertToIndirect(payload_ty, operand_id); |
| 4072 | 4090 | const members = [_]IdRef{ payload_id, try self.constBool(true, .indirect) }; |
| 4073 | | return try self.constructStruct(optional_ty_ref, &members); |
| 4091 | const types = [_]Type{ payload_ty, Type.bool }; |
| 4092 | return try self.constructStruct(optional_ty, &types, &members); |
| 4074 | 4093 | } |
| 4075 | 4094 | |
| 4076 | 4095 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { |