authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2024-02-06 12:08:25+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2024-02-09 09:27:05+03:30
logeb2d61d02e503f01070c05e2e1fc87e827124d94
tree11517e0425081a6b88aef1b919c0740bbe4e18e4
parent42fcca49c55eb9250a9ac8868fa6a9201dd9eb7e

spirv: merge `construct(Struct/Vector/Array)` into `constructComposite`


2 files changed, 30 insertions(+), 124 deletions(-)

src/codegen/spirv.zig+29-123
......@@ -721,75 +721,18 @@ const DeclGen = struct {
721721 };
722722 }
723723
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;
793736 }
794737
795738 /// This function generates a load for a constant in direct (ie, non-memory) representation.
......@@ -897,18 +840,15 @@ const DeclGen = struct {
897840 });
898841
899842 var constituents: [2]IdRef = undefined;
900 var types: [2]Type = undefined;
901843 if (eu_layout.error_first) {
902844 constituents[0] = try self.constant(err_ty, err_val, .indirect);
903845 constituents[1] = try self.constant(payload_ty, payload_val, .indirect);
904 types = .{ err_ty, payload_ty };
905846 } else {
906847 constituents[0] = try self.constant(payload_ty, payload_val, .indirect);
907848 constituents[1] = try self.constant(err_ty, err_val, .indirect);
908 types = .{ payload_ty, err_ty };
909849 }
910850
911 return try self.constructStruct(ty, &types, &constituents);
851 return try self.constructComposite(ty, &constituents);
912852 },
913853 .enum_tag => {
914854 const int_val = try val.intFromEnum(ty, mod);
......@@ -920,11 +860,7 @@ const DeclGen = struct {
920860 const ptr_ty = ty.slicePtrFieldType(mod);
921861 const ptr_id = try self.constantPtr(ptr_ty, Value.fromInterned(slice.ptr));
922862 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 });
928864 },
929865 .opt => {
930866 const payload_ty = ty.optionalChild(mod);
......@@ -951,11 +887,7 @@ const DeclGen = struct {
951887 else
952888 try self.spv.constUndef(try self.resolveType(payload_ty, .indirect));
953889
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 });
959891 },
960892 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {
961893 inline .array_type, .vector_type => |array_type, tag| {
......@@ -992,9 +924,9 @@ const DeclGen = struct {
992924 const sentinel = Value.fromInterned(array_type.sentinel);
993925 constituents[constituents.len - 1] = try self.constant(elem_ty, sentinel, .indirect);
994926 }
995 return self.constructArray(ty, constituents);
927 return self.constructComposite(ty, constituents);
996928 },
997 inline .vector_type => return self.constructVector(ty, constituents),
929 inline .vector_type => return self.constructComposite(ty, constituents),
998930 else => unreachable,
999931 }
1000932 },
......@@ -1004,9 +936,6 @@ const DeclGen = struct {
1004936 return self.todo("packed struct constants", .{});
1005937 }
1006938
1007 var types = std.ArrayList(Type).init(self.gpa);
1008 defer types.deinit();
1009
1010939 var constituents = std.ArrayList(IdRef).init(self.gpa);
1011940 defer constituents.deinit();
1012941
......@@ -1022,11 +951,10 @@ const DeclGen = struct {
1022951 const field_val = try val.fieldValue(mod, field_index);
1023952 const field_id = try self.constant(field_ty, field_val, .indirect);
1024953
1025 try types.append(field_ty);
1026954 try constituents.append(field_id);
1027955 }
1028956
1029 return try self.constructStruct(ty, types.items, constituents.items);
957 return try self.constructComposite(ty, constituents.items);
1030958 },
1031959 .anon_struct_type => unreachable, // TODO
1032960 else => unreachable,
......@@ -1870,7 +1798,7 @@ const DeclGen = struct {
18701798 for (wip.results) |*result| {
18711799 result.* = try wip.dg.convertToIndirect(wip.scalar_ty, result.*);
18721800 }
1873 return try wip.dg.constructArray(wip.result_ty, wip.results);
1801 return try wip.dg.constructComposite(wip.result_ty, wip.results);
18741802 } else {
18751803 return wip.results[0];
18761804 }
......@@ -2814,9 +2742,8 @@ const DeclGen = struct {
28142742 ov_id.* = try self.intFromBool(wip_ov.scalar_ty_ref, overflowed_id);
28152743 }
28162744
2817 return try self.constructStruct(
2745 return try self.constructComposite(
28182746 result_ty,
2819 &.{ operand_ty, ov_ty },
28202747 &.{ try wip_result.finalize(), try wip_ov.finalize() },
28212748 );
28222749 }
......@@ -2905,9 +2832,8 @@ const DeclGen = struct {
29052832 ov_id.* = try self.intFromBool(wip_ov.scalar_ty_ref, overflowed_id);
29062833 }
29072834
2908 return try self.constructStruct(
2835 return try self.constructComposite(
29092836 result_ty,
2910 &.{ operand_ty, ov_ty },
29112837 &.{ try wip_result.finalize(), try wip_ov.finalize() },
29122838 );
29132839 }
......@@ -3637,9 +3563,8 @@ const DeclGen = struct {
36373563 // Convert the pointer-to-array to a pointer to the first element.
36383564 try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0});
36393565
3640 return try self.constructStruct(
3566 return try self.constructComposite(
36413567 slice_ty,
3642 &.{ elem_ptr_ty, Type.usize },
36433568 &.{ elem_ptr_id, len_id },
36443569 );
36453570 }
......@@ -3651,14 +3576,12 @@ const DeclGen = struct {
36513576 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
36523577 const ptr_id = try self.resolve(bin_op.lhs);
36533578 const len_id = try self.resolve(bin_op.rhs);
3654 const ptr_ty = self.typeOf(bin_op.lhs);
36553579 const slice_ty = self.typeOfIndex(inst);
36563580
36573581 // Note: Types should not need to be converted to direct, these types
36583582 // dont need to be converted.
3659 return try self.constructStruct(
3583 return try self.constructComposite(
36603584 slice_ty,
3661 &.{ ptr_ty, Type.usize },
36623585 &.{ ptr_id, len_id },
36633586 );
36643587 }
......@@ -3680,8 +3603,6 @@ const DeclGen = struct {
36803603 unreachable; // TODO
36813604 }
36823605
3683 const types = try self.gpa.alloc(Type, elements.len);
3684 defer self.gpa.free(types);
36853606 const constituents = try self.gpa.alloc(IdRef, elements.len);
36863607 defer self.gpa.free(constituents);
36873608 var index: usize = 0;
......@@ -3693,7 +3614,6 @@ const DeclGen = struct {
36933614 assert(Type.fromInterned(field_ty).hasRuntimeBits(mod));
36943615
36953616 const id = try self.resolve(element);
3696 types[index] = Type.fromInterned(field_ty);
36973617 constituents[index] = try self.convertToIndirect(Type.fromInterned(field_ty), id);
36983618 index += 1;
36993619 }
......@@ -3707,7 +3627,6 @@ const DeclGen = struct {
37073627 assert(field_ty.hasRuntimeBitsIgnoreComptime(mod));
37083628
37093629 const id = try self.resolve(element);
3710 types[index] = field_ty;
37113630 constituents[index] = try self.convertToIndirect(field_ty, id);
37123631 index += 1;
37133632 }
......@@ -3715,11 +3634,7 @@ const DeclGen = struct {
37153634 else => unreachable,
37163635 }
37173636
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]);
37233638 },
37243639 .Vector => {
37253640 const n_elems = result_ty.vectorLen(mod);
......@@ -3731,7 +3646,7 @@ const DeclGen = struct {
37313646 elem_ids[i] = try self.convertToIndirect(result_ty.childType(mod), id);
37323647 }
37333648
3734 return try self.constructVector(result_ty, elem_ids);
3649 return try self.constructComposite(result_ty, elem_ids);
37353650 },
37363651 .Array => {
37373652 const array_info = result_ty.arrayInfo(mod);
......@@ -3748,7 +3663,7 @@ const DeclGen = struct {
37483663 elem_ids[n_elems - 1] = try self.constant(array_info.elem_type, sentinel_val, .indirect);
37493664 }
37503665
3751 return try self.constructArray(result_ty, elem_ids);
3666 return try self.constructComposite(result_ty, elem_ids);
37523667 },
37533668 else => unreachable,
37543669 }
......@@ -4885,11 +4800,7 @@ const DeclGen = struct {
48854800 members[eu_layout.errorFieldIndex()] = operand_id;
48864801 members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref);
48874802
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);
48934804 }
48944805
48954806 fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
......@@ -4910,11 +4821,7 @@ const DeclGen = struct {
49104821 members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0);
49114822 members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id);
49124823
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);
49184825 }
49194826
49204827 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 {
50914998
50924999 const payload_id = try self.convertToIndirect(payload_ty, operand_id);
50935000 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);
50965002 }
50975003
50985004 fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void {
src/link/SpirV.zig+1-1
......@@ -163,7 +163,7 @@ pub fn updateExports(
163163 .Vertex => spec.ExecutionModel.Vertex,
164164 .Fragment => spec.ExecutionModel.Fragment,
165165 .Kernel => spec.ExecutionModel.Kernel,
166 else => unreachable,
166 else => return,
167167 };
168168 const is_vulkan = target.os.tag == .vulkan;
169169