| ... | @@ -581,45 +581,30 @@ const DeclGen = struct { | ... | @@ -581,45 +581,30 @@ const DeclGen = struct { |
| 581 | } | 581 | } |
| 582 | | 582 | |
| 583 | /// Construct a struct at runtime. | 583 | /// Construct a struct at runtime. |
| 584 | /// result_ty_ref must be a struct type. | 584 | /// ty must be a struct type. |
| 585 | /// Constituents should be in `indirect` representation (as the elements of a struct should be). | 585 | /// Constituents should be in `indirect` representation (as the elements of a struct should be). |
| 586 | /// Result is in `direct` representation. | 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 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' | 589 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 589 | // operands are not constant. | 590 | // operands are not constant. |
| 590 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 | 591 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 591 | // For now, just initialize the struct by setting the fields manually... | 592 | // For now, just initialize the struct by setting the fields manually... |
| 592 | // TODO: Make this OpCompositeConstruct when we can | 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 = try self.alloc(ty, .{ .storage_class = .Function }); |
| 594 | const ptr_composite_id = self.spv.allocId(); | 595 | for (constituents, types, 0..) |constitent_id, member_ty, index| { |
| 595 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ | 596 | const ptr_member_ty_ref = try self.ptrType(member_ty, .Function); |
| 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); | | |
| 606 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); | 597 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 607 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 598 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 608 | .pointer = ptr_id, | 599 | .pointer = ptr_id, |
| 609 | .object = constitent_id, | 600 | .object = constitent_id, |
| 610 | }); | 601 | }); |
| 611 | } | 602 | } |
| 612 | const result_id = self.spv.allocId(); | 603 | return try self.load(ty, ptr_composite_id, .{}); |
| 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; | | |
| 619 | } | 604 | } |
| 620 | | 605 | |
| 621 | /// Construct an array at runtime. | 606 | /// Construct an array at runtime. |
| 622 | /// result_ty_ref must be an array type. | 607 | /// ty must be an array type. |
| 623 | /// Constituents should be in `indirect` representation (as the elements of an array should be). | 608 | /// Constituents should be in `indirect` representation (as the elements of an array should be). |
| 624 | /// Result is in `direct` representation. | 609 | /// Result is in `direct` representation. |
| 625 | fn constructArray(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { | 610 | fn constructArray(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| ... | @@ -750,15 +735,18 @@ const DeclGen = struct { | ... | @@ -750,15 +735,18 @@ const DeclGen = struct { |
| 750 | }.toValue(); | 735 | }.toValue(); |
| 751 | | 736 | |
| 752 | var constituents: [2]IdRef = undefined; | 737 | var constituents: [2]IdRef = undefined; |
| | 738 | var types: [2]Type = undefined; |
| 753 | if (eu_layout.error_first) { | 739 | if (eu_layout.error_first) { |
| 754 | constituents[0] = try self.constant(err_ty, err_val, .indirect); | 740 | constituents[0] = try self.constant(err_ty, err_val, .indirect); |
| 755 | constituents[1] = try self.constant(payload_ty, payload_val, .indirect); | 741 | constituents[1] = try self.constant(payload_ty, payload_val, .indirect); |
| | 742 | types = .{ err_ty, payload_ty }; |
| 756 | } else { | 743 | } else { |
| 757 | constituents[0] = try self.constant(payload_ty, payload_val, .indirect); | 744 | constituents[0] = try self.constant(payload_ty, payload_val, .indirect); |
| 758 | constituents[1] = try self.constant(err_ty, err_val, .indirect); | 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 | .enum_tag => { | 751 | .enum_tag => { |
| 764 | const int_val = try val.intFromEnum(ty, mod); | 752 | const int_val = try val.intFromEnum(ty, mod); |
| ... | @@ -776,7 +764,11 @@ const DeclGen = struct { | ... | @@ -776,7 +764,11 @@ const DeclGen = struct { |
| 776 | } | 764 | } |
| 777 | | 765 | |
| 778 | const len_id = try self.constant(Type.usize, ptr.len.toValue(), .indirect); | 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 | .opt => { | 773 | .opt => { |
| 782 | const payload_ty = ty.optionalChild(mod); | 774 | const payload_ty = ty.optionalChild(mod); |
| ... | @@ -803,7 +795,11 @@ const DeclGen = struct { | ... | @@ -803,7 +795,11 @@ const DeclGen = struct { |
| 803 | else | 795 | else |
| 804 | try self.spv.constUndef(try self.resolveType(payload_ty, .indirect)); | 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 | .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { | 804 | .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { |
| 809 | inline .array_type, .vector_type => |array_type, tag| { | 805 | inline .array_type, .vector_type => |array_type, tag| { |
| ... | @@ -849,6 +845,9 @@ const DeclGen = struct { | ... | @@ -849,6 +845,9 @@ const DeclGen = struct { |
| 849 | return self.todo("packed struct constants", .{}); | 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 | var constituents = std.ArrayList(IdRef).init(self.gpa); | 851 | var constituents = std.ArrayList(IdRef).init(self.gpa); |
| 853 | defer constituents.deinit(); | 852 | defer constituents.deinit(); |
| 854 | | 853 | |
| ... | @@ -864,10 +863,11 @@ const DeclGen = struct { | ... | @@ -864,10 +863,11 @@ const DeclGen = struct { |
| 864 | const field_val = try val.fieldValue(mod, field_index); | 863 | const field_val = try val.fieldValue(mod, field_index); |
| 865 | const field_id = try self.constant(field_ty, field_val, .indirect); | 864 | const field_id = try self.constant(field_ty, field_val, .indirect); |
| 866 | | 865 | |
| | 866 | try types.append(field_ty); |
| 867 | try constituents.append(field_id); | 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 | .anon_struct_type => unreachable, // TODO | 872 | .anon_struct_type => unreachable, // TODO |
| 873 | else => unreachable, | 873 | else => unreachable, |
| ... | @@ -2449,11 +2449,11 @@ const DeclGen = struct { | ... | @@ -2449,11 +2449,11 @@ const DeclGen = struct { |
| 2449 | // Construct the struct that Zig wants as result. | 2449 | // Construct the struct that Zig wants as result. |
| 2450 | // The value should already be the correct type. | 2450 | // The value should already be the correct type. |
| 2451 | const ov_id = try self.intFromBool(ov_ty_ref, overflowed_id); | 2451 | const ov_id = try self.intFromBool(ov_ty_ref, overflowed_id); |
| 2452 | const result_ty_ref = try self.resolveType(result_ty, .direct); | 2452 | return try self.constructStruct( |
| 2453 | return try self.constructStruct(result_ty_ref, &.{ | 2453 | result_ty, |
| 2454 | value_id, | 2454 | &.{ operand_ty, ov_ty }, |
| 2455 | ov_id, | 2455 | &.{ value_id, ov_id }, |
| 2456 | }); | 2456 | ); |
| 2457 | } | 2457 | } |
| 2458 | | 2458 | |
| 2459 | fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2459 | fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3032,7 +3032,6 @@ const DeclGen = struct { | ... | @@ -3032,7 +3032,6 @@ const DeclGen = struct { |
| 3032 | const elem_ptr_ty = slice_ty.slicePtrFieldType(mod); | 3032 | const elem_ptr_ty = slice_ty.slicePtrFieldType(mod); |
| 3033 | | 3033 | |
| 3034 | const elem_ptr_ty_ref = try self.resolveType(elem_ptr_ty, .direct); | 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 | const size_ty_ref = try self.sizeType(); | 3035 | const size_ty_ref = try self.sizeType(); |
| 3037 | | 3036 | |
| 3038 | const array_ptr_id = try self.resolve(ty_op.operand); | 3037 | const array_ptr_id = try self.resolve(ty_op.operand); |
| ... | @@ -3045,7 +3044,11 @@ const DeclGen = struct { | ... | @@ -3045,7 +3044,11 @@ const DeclGen = struct { |
| 3045 | // Convert the pointer-to-array to a pointer to the first element. | 3044 | // Convert the pointer-to-array to a pointer to the first element. |
| 3046 | try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0}); | 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 | fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3054 | fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3055,13 +3058,16 @@ const DeclGen = struct { | ... | @@ -3055,13 +3058,16 @@ const DeclGen = struct { |
| 3055 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 3058 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3056 | const ptr_id = try self.resolve(bin_op.lhs); | 3059 | const ptr_id = try self.resolve(bin_op.lhs); |
| 3057 | const len_id = try self.resolve(bin_op.rhs); | 3060 | const len_id = try self.resolve(bin_op.rhs); |
| | 3061 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 3058 | const slice_ty = self.typeOfIndex(inst); | 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, &.{ | 3064 | // Note: Types should not need to be converted to direct, these types |
| 3062 | ptr_id, // Note: Type should not need to be converted to direct. | 3065 | // dont need to be converted. |
| 3063 | len_id, // Note: Type should not need to be converted to direct. | 3066 | return try self.constructStruct( |
| 3064 | }); | 3067 | slice_ty, |
| | 3068 | &.{ ptr_ty, Type.usize }, |
| | 3069 | &.{ ptr_id, len_id }, |
| | 3070 | ); |
| 3065 | } | 3071 | } |
| 3066 | | 3072 | |
| 3067 | fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3073 | fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3071,7 +3077,6 @@ const DeclGen = struct { | ... | @@ -3071,7 +3077,6 @@ const DeclGen = struct { |
| 3071 | const ip = &mod.intern_pool; | 3077 | const ip = &mod.intern_pool; |
| 3072 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 3078 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3073 | const result_ty = self.typeOfIndex(inst); | 3079 | const result_ty = self.typeOfIndex(inst); |
| 3074 | const result_ty_ref = try self.resolveType(result_ty, .direct); | | |
| 3075 | const len: usize = @intCast(result_ty.arrayLen(mod)); | 3080 | const len: usize = @intCast(result_ty.arrayLen(mod)); |
| 3076 | const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]); | 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,6 +3088,8 @@ const DeclGen = struct { |
| 3083 | unreachable; // TODO | 3088 | unreachable; // TODO |
| 3084 | } | 3089 | } |
| 3085 | | 3090 | |
| | 3091 | const types = try self.gpa.alloc(Type, elements.len); |
| | 3092 | defer self.gpa.free(types); |
| 3086 | const constituents = try self.gpa.alloc(IdRef, elements.len); | 3093 | const constituents = try self.gpa.alloc(IdRef, elements.len); |
| 3087 | defer self.gpa.free(constituents); | 3094 | defer self.gpa.free(constituents); |
| 3088 | var index: usize = 0; | 3095 | var index: usize = 0; |
| ... | @@ -3094,6 +3101,7 @@ const DeclGen = struct { | ... | @@ -3094,6 +3101,7 @@ const DeclGen = struct { |
| 3094 | assert(field_ty.toType().hasRuntimeBits(mod)); | 3101 | assert(field_ty.toType().hasRuntimeBits(mod)); |
| 3095 | | 3102 | |
| 3096 | const id = try self.resolve(element); | 3103 | const id = try self.resolve(element); |
| | 3104 | types[index] = field_ty.toType(); |
| 3097 | constituents[index] = try self.convertToIndirect(field_ty.toType(), id); | 3105 | constituents[index] = try self.convertToIndirect(field_ty.toType(), id); |
| 3098 | index += 1; | 3106 | index += 1; |
| 3099 | } | 3107 | } |
| ... | @@ -3107,6 +3115,7 @@ const DeclGen = struct { | ... | @@ -3107,6 +3115,7 @@ const DeclGen = struct { |
| 3107 | assert(field_ty.hasRuntimeBitsIgnoreComptime(mod)); | 3115 | assert(field_ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 3108 | | 3116 | |
| 3109 | const id = try self.resolve(element); | 3117 | const id = try self.resolve(element); |
| | 3118 | types[index] = field_ty; |
| 3110 | constituents[index] = try self.convertToIndirect(field_ty, id); | 3119 | constituents[index] = try self.convertToIndirect(field_ty, id); |
| 3111 | index += 1; | 3120 | index += 1; |
| 3112 | } | 3121 | } |
| ... | @@ -3114,7 +3123,11 @@ const DeclGen = struct { | ... | @@ -3114,7 +3123,11 @@ const DeclGen = struct { |
| 3114 | else => unreachable, | 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 | .Array => { | 3132 | .Array => { |
| 3120 | const array_info = result_ty.arrayInfo(mod); | 3133 | const array_info = result_ty.arrayInfo(mod); |
| ... | @@ -3912,8 +3925,11 @@ const DeclGen = struct { | ... | @@ -3912,8 +3925,11 @@ const DeclGen = struct { |
| 3912 | members[eu_layout.errorFieldIndex()] = operand_id; | 3925 | members[eu_layout.errorFieldIndex()] = operand_id; |
| 3913 | members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref); | 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); | 3928 | var types: [2]Type = undefined; |
| 3916 | return try self.constructStruct(err_union_ty_ref, &members); | 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 | fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3935 | fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3934,8 +3950,11 @@ const DeclGen = struct { | ... | @@ -3934,8 +3950,11 @@ const DeclGen = struct { |
| 3934 | members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0); | 3950 | members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0); |
| 3935 | members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id); | 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); | 3953 | var types: [2]Type = undefined; |
| 3938 | return try self.constructStruct(err_union_ty_ref, &members); | 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 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { | 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,10 +4086,10 @@ const DeclGen = struct { |
| 4067 | return operand_id; | 4086 | return operand_id; |
| 4068 | } | 4087 | } |
| 4069 | | 4088 | |
| 4070 | const optional_ty_ref = try self.resolveType(optional_ty, .direct); | | |
| 4071 | const payload_id = try self.convertToIndirect(payload_ty, operand_id); | 4089 | const payload_id = try self.convertToIndirect(payload_ty, operand_id); |
| 4072 | const members = [_]IdRef{ payload_id, try self.constBool(true, .indirect) }; | 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 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { | 4095 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { |