| ... | ... | @@ -768,18 +768,75 @@ const DeclGen = struct { |
| 768 | 768 | }; |
| 769 | 769 | } |
| 770 | 770 | |
| 771 | | /// Construct a composite value at runtime. If the parameters are in direct |
| 772 | | /// representation, then the result is also in direct representation. Otherwise, |
| 773 | | /// if the parameters are in indirect representation, then the result is too. |
| 774 | | fn constructComposite(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| 775 | | const constituents_id = self.spv.allocId(); |
| 776 | | const type_id = try self.resolveType(ty, .direct); |
| 777 | | try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ |
| 778 | | .id_result_type = self.typeId(type_id), |
| 779 | | .id_result = constituents_id, |
| 780 | | .constituents = constituents, |
| 781 | | }); |
| 782 | | return constituents_id; |
| 771 | /// Construct a struct at runtime. |
| 772 | /// ty must be a struct type. |
| 773 | /// Constituents should be in `indirect` representation (as the elements of a struct should be). |
| 774 | /// Result is in `direct` representation. |
| 775 | fn constructStruct(self: *DeclGen, ty: Type, types: []const Type, constituents: []const IdRef) !IdRef { |
| 776 | assert(types.len == constituents.len); |
| 777 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 778 | // operands are not constant. |
| 779 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 780 | // For now, just initialize the struct by setting the fields manually... |
| 781 | // TODO: Make this OpCompositeConstruct when we can |
| 782 | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| 783 | for (constituents, types, 0..) |constitent_id, member_ty, index| { |
| 784 | const ptr_member_ty_ref = try self.ptrType(member_ty, .Function); |
| 785 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 786 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 787 | .pointer = ptr_id, |
| 788 | .object = constitent_id, |
| 789 | }); |
| 790 | } |
| 791 | return try self.load(ty, ptr_composite_id, .{}); |
| 792 | } |
| 793 | |
| 794 | /// Construct a vector at runtime. |
| 795 | /// ty must be an vector type. |
| 796 | /// Constituents should be in `indirect` representation (as the elements of an vector should be). |
| 797 | /// Result is in `direct` representation. |
| 798 | fn constructVector(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| 799 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 800 | // operands are not constant. |
| 801 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 802 | // For now, just initialize the struct by setting the fields manually... |
| 803 | // TODO: Make this OpCompositeConstruct when we can |
| 804 | const mod = self.module; |
| 805 | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| 806 | const ptr_elem_ty_ref = try self.ptrType(ty.elemType2(mod), .Function); |
| 807 | for (constituents, 0..) |constitent_id, index| { |
| 808 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 809 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 810 | .pointer = ptr_id, |
| 811 | .object = constitent_id, |
| 812 | }); |
| 813 | } |
| 814 | |
| 815 | return try self.load(ty, ptr_composite_id, .{}); |
| 816 | } |
| 817 | |
| 818 | /// Construct an array at runtime. |
| 819 | /// ty must be an array type. |
| 820 | /// Constituents should be in `indirect` representation (as the elements of an array should be). |
| 821 | /// Result is in `direct` representation. |
| 822 | fn constructArray(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| 823 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 824 | // operands are not constant. |
| 825 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 826 | // For now, just initialize the struct by setting the fields manually... |
| 827 | // TODO: Make this OpCompositeConstruct when we can |
| 828 | const mod = self.module; |
| 829 | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| 830 | const ptr_elem_ty_ref = try self.ptrType(ty.elemType2(mod), .Function); |
| 831 | for (constituents, 0..) |constitent_id, index| { |
| 832 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 833 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 834 | .pointer = ptr_id, |
| 835 | .object = constitent_id, |
| 836 | }); |
| 837 | } |
| 838 | |
| 839 | return try self.load(ty, ptr_composite_id, .{}); |
| 783 | 840 | } |
| 784 | 841 | |
| 785 | 842 | /// This function generates a load for a constant in direct (ie, non-memory) representation. |
| ... | ... | @@ -887,15 +944,18 @@ const DeclGen = struct { |
| 887 | 944 | }); |
| 888 | 945 | |
| 889 | 946 | var constituents: [2]IdRef = undefined; |
| 947 | var types: [2]Type = undefined; |
| 890 | 948 | if (eu_layout.error_first) { |
| 891 | 949 | constituents[0] = try self.constant(err_ty, err_val, .indirect); |
| 892 | 950 | constituents[1] = try self.constant(payload_ty, payload_val, .indirect); |
| 951 | types = .{ err_ty, payload_ty }; |
| 893 | 952 | } else { |
| 894 | 953 | constituents[0] = try self.constant(payload_ty, payload_val, .indirect); |
| 895 | 954 | constituents[1] = try self.constant(err_ty, err_val, .indirect); |
| 955 | types = .{ payload_ty, err_ty }; |
| 896 | 956 | } |
| 897 | 957 | |
| 898 | | return try self.constructComposite(ty, &constituents); |
| 958 | return try self.constructStruct(ty, &types, &constituents); |
| 899 | 959 | }, |
| 900 | 960 | .enum_tag => { |
| 901 | 961 | const int_val = try val.intFromEnum(ty, mod); |
| ... | ... | @@ -907,7 +967,11 @@ const DeclGen = struct { |
| 907 | 967 | const ptr_ty = ty.slicePtrFieldType(mod); |
| 908 | 968 | const ptr_id = try self.constantPtr(ptr_ty, Value.fromInterned(slice.ptr)); |
| 909 | 969 | const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect); |
| 910 | | return self.constructComposite(ty, &.{ ptr_id, len_id }); |
| 970 | return self.constructStruct( |
| 971 | ty, |
| 972 | &.{ ptr_ty, Type.usize }, |
| 973 | &.{ ptr_id, len_id }, |
| 974 | ); |
| 911 | 975 | }, |
| 912 | 976 | .opt => { |
| 913 | 977 | const payload_ty = ty.optionalChild(mod); |
| ... | ... | @@ -934,7 +998,11 @@ const DeclGen = struct { |
| 934 | 998 | else |
| 935 | 999 | try self.spv.constUndef(try self.resolveType(payload_ty, .indirect)); |
| 936 | 1000 | |
| 937 | | return try self.constructComposite(ty, &.{ payload_id, has_pl_id }); |
| 1001 | return try self.constructStruct( |
| 1002 | ty, |
| 1003 | &.{ payload_ty, Type.bool }, |
| 1004 | &.{ payload_id, has_pl_id }, |
| 1005 | ); |
| 938 | 1006 | }, |
| 939 | 1007 | .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { |
| 940 | 1008 | inline .array_type, .vector_type => |array_type, tag| { |
| ... | ... | @@ -971,9 +1039,9 @@ const DeclGen = struct { |
| 971 | 1039 | const sentinel = Value.fromInterned(array_type.sentinel); |
| 972 | 1040 | constituents[constituents.len - 1] = try self.constant(elem_ty, sentinel, .indirect); |
| 973 | 1041 | } |
| 974 | | return self.constructComposite(ty, constituents); |
| 1042 | return self.constructArray(ty, constituents); |
| 975 | 1043 | }, |
| 976 | | inline .vector_type => return self.constructComposite(ty, constituents), |
| 1044 | inline .vector_type => return self.constructVector(ty, constituents), |
| 977 | 1045 | else => unreachable, |
| 978 | 1046 | } |
| 979 | 1047 | }, |
| ... | ... | @@ -983,6 +1051,9 @@ const DeclGen = struct { |
| 983 | 1051 | return self.todo("packed struct constants", .{}); |
| 984 | 1052 | } |
| 985 | 1053 | |
| 1054 | var types = std.ArrayList(Type).init(self.gpa); |
| 1055 | defer types.deinit(); |
| 1056 | |
| 986 | 1057 | var constituents = std.ArrayList(IdRef).init(self.gpa); |
| 987 | 1058 | defer constituents.deinit(); |
| 988 | 1059 | |
| ... | ... | @@ -998,10 +1069,11 @@ const DeclGen = struct { |
| 998 | 1069 | const field_val = try val.fieldValue(mod, field_index); |
| 999 | 1070 | const field_id = try self.constant(field_ty, field_val, .indirect); |
| 1000 | 1071 | |
| 1072 | try types.append(field_ty); |
| 1001 | 1073 | try constituents.append(field_id); |
| 1002 | 1074 | } |
| 1003 | 1075 | |
| 1004 | | return try self.constructComposite(ty, constituents.items); |
| 1076 | return try self.constructStruct(ty, types.items, constituents.items); |
| 1005 | 1077 | }, |
| 1006 | 1078 | .anon_struct_type => unreachable, // TODO |
| 1007 | 1079 | else => unreachable, |
| ... | ... | @@ -1841,7 +1913,7 @@ const DeclGen = struct { |
| 1841 | 1913 | for (wip.results) |*result| { |
| 1842 | 1914 | result.* = try wip.dg.convertToIndirect(wip.ty, result.*); |
| 1843 | 1915 | } |
| 1844 | | return try wip.dg.constructComposite(wip.result_ty, wip.results); |
| 1916 | return try wip.dg.constructArray(wip.result_ty, wip.results); |
| 1845 | 1917 | } else { |
| 1846 | 1918 | return wip.results[0]; |
| 1847 | 1919 | } |
| ... | ... | @@ -2792,8 +2864,9 @@ const DeclGen = struct { |
| 2792 | 2864 | ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id); |
| 2793 | 2865 | } |
| 2794 | 2866 | |
| 2795 | | return try self.constructComposite( |
| 2867 | return try self.constructStruct( |
| 2796 | 2868 | result_ty, |
| 2869 | &.{ operand_ty, ov_ty }, |
| 2797 | 2870 | &.{ try wip_result.finalize(), try wip_ov.finalize() }, |
| 2798 | 2871 | ); |
| 2799 | 2872 | } |
| ... | ... | @@ -2885,8 +2958,9 @@ const DeclGen = struct { |
| 2885 | 2958 | ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id); |
| 2886 | 2959 | } |
| 2887 | 2960 | |
| 2888 | | return try self.constructComposite( |
| 2961 | return try self.constructStruct( |
| 2889 | 2962 | result_ty, |
| 2963 | &.{ operand_ty, ov_ty }, |
| 2890 | 2964 | &.{ try wip_result.finalize(), try wip_ov.finalize() }, |
| 2891 | 2965 | ); |
| 2892 | 2966 | } |
| ... | ... | @@ -3588,7 +3662,11 @@ const DeclGen = struct { |
| 3588 | 3662 | // Convert the pointer-to-array to a pointer to the first element. |
| 3589 | 3663 | try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0}); |
| 3590 | 3664 | |
| 3591 | | return try self.constructComposite(slice_ty, &.{ elem_ptr_id, len_id }); |
| 3665 | return try self.constructStruct( |
| 3666 | slice_ty, |
| 3667 | &.{ elem_ptr_ty, Type.usize }, |
| 3668 | &.{ elem_ptr_id, len_id }, |
| 3669 | ); |
| 3592 | 3670 | } |
| 3593 | 3671 | |
| 3594 | 3672 | fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | ... | @@ -3596,11 +3674,16 @@ const DeclGen = struct { |
| 3596 | 3674 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3597 | 3675 | const ptr_id = try self.resolve(bin_op.lhs); |
| 3598 | 3676 | const len_id = try self.resolve(bin_op.rhs); |
| 3677 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 3599 | 3678 | const slice_ty = self.typeOfIndex(inst); |
| 3600 | 3679 | |
| 3601 | 3680 | // Note: Types should not need to be converted to direct, these types |
| 3602 | 3681 | // dont need to be converted. |
| 3603 | | return try self.constructComposite(slice_ty, &.{ ptr_id, len_id }); |
| 3682 | return try self.constructStruct( |
| 3683 | slice_ty, |
| 3684 | &.{ ptr_ty, Type.usize }, |
| 3685 | &.{ ptr_id, len_id }, |
| 3686 | ); |
| 3604 | 3687 | } |
| 3605 | 3688 | |
| 3606 | 3689 | fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | ... | @@ -3618,6 +3701,8 @@ const DeclGen = struct { |
| 3618 | 3701 | unreachable; // TODO |
| 3619 | 3702 | } |
| 3620 | 3703 | |
| 3704 | const types = try self.gpa.alloc(Type, elements.len); |
| 3705 | defer self.gpa.free(types); |
| 3621 | 3706 | const constituents = try self.gpa.alloc(IdRef, elements.len); |
| 3622 | 3707 | defer self.gpa.free(constituents); |
| 3623 | 3708 | var index: usize = 0; |
| ... | ... | @@ -3629,6 +3714,7 @@ const DeclGen = struct { |
| 3629 | 3714 | assert(Type.fromInterned(field_ty).hasRuntimeBits(mod)); |
| 3630 | 3715 | |
| 3631 | 3716 | const id = try self.resolve(element); |
| 3717 | types[index] = Type.fromInterned(field_ty); |
| 3632 | 3718 | constituents[index] = try self.convertToIndirect(Type.fromInterned(field_ty), id); |
| 3633 | 3719 | index += 1; |
| 3634 | 3720 | } |
| ... | ... | @@ -3643,6 +3729,7 @@ const DeclGen = struct { |
| 3643 | 3729 | assert(field_ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 3644 | 3730 | |
| 3645 | 3731 | const id = try self.resolve(element); |
| 3732 | types[index] = field_ty; |
| 3646 | 3733 | constituents[index] = try self.convertToIndirect(field_ty, id); |
| 3647 | 3734 | index += 1; |
| 3648 | 3735 | } |
| ... | ... | @@ -3650,7 +3737,11 @@ const DeclGen = struct { |
| 3650 | 3737 | else => unreachable, |
| 3651 | 3738 | } |
| 3652 | 3739 | |
| 3653 | | return try self.constructComposite(result_ty, constituents[0..index]); |
| 3740 | return try self.constructStruct( |
| 3741 | result_ty, |
| 3742 | types[0..index], |
| 3743 | constituents[0..index], |
| 3744 | ); |
| 3654 | 3745 | }, |
| 3655 | 3746 | .Vector => { |
| 3656 | 3747 | const n_elems = result_ty.vectorLen(mod); |
| ... | ... | @@ -3662,7 +3753,7 @@ const DeclGen = struct { |
| 3662 | 3753 | elem_ids[i] = try self.convertToIndirect(result_ty.childType(mod), id); |
| 3663 | 3754 | } |
| 3664 | 3755 | |
| 3665 | | return try self.constructComposite(result_ty, elem_ids); |
| 3756 | return try self.constructVector(result_ty, elem_ids); |
| 3666 | 3757 | }, |
| 3667 | 3758 | .Array => { |
| 3668 | 3759 | const array_info = result_ty.arrayInfo(mod); |
| ... | ... | @@ -3679,7 +3770,7 @@ const DeclGen = struct { |
| 3679 | 3770 | elem_ids[n_elems - 1] = try self.constant(array_info.elem_type, sentinel_val, .indirect); |
| 3680 | 3771 | } |
| 3681 | 3772 | |
| 3682 | | return try self.constructComposite(result_ty, elem_ids); |
| 3773 | return try self.constructArray(result_ty, elem_ids); |
| 3683 | 3774 | }, |
| 3684 | 3775 | else => unreachable, |
| 3685 | 3776 | } |
| ... | ... | @@ -4792,7 +4883,11 @@ const DeclGen = struct { |
| 4792 | 4883 | members[eu_layout.errorFieldIndex()] = operand_id; |
| 4793 | 4884 | members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref); |
| 4794 | 4885 | |
| 4795 | | return try self.constructComposite(err_union_ty, &members); |
| 4886 | var types: [2]Type = undefined; |
| 4887 | types[eu_layout.errorFieldIndex()] = Type.anyerror; |
| 4888 | types[eu_layout.payloadFieldIndex()] = payload_ty; |
| 4889 | |
| 4890 | return try self.constructStruct(err_union_ty, &types, &members); |
| 4796 | 4891 | } |
| 4797 | 4892 | |
| 4798 | 4893 | fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | ... | @@ -4811,7 +4906,11 @@ const DeclGen = struct { |
| 4811 | 4906 | members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0); |
| 4812 | 4907 | members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id); |
| 4813 | 4908 | |
| 4814 | | return try self.constructComposite(err_union_ty, &members); |
| 4909 | var types: [2]Type = undefined; |
| 4910 | types[eu_layout.errorFieldIndex()] = Type.anyerror; |
| 4911 | types[eu_layout.payloadFieldIndex()] = payload_ty; |
| 4912 | |
| 4913 | return try self.constructStruct(err_union_ty, &types, &members); |
| 4815 | 4914 | } |
| 4816 | 4915 | |
| 4817 | 4916 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?IdRef { |
| ... | ... | @@ -4978,7 +5077,8 @@ const DeclGen = struct { |
| 4978 | 5077 | |
| 4979 | 5078 | const payload_id = try self.convertToIndirect(payload_ty, operand_id); |
| 4980 | 5079 | const members = [_]IdRef{ payload_id, try self.constBool(true, .indirect) }; |
| 4981 | | return try self.constructComposite(optional_ty, &members); |
| 5080 | const types = [_]Type{ payload_ty, Type.bool }; |
| 5081 | return try self.constructStruct(optional_ty, &types, &members); |
| 4982 | 5082 | } |
| 4983 | 5083 | |
| 4984 | 5084 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { |