| ... | ... | @@ -721,75 +721,18 @@ const DeclGen = struct { |
| 721 | 721 | }; |
| 722 | 722 | } |
| 723 | 723 | |
| 724 | | /// Construct a struct at runtime. |
| 725 | | /// ty must be a struct type. |
| 726 | | /// Constituents should be in `indirect` representation (as the elements of a struct should be). |
| 727 | | /// Result is in `direct` representation. |
| 728 | | fn constructStruct(self: *DeclGen, ty: Type, types: []const Type, constituents: []const IdRef) !IdRef { |
| 729 | | assert(types.len == constituents.len); |
| 730 | | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 731 | | // operands are not constant. |
| 732 | | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 733 | | // For now, just initialize the struct by setting the fields manually... |
| 734 | | // TODO: Make this OpCompositeConstruct when we can |
| 735 | | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| 736 | | for (constituents, types, 0..) |constitent_id, member_ty, index| { |
| 737 | | const ptr_member_ty_ref = try self.ptrType(member_ty, .Function); |
| 738 | | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 739 | | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 740 | | .pointer = ptr_id, |
| 741 | | .object = constitent_id, |
| 742 | | }); |
| 743 | | } |
| 744 | | return try self.load(ty, ptr_composite_id, .{}); |
| 745 | | } |
| 746 | | |
| 747 | | /// Construct a vector at runtime. |
| 748 | | /// ty must be an vector type. |
| 749 | | /// Constituents should be in `indirect` representation (as the elements of an vector should be). |
| 750 | | /// Result is in `direct` representation. |
| 751 | | fn constructVector(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| 752 | | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 753 | | // operands are not constant. |
| 754 | | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 755 | | // For now, just initialize the struct by setting the fields manually... |
| 756 | | // TODO: Make this OpCompositeConstruct when we can |
| 757 | | const mod = self.module; |
| 758 | | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| 759 | | const ptr_elem_ty_ref = try self.ptrType(ty.elemType2(mod), .Function); |
| 760 | | for (constituents, 0..) |constitent_id, index| { |
| 761 | | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 762 | | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 763 | | .pointer = ptr_id, |
| 764 | | .object = constitent_id, |
| 765 | | }); |
| 766 | | } |
| 767 | | |
| 768 | | return try self.load(ty, ptr_composite_id, .{}); |
| 769 | | } |
| 770 | | |
| 771 | | /// Construct an array at runtime. |
| 772 | | /// ty must be an array type. |
| 773 | | /// Constituents should be in `indirect` representation (as the elements of an array should be). |
| 774 | | /// Result is in `direct` representation. |
| 775 | | fn constructArray(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| 776 | | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 777 | | // operands are not constant. |
| 778 | | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 779 | | // For now, just initialize the struct by setting the fields manually... |
| 780 | | // TODO: Make this OpCompositeConstruct when we can |
| 781 | | const mod = self.module; |
| 782 | | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| 783 | | const ptr_elem_ty_ref = try self.ptrType(ty.elemType2(mod), .Function); |
| 784 | | for (constituents, 0..) |constitent_id, index| { |
| 785 | | const ptr_id = try self.accessChain(ptr_elem_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 | | |
| 792 | | return try self.load(ty, ptr_composite_id, .{}); |
| 724 | /// Construct a composite value at runtime. If the parameters are in direct |
| 725 | /// representation, then the result is also in direct representation. Otherwise, |
| 726 | /// if the parameters are in indirect representation, then the result is too. |
| 727 | fn constructComposite(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| 728 | const constituents_id = self.spv.allocId(); |
| 729 | const type_id = try self.resolveTypeId(ty); |
| 730 | try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ |
| 731 | .id_result_type = type_id, |
| 732 | .id_result = constituents_id, |
| 733 | .constituents = constituents, |
| 734 | }); |
| 735 | return constituents_id; |
| 793 | 736 | } |
| 794 | 737 | |
| 795 | 738 | /// This function generates a load for a constant in direct (ie, non-memory) representation. |
| ... | ... | @@ -897,18 +840,15 @@ const DeclGen = struct { |
| 897 | 840 | }); |
| 898 | 841 | |
| 899 | 842 | var constituents: [2]IdRef = undefined; |
| 900 | | var types: [2]Type = undefined; |
| 901 | 843 | if (eu_layout.error_first) { |
| 902 | 844 | constituents[0] = try self.constant(err_ty, err_val, .indirect); |
| 903 | 845 | constituents[1] = try self.constant(payload_ty, payload_val, .indirect); |
| 904 | | types = .{ err_ty, payload_ty }; |
| 905 | 846 | } else { |
| 906 | 847 | constituents[0] = try self.constant(payload_ty, payload_val, .indirect); |
| 907 | 848 | constituents[1] = try self.constant(err_ty, err_val, .indirect); |
| 908 | | types = .{ payload_ty, err_ty }; |
| 909 | 849 | } |
| 910 | 850 | |
| 911 | | return try self.constructStruct(ty, &types, &constituents); |
| 851 | return try self.constructComposite(ty, &constituents); |
| 912 | 852 | }, |
| 913 | 853 | .enum_tag => { |
| 914 | 854 | const int_val = try val.intFromEnum(ty, mod); |
| ... | ... | @@ -920,11 +860,7 @@ const DeclGen = struct { |
| 920 | 860 | const ptr_ty = ty.slicePtrFieldType(mod); |
| 921 | 861 | const ptr_id = try self.constantPtr(ptr_ty, Value.fromInterned(slice.ptr)); |
| 922 | 862 | const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect); |
| 923 | | return self.constructStruct( |
| 924 | | ty, |
| 925 | | &.{ ptr_ty, Type.usize }, |
| 926 | | &.{ ptr_id, len_id }, |
| 927 | | ); |
| 863 | return self.constructComposite(ty, &.{ ptr_id, len_id }); |
| 928 | 864 | }, |
| 929 | 865 | .opt => { |
| 930 | 866 | const payload_ty = ty.optionalChild(mod); |
| ... | ... | @@ -951,11 +887,7 @@ const DeclGen = struct { |
| 951 | 887 | else |
| 952 | 888 | try self.spv.constUndef(try self.resolveType(payload_ty, .indirect)); |
| 953 | 889 | |
| 954 | | return try self.constructStruct( |
| 955 | | ty, |
| 956 | | &.{ payload_ty, Type.bool }, |
| 957 | | &.{ payload_id, has_pl_id }, |
| 958 | | ); |
| 890 | return try self.constructComposite(ty, &.{ payload_id, has_pl_id }); |
| 959 | 891 | }, |
| 960 | 892 | .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { |
| 961 | 893 | inline .array_type, .vector_type => |array_type, tag| { |
| ... | ... | @@ -992,9 +924,9 @@ const DeclGen = struct { |
| 992 | 924 | const sentinel = Value.fromInterned(array_type.sentinel); |
| 993 | 925 | constituents[constituents.len - 1] = try self.constant(elem_ty, sentinel, .indirect); |
| 994 | 926 | } |
| 995 | | return self.constructArray(ty, constituents); |
| 927 | return self.constructComposite(ty, constituents); |
| 996 | 928 | }, |
| 997 | | inline .vector_type => return self.constructVector(ty, constituents), |
| 929 | inline .vector_type => return self.constructComposite(ty, constituents), |
| 998 | 930 | else => unreachable, |
| 999 | 931 | } |
| 1000 | 932 | }, |
| ... | ... | @@ -1004,9 +936,6 @@ const DeclGen = struct { |
| 1004 | 936 | return self.todo("packed struct constants", .{}); |
| 1005 | 937 | } |
| 1006 | 938 | |
| 1007 | | var types = std.ArrayList(Type).init(self.gpa); |
| 1008 | | defer types.deinit(); |
| 1009 | | |
| 1010 | 939 | var constituents = std.ArrayList(IdRef).init(self.gpa); |
| 1011 | 940 | defer constituents.deinit(); |
| 1012 | 941 | |
| ... | ... | @@ -1022,11 +951,10 @@ const DeclGen = struct { |
| 1022 | 951 | const field_val = try val.fieldValue(mod, field_index); |
| 1023 | 952 | const field_id = try self.constant(field_ty, field_val, .indirect); |
| 1024 | 953 | |
| 1025 | | try types.append(field_ty); |
| 1026 | 954 | try constituents.append(field_id); |
| 1027 | 955 | } |
| 1028 | 956 | |
| 1029 | | return try self.constructStruct(ty, types.items, constituents.items); |
| 957 | return try self.constructComposite(ty, constituents.items); |
| 1030 | 958 | }, |
| 1031 | 959 | .anon_struct_type => unreachable, // TODO |
| 1032 | 960 | else => unreachable, |
| ... | ... | @@ -1870,7 +1798,7 @@ const DeclGen = struct { |
| 1870 | 1798 | for (wip.results) |*result| { |
| 1871 | 1799 | result.* = try wip.dg.convertToIndirect(wip.scalar_ty, result.*); |
| 1872 | 1800 | } |
| 1873 | | return try wip.dg.constructArray(wip.result_ty, wip.results); |
| 1801 | return try wip.dg.constructComposite(wip.result_ty, wip.results); |
| 1874 | 1802 | } else { |
| 1875 | 1803 | return wip.results[0]; |
| 1876 | 1804 | } |
| ... | ... | @@ -2814,9 +2742,8 @@ const DeclGen = struct { |
| 2814 | 2742 | ov_id.* = try self.intFromBool(wip_ov.scalar_ty_ref, overflowed_id); |
| 2815 | 2743 | } |
| 2816 | 2744 | |
| 2817 | | return try self.constructStruct( |
| 2745 | return try self.constructComposite( |
| 2818 | 2746 | result_ty, |
| 2819 | | &.{ operand_ty, ov_ty }, |
| 2820 | 2747 | &.{ try wip_result.finalize(), try wip_ov.finalize() }, |
| 2821 | 2748 | ); |
| 2822 | 2749 | } |
| ... | ... | @@ -2905,9 +2832,8 @@ const DeclGen = struct { |
| 2905 | 2832 | ov_id.* = try self.intFromBool(wip_ov.scalar_ty_ref, overflowed_id); |
| 2906 | 2833 | } |
| 2907 | 2834 | |
| 2908 | | return try self.constructStruct( |
| 2835 | return try self.constructComposite( |
| 2909 | 2836 | result_ty, |
| 2910 | | &.{ operand_ty, ov_ty }, |
| 2911 | 2837 | &.{ try wip_result.finalize(), try wip_ov.finalize() }, |
| 2912 | 2838 | ); |
| 2913 | 2839 | } |
| ... | ... | @@ -3637,9 +3563,8 @@ const DeclGen = struct { |
| 3637 | 3563 | // Convert the pointer-to-array to a pointer to the first element. |
| 3638 | 3564 | try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0}); |
| 3639 | 3565 | |
| 3640 | | return try self.constructStruct( |
| 3566 | return try self.constructComposite( |
| 3641 | 3567 | slice_ty, |
| 3642 | | &.{ elem_ptr_ty, Type.usize }, |
| 3643 | 3568 | &.{ elem_ptr_id, len_id }, |
| 3644 | 3569 | ); |
| 3645 | 3570 | } |
| ... | ... | @@ -3651,14 +3576,12 @@ const DeclGen = struct { |
| 3651 | 3576 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3652 | 3577 | const ptr_id = try self.resolve(bin_op.lhs); |
| 3653 | 3578 | const len_id = try self.resolve(bin_op.rhs); |
| 3654 | | const ptr_ty = self.typeOf(bin_op.lhs); |
| 3655 | 3579 | const slice_ty = self.typeOfIndex(inst); |
| 3656 | 3580 | |
| 3657 | 3581 | // Note: Types should not need to be converted to direct, these types |
| 3658 | 3582 | // dont need to be converted. |
| 3659 | | return try self.constructStruct( |
| 3583 | return try self.constructComposite( |
| 3660 | 3584 | slice_ty, |
| 3661 | | &.{ ptr_ty, Type.usize }, |
| 3662 | 3585 | &.{ ptr_id, len_id }, |
| 3663 | 3586 | ); |
| 3664 | 3587 | } |
| ... | ... | @@ -3680,8 +3603,6 @@ const DeclGen = struct { |
| 3680 | 3603 | unreachable; // TODO |
| 3681 | 3604 | } |
| 3682 | 3605 | |
| 3683 | | const types = try self.gpa.alloc(Type, elements.len); |
| 3684 | | defer self.gpa.free(types); |
| 3685 | 3606 | const constituents = try self.gpa.alloc(IdRef, elements.len); |
| 3686 | 3607 | defer self.gpa.free(constituents); |
| 3687 | 3608 | var index: usize = 0; |
| ... | ... | @@ -3693,7 +3614,6 @@ const DeclGen = struct { |
| 3693 | 3614 | assert(Type.fromInterned(field_ty).hasRuntimeBits(mod)); |
| 3694 | 3615 | |
| 3695 | 3616 | const id = try self.resolve(element); |
| 3696 | | types[index] = Type.fromInterned(field_ty); |
| 3697 | 3617 | constituents[index] = try self.convertToIndirect(Type.fromInterned(field_ty), id); |
| 3698 | 3618 | index += 1; |
| 3699 | 3619 | } |
| ... | ... | @@ -3707,7 +3627,6 @@ const DeclGen = struct { |
| 3707 | 3627 | assert(field_ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 3708 | 3628 | |
| 3709 | 3629 | const id = try self.resolve(element); |
| 3710 | | types[index] = field_ty; |
| 3711 | 3630 | constituents[index] = try self.convertToIndirect(field_ty, id); |
| 3712 | 3631 | index += 1; |
| 3713 | 3632 | } |
| ... | ... | @@ -3715,11 +3634,7 @@ const DeclGen = struct { |
| 3715 | 3634 | else => unreachable, |
| 3716 | 3635 | } |
| 3717 | 3636 | |
| 3718 | | return try self.constructStruct( |
| 3719 | | result_ty, |
| 3720 | | types[0..index], |
| 3721 | | constituents[0..index], |
| 3722 | | ); |
| 3637 | return try self.constructComposite(result_ty, constituents[0..index]); |
| 3723 | 3638 | }, |
| 3724 | 3639 | .Vector => { |
| 3725 | 3640 | const n_elems = result_ty.vectorLen(mod); |
| ... | ... | @@ -3731,7 +3646,7 @@ const DeclGen = struct { |
| 3731 | 3646 | elem_ids[i] = try self.convertToIndirect(result_ty.childType(mod), id); |
| 3732 | 3647 | } |
| 3733 | 3648 | |
| 3734 | | return try self.constructVector(result_ty, elem_ids); |
| 3649 | return try self.constructComposite(result_ty, elem_ids); |
| 3735 | 3650 | }, |
| 3736 | 3651 | .Array => { |
| 3737 | 3652 | const array_info = result_ty.arrayInfo(mod); |
| ... | ... | @@ -3748,7 +3663,7 @@ const DeclGen = struct { |
| 3748 | 3663 | elem_ids[n_elems - 1] = try self.constant(array_info.elem_type, sentinel_val, .indirect); |
| 3749 | 3664 | } |
| 3750 | 3665 | |
| 3751 | | return try self.constructArray(result_ty, elem_ids); |
| 3666 | return try self.constructComposite(result_ty, elem_ids); |
| 3752 | 3667 | }, |
| 3753 | 3668 | else => unreachable, |
| 3754 | 3669 | } |
| ... | ... | @@ -4885,11 +4800,7 @@ const DeclGen = struct { |
| 4885 | 4800 | members[eu_layout.errorFieldIndex()] = operand_id; |
| 4886 | 4801 | members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref); |
| 4887 | 4802 | |
| 4888 | | var types: [2]Type = undefined; |
| 4889 | | types[eu_layout.errorFieldIndex()] = Type.anyerror; |
| 4890 | | types[eu_layout.payloadFieldIndex()] = payload_ty; |
| 4891 | | |
| 4892 | | return try self.constructStruct(err_union_ty, &types, &members); |
| 4803 | return try self.constructComposite(err_union_ty, &members); |
| 4893 | 4804 | } |
| 4894 | 4805 | |
| 4895 | 4806 | fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | ... | @@ -4910,11 +4821,7 @@ const DeclGen = struct { |
| 4910 | 4821 | members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0); |
| 4911 | 4822 | members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id); |
| 4912 | 4823 | |
| 4913 | | var types: [2]Type = undefined; |
| 4914 | | types[eu_layout.errorFieldIndex()] = Type.anyerror; |
| 4915 | | types[eu_layout.payloadFieldIndex()] = payload_ty; |
| 4916 | | |
| 4917 | | return try self.constructStruct(err_union_ty, &types, &members); |
| 4824 | return try self.constructComposite(err_union_ty, &members); |
| 4918 | 4825 | } |
| 4919 | 4826 | |
| 4920 | 4827 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?IdRef { |
| ... | ... | @@ -5091,8 +4998,7 @@ const DeclGen = struct { |
| 5091 | 4998 | |
| 5092 | 4999 | const payload_id = try self.convertToIndirect(payload_ty, operand_id); |
| 5093 | 5000 | const members = [_]IdRef{ payload_id, try self.constBool(true, .indirect) }; |
| 5094 | | const types = [_]Type{ payload_ty, Type.bool }; |
| 5095 | | return try self.constructStruct(optional_ty, &types, &members); |
| 5001 | return try self.constructComposite(optional_ty, &members); |
| 5096 | 5002 | } |
| 5097 | 5003 | |
| 5098 | 5004 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { |