| ... | @@ -209,10 +209,6 @@ const DeclGen = struct { | ... | @@ -209,10 +209,6 @@ const DeclGen = struct { |
| 209 | /// See Object.type_map | 209 | /// See Object.type_map |
| 210 | type_map: *TypeMap, | 210 | type_map: *TypeMap, |
| 211 | | 211 | |
| 212 | /// Child types of pointers that are currently in progress of being resolved. If a pointer | | |
| 213 | /// is already in this map, its recursive. | | |
| 214 | wip_pointers: std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, CacheRef) = .{}, | | |
| 215 | | | |
| 216 | /// We need to keep track of result ids for block labels, as well as the 'incoming' | 212 | /// We need to keep track of result ids for block labels, as well as the 'incoming' |
| 217 | /// blocks for a block. | 213 | /// blocks for a block. |
| 218 | blocks: BlockMap = .{}, | 214 | blocks: BlockMap = .{}, |
| ... | @@ -299,7 +295,6 @@ const DeclGen = struct { | ... | @@ -299,7 +295,6 @@ const DeclGen = struct { |
| 299 | pub fn deinit(self: *DeclGen) void { | 295 | pub fn deinit(self: *DeclGen) void { |
| 300 | self.args.deinit(self.gpa); | 296 | self.args.deinit(self.gpa); |
| 301 | self.inst_results.deinit(self.gpa); | 297 | self.inst_results.deinit(self.gpa); |
| 302 | self.wip_pointers.deinit(self.gpa); | | |
| 303 | self.blocks.deinit(self.gpa); | 298 | self.blocks.deinit(self.gpa); |
| 304 | self.func.deinit(self.gpa); | 299 | self.func.deinit(self.gpa); |
| 305 | self.base_line_stack.deinit(self.gpa); | 300 | self.base_line_stack.deinit(self.gpa); |
| ... | @@ -363,7 +358,8 @@ const DeclGen = struct { | ... | @@ -363,7 +358,8 @@ const DeclGen = struct { |
| 363 | | 358 | |
| 364 | const mod = self.module; | 359 | const mod = self.module; |
| 365 | const ty = mod.intern_pool.typeOf(val).toType(); | 360 | const ty = mod.intern_pool.typeOf(val).toType(); |
| 366 | const ptr_ty_ref = try self.ptrType(ty, storage_class); | 361 | const ty_ref = try self.resolveType(ty, .indirect); |
| | 362 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class); |
| 367 | | 363 | |
| 368 | const var_id = self.spv.declPtr(spv_decl_index).result_id; | 364 | const var_id = self.spv.declPtr(spv_decl_index).result_id; |
| 369 | | 365 | |
| ... | @@ -586,41 +582,66 @@ const DeclGen = struct { | ... | @@ -586,41 +582,66 @@ const DeclGen = struct { |
| 586 | } | 582 | } |
| 587 | | 583 | |
| 588 | /// Construct a struct at runtime. | 584 | /// Construct a struct at runtime. |
| 589 | /// ty must be a struct type. | 585 | /// result_ty_ref must be a struct type. |
| 590 | /// Constituents should be in `indirect` representation (as the elements of a struct should be). | 586 | /// Constituents should be in `indirect` representation (as the elements of a struct should be). |
| 591 | /// Result is in `direct` representation. | 587 | /// Result is in `direct` representation. |
| 592 | fn constructStruct(self: *DeclGen, ty: Type, types: []const Type, constituents: []const IdRef) !IdRef { | 588 | fn constructStruct(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef { |
| 593 | assert(types.len == constituents.len); | | |
| 594 | // 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' |
| 595 | // operands are not constant. | 590 | // operands are not constant. |
| 596 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 | 591 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 597 | // For now, just initialize the struct by setting the fields manually... | 592 | // For now, just initialize the struct by setting the fields manually... |
| 598 | // TODO: Make this OpCompositeConstruct when we can | 593 | // TODO: Make this OpCompositeConstruct when we can |
| 599 | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); | 594 | const ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); |
| 600 | for (constituents, types, 0..) |constitent_id, member_ty, index| { | 595 | const ptr_composite_id = self.spv.allocId(); |
| 601 | const ptr_member_ty_ref = try self.ptrType(member_ty, .Function); | 596 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| | 597 | .id_result_type = self.typeId(ptr_ty_ref), |
| | 598 | .id_result = ptr_composite_id, |
| | 599 | .storage_class = .Function, |
| | 600 | }); |
| | 601 | |
| | 602 | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).struct_type; |
| | 603 | const member_types = spv_composite_ty.member_types; |
| | 604 | |
| | 605 | for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| { |
| | 606 | const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Function); |
| 602 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); | 607 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 603 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 608 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 604 | .pointer = ptr_id, | 609 | .pointer = ptr_id, |
| 605 | .object = constitent_id, | 610 | .object = constitent_id, |
| 606 | }); | 611 | }); |
| 607 | } | 612 | } |
| 608 | return try self.load(ty, ptr_composite_id, .{}); | 613 | const result_id = self.spv.allocId(); |
| | 614 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| | 615 | .id_result_type = self.typeId(result_ty_ref), |
| | 616 | .id_result = result_id, |
| | 617 | .pointer = ptr_composite_id, |
| | 618 | }); |
| | 619 | return result_id; |
| 609 | } | 620 | } |
| 610 | | 621 | |
| 611 | /// Construct an array at runtime. | 622 | /// Construct an array at runtime. |
| 612 | /// ty must be an array type. | 623 | /// result_ty_ref must be an array type. |
| 613 | /// Constituents should be in `indirect` representation (as the elements of an array should be). | 624 | /// Constituents should be in `indirect` representation (as the elements of an array should be). |
| 614 | /// Result is in `direct` representation. | 625 | /// Result is in `direct` representation. |
| 615 | fn constructArray(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { | 626 | fn constructArray(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef { |
| 616 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' | 627 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 617 | // operands are not constant. | 628 | // operands are not constant. |
| 618 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 | 629 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 619 | // For now, just initialize the struct by setting the fields manually... | 630 | // For now, just initialize the struct by setting the fields manually... |
| 620 | // TODO: Make this OpCompositeConstruct when we can | 631 | // TODO: Make this OpCompositeConstruct when we can |
| 621 | const mod = self.module; | 632 | // TODO: Make this Function storage type |
| 622 | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); | 633 | const ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); |
| 623 | const ptr_elem_ty_ref = try self.ptrType(ty.elemType2(mod), .Function); | 634 | const ptr_composite_id = self.spv.allocId(); |
| | 635 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| | 636 | .id_result_type = self.typeId(ptr_ty_ref), |
| | 637 | .id_result = ptr_composite_id, |
| | 638 | .storage_class = .Function, |
| | 639 | }); |
| | 640 | |
| | 641 | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).array_type; |
| | 642 | const elem_ty_ref = spv_composite_ty.element_type; |
| | 643 | const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Function); |
| | 644 | |
| 624 | for (constituents, 0..) |constitent_id, index| { | 645 | for (constituents, 0..) |constitent_id, index| { |
| 625 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); | 646 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 626 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 647 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| ... | @@ -628,8 +649,13 @@ const DeclGen = struct { | ... | @@ -628,8 +649,13 @@ const DeclGen = struct { |
| 628 | .object = constitent_id, | 649 | .object = constitent_id, |
| 629 | }); | 650 | }); |
| 630 | } | 651 | } |
| 631 | | 652 | const result_id = self.spv.allocId(); |
| 632 | return try self.load(ty, ptr_composite_id, .{}); | 653 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| | 654 | .id_result_type = self.typeId(result_ty_ref), |
| | 655 | .id_result = result_id, |
| | 656 | .pointer = ptr_composite_id, |
| | 657 | }); |
| | 658 | return result_id; |
| 633 | } | 659 | } |
| 634 | | 660 | |
| 635 | /// This function generates a load for a constant in direct (ie, non-memory) representation. | 661 | /// This function generates a load for a constant in direct (ie, non-memory) representation. |
| ... | @@ -740,18 +766,15 @@ const DeclGen = struct { | ... | @@ -740,18 +766,15 @@ const DeclGen = struct { |
| 740 | }.toValue(); | 766 | }.toValue(); |
| 741 | | 767 | |
| 742 | var constituents: [2]IdRef = undefined; | 768 | var constituents: [2]IdRef = undefined; |
| 743 | var types: [2]Type = undefined; | | |
| 744 | if (eu_layout.error_first) { | 769 | if (eu_layout.error_first) { |
| 745 | constituents[0] = try self.constant(err_ty, err_val, .indirect); | 770 | constituents[0] = try self.constant(err_ty, err_val, .indirect); |
| 746 | constituents[1] = try self.constant(payload_ty, payload_val, .indirect); | 771 | constituents[1] = try self.constant(payload_ty, payload_val, .indirect); |
| 747 | types = .{ err_ty, payload_ty }; | | |
| 748 | } else { | 772 | } else { |
| 749 | constituents[0] = try self.constant(payload_ty, payload_val, .indirect); | 773 | constituents[0] = try self.constant(payload_ty, payload_val, .indirect); |
| 750 | constituents[1] = try self.constant(err_ty, err_val, .indirect); | 774 | constituents[1] = try self.constant(err_ty, err_val, .indirect); |
| 751 | types = .{ payload_ty, err_ty }; | | |
| 752 | } | 775 | } |
| 753 | | 776 | |
| 754 | return try self.constructStruct(ty, &types, &constituents); | 777 | return try self.constructStruct(result_ty_ref, &constituents); |
| 755 | }, | 778 | }, |
| 756 | .enum_tag => { | 779 | .enum_tag => { |
| 757 | const int_val = try val.intFromEnum(ty, mod); | 780 | const int_val = try val.intFromEnum(ty, mod); |
| ... | @@ -769,11 +792,7 @@ const DeclGen = struct { | ... | @@ -769,11 +792,7 @@ const DeclGen = struct { |
| 769 | } | 792 | } |
| 770 | | 793 | |
| 771 | const len_id = try self.constant(Type.usize, ptr.len.toValue(), .indirect); | 794 | const len_id = try self.constant(Type.usize, ptr.len.toValue(), .indirect); |
| 772 | return try self.constructStruct( | 795 | return try self.constructStruct(result_ty_ref, &.{ ptr_id, len_id }); |
| 773 | ty, | | |
| 774 | &.{ ptr_ty, Type.usize }, | | |
| 775 | &.{ ptr_id, len_id }, | | |
| 776 | ); | | |
| 777 | }, | 796 | }, |
| 778 | .opt => { | 797 | .opt => { |
| 779 | const payload_ty = ty.optionalChild(mod); | 798 | const payload_ty = ty.optionalChild(mod); |
| ... | @@ -800,11 +819,7 @@ const DeclGen = struct { | ... | @@ -800,11 +819,7 @@ const DeclGen = struct { |
| 800 | else | 819 | else |
| 801 | try self.spv.constUndef(try self.resolveType(payload_ty, .indirect)); | 820 | try self.spv.constUndef(try self.resolveType(payload_ty, .indirect)); |
| 802 | | 821 | |
| 803 | return try self.constructStruct( | 822 | return try self.constructStruct(result_ty_ref, &.{ payload_id, has_pl_id }); |
| 804 | ty, | | |
| 805 | &.{ payload_ty, Type.bool }, | | |
| 806 | &.{ payload_id, has_pl_id }, | | |
| 807 | ); | | |
| 808 | }, | 823 | }, |
| 809 | .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { | 824 | .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { |
| 810 | inline .array_type, .vector_type => |array_type, tag| { | 825 | inline .array_type, .vector_type => |array_type, tag| { |
| ... | @@ -842,7 +857,7 @@ const DeclGen = struct { | ... | @@ -842,7 +857,7 @@ const DeclGen = struct { |
| 842 | else => {}, | 857 | else => {}, |
| 843 | } | 858 | } |
| 844 | | 859 | |
| 845 | return try self.constructArray(ty, constituents); | 860 | return try self.constructArray(result_ty_ref, constituents); |
| 846 | }, | 861 | }, |
| 847 | .struct_type => { | 862 | .struct_type => { |
| 848 | const struct_type = mod.typeToStruct(ty).?; | 863 | const struct_type = mod.typeToStruct(ty).?; |
| ... | @@ -850,9 +865,6 @@ const DeclGen = struct { | ... | @@ -850,9 +865,6 @@ const DeclGen = struct { |
| 850 | return self.todo("packed struct constants", .{}); | 865 | return self.todo("packed struct constants", .{}); |
| 851 | } | 866 | } |
| 852 | | 867 | |
| 853 | var types = std.ArrayList(Type).init(self.gpa); | | |
| 854 | defer types.deinit(); | | |
| 855 | | | |
| 856 | var constituents = std.ArrayList(IdRef).init(self.gpa); | 868 | var constituents = std.ArrayList(IdRef).init(self.gpa); |
| 857 | defer constituents.deinit(); | 869 | defer constituents.deinit(); |
| 858 | | 870 | |
| ... | @@ -868,23 +880,22 @@ const DeclGen = struct { | ... | @@ -868,23 +880,22 @@ const DeclGen = struct { |
| 868 | const field_val = try val.fieldValue(mod, field_index); | 880 | const field_val = try val.fieldValue(mod, field_index); |
| 869 | const field_id = try self.constant(field_ty, field_val, .indirect); | 881 | const field_id = try self.constant(field_ty, field_val, .indirect); |
| 870 | | 882 | |
| 871 | try types.append(field_ty); | | |
| 872 | try constituents.append(field_id); | 883 | try constituents.append(field_id); |
| 873 | } | 884 | } |
| 874 | | 885 | |
| 875 | return try self.constructStruct(ty, types.items, constituents.items); | 886 | return try self.constructStruct(result_ty_ref, constituents.items); |
| 876 | }, | 887 | }, |
| 877 | .anon_struct_type => unreachable, // TODO | 888 | .anon_struct_type => unreachable, // TODO |
| 878 | else => unreachable, | 889 | else => unreachable, |
| 879 | }, | 890 | }, |
| 880 | .un => |un| { | 891 | .un => |un| { |
| 881 | const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; | 892 | const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; |
| 882 | const union_obj = mod.typeToUnion(ty).?; | 893 | const layout = self.unionLayout(ty, active_field); |
| 883 | const field_ty = union_obj.field_types.get(ip)[active_field].toType(); | 894 | const payload = if (layout.active_field_size != 0) |
| 884 | const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod)) | 895 | try self.constant(layout.active_field_ty, un.val.toValue(), .indirect) |
| 885 | try self.constant(field_ty, un.val.toValue(), .direct) | | |
| 886 | else | 896 | else |
| 887 | null; | 897 | null; |
| | 898 | |
| 888 | return try self.unionInit(ty, active_field, payload); | 899 | return try self.unionInit(ty, active_field, payload); |
| 889 | }, | 900 | }, |
| 890 | .memoized_call => unreachable, | 901 | .memoized_call => unreachable, |
| ... | @@ -923,7 +934,8 @@ const DeclGen = struct { | ... | @@ -923,7 +934,8 @@ const DeclGen = struct { |
| 923 | | 934 | |
| 924 | // TODO: Can we consolidate this in ptrElemPtr? | 935 | // TODO: Can we consolidate this in ptrElemPtr? |
| 925 | const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. | 936 | const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. |
| 926 | const elem_ptr_ty_ref = try self.ptrType(elem_ty, spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod))); | 937 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); |
| | 938 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod))); |
| 927 | | 939 | |
| 928 | if (elem_ptr_ty_ref == result_ty_ref) { | 940 | if (elem_ptr_ty_ref == result_ty_ref) { |
| 929 | return elem_ptr_id; | 941 | return elem_ptr_id; |
| ... | @@ -985,7 +997,8 @@ const DeclGen = struct { | ... | @@ -985,7 +997,8 @@ const DeclGen = struct { |
| 985 | }; | 997 | }; |
| 986 | | 998 | |
| 987 | const decl_id = try self.resolveAnonDecl(decl_val, actual_storage_class); | 999 | const decl_id = try self.resolveAnonDecl(decl_val, actual_storage_class); |
| 988 | const decl_ptr_ty_ref = try self.ptrType(decl_ty, final_storage_class); | 1000 | const decl_ty_ref = try self.resolveType(decl_ty, .indirect); |
| | 1001 | const decl_ptr_ty_ref = try self.spv.ptrType(decl_ty_ref, final_storage_class); |
| 989 | | 1002 | |
| 990 | const ptr_id = switch (final_storage_class) { | 1003 | const ptr_id = switch (final_storage_class) { |
| 991 | .Generic => blk: { | 1004 | .Generic => blk: { |
| ... | @@ -1041,7 +1054,8 @@ const DeclGen = struct { | ... | @@ -1041,7 +1054,8 @@ const DeclGen = struct { |
| 1041 | | 1054 | |
| 1042 | const final_storage_class = spvStorageClass(decl.@"addrspace"); | 1055 | const final_storage_class = spvStorageClass(decl.@"addrspace"); |
| 1043 | | 1056 | |
| 1044 | const decl_ptr_ty_ref = try self.ptrType(decl.ty, final_storage_class); | 1057 | const decl_ty_ref = try self.resolveType(decl.ty, .indirect); |
| | 1058 | const decl_ptr_ty_ref = try self.spv.ptrType(decl_ty_ref, final_storage_class); |
| 1045 | | 1059 | |
| 1046 | const ptr_id = switch (final_storage_class) { | 1060 | const ptr_id = switch (final_storage_class) { |
| 1047 | .Generic => blk: { | 1061 | .Generic => blk: { |
| ... | @@ -1109,52 +1123,29 @@ const DeclGen = struct { | ... | @@ -1109,52 +1123,29 @@ const DeclGen = struct { |
| 1109 | return try self.intType(.unsigned, self.getTarget().ptrBitWidth()); | 1123 | return try self.intType(.unsigned, self.getTarget().ptrBitWidth()); |
| 1110 | } | 1124 | } |
| 1111 | | 1125 | |
| 1112 | fn ptrType(self: *DeclGen, child_ty: Type, storage_class: StorageClass) !CacheRef { | 1126 | /// Generate a union type, optionally with a known field. If the tag alignment is greater |
| 1113 | const key = .{ child_ty.toIntern(), storage_class }; | 1127 | /// than that of the payload, a regular union (non-packed, with both tag and payload), will |
| 1114 | const entry = try self.wip_pointers.getOrPut(self.gpa, key); | 1128 | /// be generated as follows: |
| 1115 | if (entry.found_existing) { | 1129 | /// If the active field is known: |
| 1116 | const fwd_ref = entry.value_ptr.*; | | |
| 1117 | try self.spv.cache.recursive_ptrs.put(self.spv.gpa, fwd_ref, {}); | | |
| 1118 | return fwd_ref; | | |
| 1119 | } | | |
| 1120 | | | |
| 1121 | const fwd_ref = try self.spv.resolve(.{ .fwd_ptr_type = .{ | | |
| 1122 | .zig_child_type = child_ty.toIntern(), | | |
| 1123 | .storage_class = storage_class, | | |
| 1124 | } }); | | |
| 1125 | entry.value_ptr.* = fwd_ref; | | |
| 1126 | | | |
| 1127 | const child_ty_ref = try self.resolveType(child_ty, .indirect); | | |
| 1128 | _ = try self.spv.resolve(.{ .ptr_type = .{ | | |
| 1129 | .storage_class = storage_class, | | |
| 1130 | .child_type = child_ty_ref, | | |
| 1131 | .fwd = fwd_ref, | | |
| 1132 | } }); | | |
| 1133 | | | |
| 1134 | assert(self.wip_pointers.remove(key)); | | |
| 1135 | | | |
| 1136 | return fwd_ref; | | |
| 1137 | } | | |
| 1138 | | | |
| 1139 | /// Generate a union type. Union types are always generated with the | | |
| 1140 | /// most aligned field active. If the tag alignment is greater | | |
| 1141 | /// than that of the payload, a regular union (non-packed, with both tag and | | |
| 1142 | /// payload), will be generated as follows: | | |
| 1143 | /// struct { | 1130 | /// struct { |
| 1144 | /// tag: TagType, | 1131 | /// tag: TagType, |
| 1145 | /// payload: MostAlignedFieldType, | 1132 | /// payload: ActivePayloadType, |
| 1146 | /// payload_padding: [payload_size - @sizeOf(MostAlignedFieldType)]u8, | 1133 | /// payload_padding: [payload_size - @sizeOf(ActivePayloadType)]u8, |
| 1147 | /// padding: [padding_size]u8, | 1134 | /// padding: [padding_size]u8, |
| 1148 | /// } | 1135 | /// } |
| 1149 | /// If the payload alignment is greater than that of the tag: | 1136 | /// If the payload alignment is greater than that of the tag: |
| 1150 | /// struct { | 1137 | /// struct { |
| 1151 | /// payload: MostAlignedFieldType, | 1138 | /// payload: ActivePayloadType, |
| 1152 | /// payload_padding: [payload_size - @sizeOf(MostAlignedFieldType)]u8, | 1139 | /// payload_padding: [payload_size - @sizeOf(ActivePayloadType)]u8, |
| 1153 | /// tag: TagType, | 1140 | /// tag: TagType, |
| 1154 | /// padding: [padding_size]u8, | 1141 | /// padding: [padding_size]u8, |
| 1155 | /// } | 1142 | /// } |
| | 1143 | /// If the active payload is unknown, it will default back to the most aligned field. This is |
| | 1144 | /// to make sure that the overal struct has the correct alignment in spir-v. |
| 1156 | /// If any of the fields' size is 0, it will be omitted. | 1145 | /// If any of the fields' size is 0, it will be omitted. |
| 1157 | fn resolveUnionType(self: *DeclGen, ty: Type) !CacheRef { | 1146 | /// NOTE: When the active field is set to something other than the most aligned field, the |
| | 1147 | /// resulting struct will be *underaligned*. |
| | 1148 | fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef { |
| 1158 | const mod = self.module; | 1149 | const mod = self.module; |
| 1159 | const ip = &mod.intern_pool; | 1150 | const ip = &mod.intern_pool; |
| 1160 | const union_obj = mod.typeToUnion(ty).?; | 1151 | const union_obj = mod.typeToUnion(ty).?; |
| ... | @@ -1163,13 +1154,17 @@ const DeclGen = struct { | ... | @@ -1163,13 +1154,17 @@ const DeclGen = struct { |
| 1163 | return self.todo("packed union types", .{}); | 1154 | return self.todo("packed union types", .{}); |
| 1164 | } | 1155 | } |
| 1165 | | 1156 | |
| 1166 | const layout = self.unionLayout(ty); | 1157 | const layout = self.unionLayout(ty, maybe_active_field); |
| 1167 | if (!layout.has_payload) { | 1158 | |
| | 1159 | if (layout.payload_size == 0) { |
| 1168 | // No payload, so represent this as just the tag type. | 1160 | // No payload, so represent this as just the tag type. |
| 1169 | return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); | 1161 | return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); |
| 1170 | } | 1162 | } |
| 1171 | | 1163 | |
| 1172 | if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; | 1164 | // TODO: We need to add the active field to the key, somehow. |
| | 1165 | if (maybe_active_field == null) { |
| | 1166 | if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; |
| | 1167 | } |
| 1173 | | 1168 | |
| 1174 | var member_types: [4]CacheRef = undefined; | 1169 | var member_types: [4]CacheRef = undefined; |
| 1175 | var member_names: [4]CacheString = undefined; | 1170 | var member_names: [4]CacheString = undefined; |
| ... | @@ -1182,10 +1177,10 @@ const DeclGen = struct { | ... | @@ -1182,10 +1177,10 @@ const DeclGen = struct { |
| 1182 | member_names[layout.tag_index] = try self.spv.resolveString("(tag)"); | 1177 | member_names[layout.tag_index] = try self.spv.resolveString("(tag)"); |
| 1183 | } | 1178 | } |
| 1184 | | 1179 | |
| 1185 | if (layout.payload_size != 0) { | 1180 | if (layout.active_field_size != 0) { |
| 1186 | const payload_ty_ref = try self.resolveType(layout.payload_ty, .indirect); | 1181 | const active_payload_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); |
| 1187 | member_types[layout.payload_index] = payload_ty_ref; | 1182 | member_types[layout.active_field_index] = active_payload_ty_ref; |
| 1188 | member_names[layout.payload_index] = try self.spv.resolveString("(payload)"); | 1183 | member_names[layout.active_field_index] = try self.spv.resolveString("(payload)"); |
| 1189 | } | 1184 | } |
| 1190 | | 1185 | |
| 1191 | if (layout.payload_padding_size != 0) { | 1186 | if (layout.payload_padding_size != 0) { |
| ... | @@ -1206,7 +1201,9 @@ const DeclGen = struct { | ... | @@ -1206,7 +1201,9 @@ const DeclGen = struct { |
| 1206 | .member_names = member_names[0..layout.total_fields], | 1201 | .member_names = member_names[0..layout.total_fields], |
| 1207 | } }); | 1202 | } }); |
| 1208 | | 1203 | |
| 1209 | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); | 1204 | if (maybe_active_field == null) { |
| | 1205 | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); |
| | 1206 | } |
| 1210 | return ty_ref; | 1207 | return ty_ref; |
| 1211 | } | 1208 | } |
| 1212 | | 1209 | |
| ... | @@ -1354,12 +1351,12 @@ const DeclGen = struct { | ... | @@ -1354,12 +1351,12 @@ const DeclGen = struct { |
| 1354 | .Pointer => { | 1351 | .Pointer => { |
| 1355 | const ptr_info = ty.ptrInfo(mod); | 1352 | const ptr_info = ty.ptrInfo(mod); |
| 1356 | | 1353 | |
| 1357 | // Note: Don't cache this pointer type, it would mess up the recursive pointer functionality | | |
| 1358 | // in ptrType()! | | |
| 1359 | | | |
| 1360 | const storage_class = spvStorageClass(ptr_info.flags.address_space); | 1354 | const storage_class = spvStorageClass(ptr_info.flags.address_space); |
| 1361 | const ptr_ty_ref = try self.ptrType(ptr_info.child.toType(), storage_class); | 1355 | const child_ty_ref = try self.resolveType(ptr_info.child.toType(), .indirect); |
| 1362 | | 1356 | const ptr_ty_ref = try self.spv.resolve(.{ .ptr_type = .{ |
| | 1357 | .storage_class = storage_class, |
| | 1358 | .child_type = child_ty_ref, |
| | 1359 | } }); |
| 1363 | if (ptr_info.flags.size != .Slice) { | 1360 | if (ptr_info.flags.size != .Slice) { |
| 1364 | return ptr_ty_ref; | 1361 | return ptr_ty_ref; |
| 1365 | } | 1362 | } |
| ... | @@ -1474,7 +1471,7 @@ const DeclGen = struct { | ... | @@ -1474,7 +1471,7 @@ const DeclGen = struct { |
| 1474 | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); | 1471 | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); |
| 1475 | return ty_ref; | 1472 | return ty_ref; |
| 1476 | }, | 1473 | }, |
| 1477 | .Union => return try self.resolveUnionType(ty), | 1474 | .Union => return try self.resolveUnionType(ty, null), |
| 1478 | .ErrorSet => return try self.intType(.unsigned, 16), | 1475 | .ErrorSet => return try self.intType(.unsigned, 16), |
| 1479 | .ErrorUnion => { | 1476 | .ErrorUnion => { |
| 1480 | const payload_ty = ty.errorUnionPayload(mod); | 1477 | const payload_ty = ty.errorUnionPayload(mod); |
| ... | @@ -1588,16 +1585,14 @@ const DeclGen = struct { | ... | @@ -1588,16 +1585,14 @@ const DeclGen = struct { |
| 1588 | } | 1585 | } |
| 1589 | | 1586 | |
| 1590 | const UnionLayout = struct { | 1587 | const UnionLayout = struct { |
| 1591 | /// If false, this union is represented | 1588 | active_field: u32, |
| 1592 | /// by only an integer of the tag type. | 1589 | active_field_ty: Type, |
| 1593 | has_payload: bool, | 1590 | payload_size: u32, |
| | 1591 | |
| 1594 | tag_size: u32, | 1592 | tag_size: u32, |
| 1595 | tag_index: u32, | 1593 | tag_index: u32, |
| 1596 | /// Note: This is the size of the payload type itself, NOT the size of the ENTIRE payload. | 1594 | active_field_size: u32, |
| 1597 | /// Use `has_payload` instead!! | 1595 | active_field_index: u32, |
| 1598 | payload_ty: Type, | | |
| 1599 | payload_size: u32, | | |
| 1600 | payload_index: u32, | | |
| 1601 | payload_padding_size: u32, | 1596 | payload_padding_size: u32, |
| 1602 | payload_padding_index: u32, | 1597 | payload_padding_index: u32, |
| 1603 | padding_size: u32, | 1598 | padding_size: u32, |
| ... | @@ -1605,19 +1600,23 @@ const DeclGen = struct { | ... | @@ -1605,19 +1600,23 @@ const DeclGen = struct { |
| 1605 | total_fields: u32, | 1600 | total_fields: u32, |
| 1606 | }; | 1601 | }; |
| 1607 | | 1602 | |
| 1608 | fn unionLayout(self: *DeclGen, ty: Type) UnionLayout { | 1603 | fn unionLayout(self: *DeclGen, ty: Type, maybe_active_field: ?usize) UnionLayout { |
| 1609 | const mod = self.module; | 1604 | const mod = self.module; |
| 1610 | const ip = &mod.intern_pool; | 1605 | const ip = &mod.intern_pool; |
| 1611 | const layout = ty.unionGetLayout(self.module); | 1606 | const layout = ty.unionGetLayout(self.module); |
| 1612 | const union_obj = mod.typeToUnion(ty).?; | 1607 | const union_obj = mod.typeToUnion(ty).?; |
| 1613 | | 1608 | |
| | 1609 | const active_field = maybe_active_field orelse layout.most_aligned_field; |
| | 1610 | const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); |
| | 1611 | |
| 1614 | var union_layout = UnionLayout{ | 1612 | var union_layout = UnionLayout{ |
| 1615 | .has_payload = layout.payload_size != 0, | 1613 | .active_field = @intCast(active_field), |
| | 1614 | .active_field_ty = active_field_ty, |
| | 1615 | .payload_size = @intCast(layout.payload_size), |
| 1616 | .tag_size = @intCast(layout.tag_size), | 1616 | .tag_size = @intCast(layout.tag_size), |
| 1617 | .tag_index = undefined, | 1617 | .tag_index = undefined, |
| 1618 | .payload_ty = undefined, | 1618 | .active_field_size = undefined, |
| 1619 | .payload_size = undefined, | 1619 | .active_field_index = undefined, |
| 1620 | .payload_index = undefined, | | |
| 1621 | .payload_padding_size = undefined, | 1620 | .payload_padding_size = undefined, |
| 1622 | .payload_padding_index = undefined, | 1621 | .payload_padding_index = undefined, |
| 1623 | .padding_size = @intCast(layout.padding), | 1622 | .padding_size = @intCast(layout.padding), |
| ... | @@ -1625,16 +1624,11 @@ const DeclGen = struct { | ... | @@ -1625,16 +1624,11 @@ const DeclGen = struct { |
| 1625 | .total_fields = undefined, | 1624 | .total_fields = undefined, |
| 1626 | }; | 1625 | }; |
| 1627 | | 1626 | |
| 1628 | if (union_layout.has_payload) { | 1627 | union_layout.active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 1629 | const most_aligned_field = layout.most_aligned_field; | 1628 | @intCast(active_field_ty.abiSize(mod)) |
| 1630 | const most_aligned_field_ty = union_obj.field_types.get(ip)[most_aligned_field].toType(); | 1629 | else |
| 1631 | union_layout.payload_ty = most_aligned_field_ty; | 1630 | 0; |
| 1632 | union_layout.payload_size = @intCast(most_aligned_field_ty.abiSize(mod)); | 1631 | union_layout.payload_padding_size = @intCast(layout.payload_size - union_layout.active_field_size); |
| 1633 | } else { | | |
| 1634 | union_layout.payload_size = 0; | | |
| 1635 | } | | |
| 1636 | | | |
| 1637 | union_layout.payload_padding_size = @intCast(layout.payload_size - union_layout.payload_size); | | |
| 1638 | | 1632 | |
| 1639 | const tag_first = layout.tag_align.compare(.gte, layout.payload_align); | 1633 | const tag_first = layout.tag_align.compare(.gte, layout.payload_align); |
| 1640 | var field_index: u32 = 0; | 1634 | var field_index: u32 = 0; |
| ... | @@ -1644,8 +1638,8 @@ const DeclGen = struct { | ... | @@ -1644,8 +1638,8 @@ const DeclGen = struct { |
| 1644 | field_index += 1; | 1638 | field_index += 1; |
| 1645 | } | 1639 | } |
| 1646 | | 1640 | |
| 1647 | if (union_layout.payload_size != 0) { | 1641 | if (union_layout.active_field_size != 0) { |
| 1648 | union_layout.payload_index = field_index; | 1642 | union_layout.active_field_index = field_index; |
| 1649 | field_index += 1; | 1643 | field_index += 1; |
| 1650 | } | 1644 | } |
| 1651 | | 1645 | |
| ... | @@ -1689,7 +1683,7 @@ const DeclGen = struct { | ... | @@ -1689,7 +1683,7 @@ const DeclGen = struct { |
| 1689 | /// the name of an error in the text executor. | 1683 | /// the name of an error in the text executor. |
| 1690 | fn generateTestEntryPoint(self: *DeclGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void { | 1684 | fn generateTestEntryPoint(self: *DeclGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void { |
| 1691 | const anyerror_ty_ref = try self.resolveType(Type.anyerror, .direct); | 1685 | const anyerror_ty_ref = try self.resolveType(Type.anyerror, .direct); |
| 1692 | const ptr_anyerror_ty_ref = try self.ptrType(Type.anyerror, .CrossWorkgroup); | 1686 | const ptr_anyerror_ty_ref = try self.spv.ptrType(anyerror_ty_ref, .CrossWorkgroup); |
| 1693 | const void_ty_ref = try self.resolveType(Type.void, .direct); | 1687 | const void_ty_ref = try self.resolveType(Type.void, .direct); |
| 1694 | | 1688 | |
| 1695 | const kernel_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{ | 1689 | const kernel_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{ |
| ... | @@ -1724,7 +1718,6 @@ const DeclGen = struct { | ... | @@ -1724,7 +1718,6 @@ const DeclGen = struct { |
| 1724 | .id_result = error_id, | 1718 | .id_result = error_id, |
| 1725 | .function = test_id, | 1719 | .function = test_id, |
| 1726 | }); | 1720 | }); |
| 1727 | // Note: Convert to direct not required. | | |
| 1728 | try section.emit(self.spv.gpa, .OpStore, .{ | 1721 | try section.emit(self.spv.gpa, .OpStore, .{ |
| 1729 | .pointer = p_error_id, | 1722 | .pointer = p_error_id, |
| 1730 | .object = error_id, | 1723 | .object = error_id, |
| ... | @@ -1829,7 +1822,8 @@ const DeclGen = struct { | ... | @@ -1829,7 +1822,8 @@ const DeclGen = struct { |
| 1829 | else => final_storage_class, | 1822 | else => final_storage_class, |
| 1830 | }; | 1823 | }; |
| 1831 | | 1824 | |
| 1832 | const ptr_ty_ref = try self.ptrType(decl.ty, actual_storage_class); | 1825 | const ty_ref = try self.resolveType(decl.ty, .indirect); |
| | 1826 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, actual_storage_class); |
| 1833 | | 1827 | |
| 1834 | const begin = self.spv.beginGlobal(); | 1828 | const begin = self.spv.beginGlobal(); |
| 1835 | try self.spv.globals.section.emit(self.spv.gpa, .OpVariable, .{ | 1829 | try self.spv.globals.section.emit(self.spv.gpa, .OpVariable, .{ |
| ... | @@ -1934,15 +1928,11 @@ const DeclGen = struct { | ... | @@ -1934,15 +1928,11 @@ const DeclGen = struct { |
| 1934 | return try self.convertToDirect(result_ty, result_id); | 1928 | return try self.convertToDirect(result_ty, result_id); |
| 1935 | } | 1929 | } |
| 1936 | | 1930 | |
| 1937 | const MemoryOptions = struct { | 1931 | fn load(self: *DeclGen, value_ty: Type, ptr_id: IdRef, is_volatile: bool) !IdRef { |
| 1938 | is_volatile: bool = false, | | |
| 1939 | }; | | |
| 1940 | | | |
| 1941 | fn load(self: *DeclGen, value_ty: Type, ptr_id: IdRef, options: MemoryOptions) !IdRef { | | |
| 1942 | const indirect_value_ty_ref = try self.resolveType(value_ty, .indirect); | 1932 | const indirect_value_ty_ref = try self.resolveType(value_ty, .indirect); |
| 1943 | const result_id = self.spv.allocId(); | 1933 | const result_id = self.spv.allocId(); |
| 1944 | const access = spec.MemoryAccess.Extended{ | 1934 | const access = spec.MemoryAccess.Extended{ |
| 1945 | .Volatile = options.is_volatile, | 1935 | .Volatile = is_volatile, |
| 1946 | }; | 1936 | }; |
| 1947 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ | 1937 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 1948 | .id_result_type = self.typeId(indirect_value_ty_ref), | 1938 | .id_result_type = self.typeId(indirect_value_ty_ref), |
| ... | @@ -1953,10 +1943,10 @@ const DeclGen = struct { | ... | @@ -1953,10 +1943,10 @@ const DeclGen = struct { |
| 1953 | return try self.convertToDirect(value_ty, result_id); | 1943 | return try self.convertToDirect(value_ty, result_id); |
| 1954 | } | 1944 | } |
| 1955 | | 1945 | |
| 1956 | fn store(self: *DeclGen, value_ty: Type, ptr_id: IdRef, value_id: IdRef, options: MemoryOptions) !void { | 1946 | fn store(self: *DeclGen, value_ty: Type, ptr_id: IdRef, value_id: IdRef, is_volatile: bool) !void { |
| 1957 | const indirect_value_id = try self.convertToIndirect(value_ty, value_id); | 1947 | const indirect_value_id = try self.convertToIndirect(value_ty, value_id); |
| 1958 | const access = spec.MemoryAccess.Extended{ | 1948 | const access = spec.MemoryAccess.Extended{ |
| 1959 | .Volatile = options.is_volatile, | 1949 | .Volatile = is_volatile, |
| 1960 | }; | 1950 | }; |
| 1961 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 1951 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 1962 | .pointer = ptr_id, | 1952 | .pointer = ptr_id, |
| ... | @@ -2128,7 +2118,9 @@ const DeclGen = struct { | ... | @@ -2128,7 +2118,9 @@ const DeclGen = struct { |
| 2128 | constituent.* = try self.convertToIndirect(child_ty, result_id); | 2118 | constituent.* = try self.convertToIndirect(child_ty, result_id); |
| 2129 | } | 2119 | } |
| 2130 | | 2120 | |
| 2131 | return try self.constructArray(ty, constituents); | 2121 | const result_ty = try self.resolveType(child_ty, .indirect); |
| | 2122 | const result_ty_ref = try self.spv.arrayType(vector_len, result_ty); |
| | 2123 | return try self.constructArray(result_ty_ref, constituents); |
| 2132 | } | 2124 | } |
| 2133 | | 2125 | |
| 2134 | const result_id = self.spv.allocId(); | 2126 | const result_id = self.spv.allocId(); |
| ... | @@ -2189,7 +2181,7 @@ const DeclGen = struct { | ... | @@ -2189,7 +2181,7 @@ const DeclGen = struct { |
| 2189 | | 2181 | |
| 2190 | const info = try self.arithmeticTypeInfo(result_ty); | 2182 | const info = try self.arithmeticTypeInfo(result_ty); |
| 2191 | // TODO: Use fmin for OpenCL | 2183 | // TODO: Use fmin for OpenCL |
| 2192 | const cmp_id = try self.cmp(op, Type.bool, result_ty, lhs_id, rhs_id); | 2184 | const cmp_id = try self.cmp(op, result_ty, lhs_id, rhs_id); |
| 2193 | const selection_id = switch (info.class) { | 2185 | const selection_id = switch (info.class) { |
| 2194 | .float => blk: { | 2186 | .float => blk: { |
| 2195 | // cmp uses OpFOrd. When we have 0 [<>] nan this returns false, | 2187 | // cmp uses OpFOrd. When we have 0 [<>] nan this returns false, |
| ... | @@ -2324,7 +2316,7 @@ const DeclGen = struct { | ... | @@ -2324,7 +2316,7 @@ const DeclGen = struct { |
| 2324 | constituent.* = try self.arithOp(child_ty, lhs_index_id, rhs_index_id, fop, sop, uop, modular); | 2316 | constituent.* = try self.arithOp(child_ty, lhs_index_id, rhs_index_id, fop, sop, uop, modular); |
| 2325 | } | 2317 | } |
| 2326 | | 2318 | |
| 2327 | return self.constructArray(ty, constituents); | 2319 | return self.constructArray(result_ty_ref, constituents); |
| 2328 | } | 2320 | } |
| 2329 | | 2321 | |
| 2330 | // Binary operations are generally applicable to both scalar and vector operations | 2322 | // Binary operations are generally applicable to both scalar and vector operations |
| ... | @@ -2480,11 +2472,11 @@ const DeclGen = struct { | ... | @@ -2480,11 +2472,11 @@ const DeclGen = struct { |
| 2480 | // Construct the struct that Zig wants as result. | 2472 | // Construct the struct that Zig wants as result. |
| 2481 | // The value should already be the correct type. | 2473 | // The value should already be the correct type. |
| 2482 | const ov_id = try self.intFromBool(ov_ty_ref, overflowed_id); | 2474 | const ov_id = try self.intFromBool(ov_ty_ref, overflowed_id); |
| 2483 | return try self.constructStruct( | 2475 | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 2484 | result_ty, | 2476 | return try self.constructStruct(result_ty_ref, &.{ |
| 2485 | &.{ operand_ty, ov_ty }, | 2477 | value_id, |
| 2486 | &.{ value_id, ov_id }, | 2478 | ov_id, |
| 2487 | ); | 2479 | }); |
| 2488 | } | 2480 | } |
| 2489 | | 2481 | |
| 2490 | fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2482 | fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -2642,7 +2634,6 @@ const DeclGen = struct { | ... | @@ -2642,7 +2634,6 @@ const DeclGen = struct { |
| 2642 | fn cmp( | 2634 | fn cmp( |
| 2643 | self: *DeclGen, | 2635 | self: *DeclGen, |
| 2644 | op: std.math.CompareOperator, | 2636 | op: std.math.CompareOperator, |
| 2645 | result_ty: Type, | | |
| 2646 | ty: Type, | 2637 | ty: Type, |
| 2647 | lhs_id: IdRef, | 2638 | lhs_id: IdRef, |
| 2648 | rhs_id: IdRef, | 2639 | rhs_id: IdRef, |
| ... | @@ -2683,7 +2674,7 @@ const DeclGen = struct { | ... | @@ -2683,7 +2674,7 @@ const DeclGen = struct { |
| 2683 | if (ty.optionalReprIsPayload(mod)) { | 2674 | if (ty.optionalReprIsPayload(mod)) { |
| 2684 | assert(payload_ty.hasRuntimeBitsIgnoreComptime(mod)); | 2675 | assert(payload_ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 2685 | assert(!payload_ty.isSlice(mod)); | 2676 | assert(!payload_ty.isSlice(mod)); |
| 2686 | return self.cmp(op, Type.bool, payload_ty, lhs_id, rhs_id); | 2677 | return self.cmp(op, payload_ty, lhs_id, rhs_id); |
| 2687 | } | 2678 | } |
| 2688 | | 2679 | |
| 2689 | const lhs_valid_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) | 2680 | const lhs_valid_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| ... | @@ -2696,7 +2687,7 @@ const DeclGen = struct { | ... | @@ -2696,7 +2687,7 @@ const DeclGen = struct { |
| 2696 | else | 2687 | else |
| 2697 | try self.convertToDirect(Type.bool, rhs_id); | 2688 | try self.convertToDirect(Type.bool, rhs_id); |
| 2698 | | 2689 | |
| 2699 | const valid_cmp_id = try self.cmp(op, Type.bool, Type.bool, lhs_valid_id, rhs_valid_id); | 2690 | const valid_cmp_id = try self.cmp(op, Type.bool, lhs_valid_id, rhs_valid_id); |
| 2700 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 2691 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2701 | return valid_cmp_id; | 2692 | return valid_cmp_id; |
| 2702 | } | 2693 | } |
| ... | @@ -2707,7 +2698,7 @@ const DeclGen = struct { | ... | @@ -2707,7 +2698,7 @@ const DeclGen = struct { |
| 2707 | const lhs_pl_id = try self.extractField(payload_ty, lhs_id, 0); | 2698 | const lhs_pl_id = try self.extractField(payload_ty, lhs_id, 0); |
| 2708 | const rhs_pl_id = try self.extractField(payload_ty, rhs_id, 0); | 2699 | const rhs_pl_id = try self.extractField(payload_ty, rhs_id, 0); |
| 2709 | | 2700 | |
| 2710 | const pl_cmp_id = try self.cmp(op, Type.bool, payload_ty, lhs_pl_id, rhs_pl_id); | 2701 | const pl_cmp_id = try self.cmp(op, payload_ty, lhs_pl_id, rhs_pl_id); |
| 2711 | | 2702 | |
| 2712 | // op == .eq => lhs_valid == rhs_valid && lhs_pl == rhs_pl | 2703 | // op == .eq => lhs_valid == rhs_valid && lhs_pl == rhs_pl |
| 2713 | // op == .neq => lhs_valid != rhs_valid || lhs_pl != rhs_pl | 2704 | // op == .neq => lhs_valid != rhs_valid || lhs_pl != rhs_pl |
| ... | @@ -2729,6 +2720,7 @@ const DeclGen = struct { | ... | @@ -2729,6 +2720,7 @@ const DeclGen = struct { |
| 2729 | .Vector => { | 2720 | .Vector => { |
| 2730 | const child_ty = ty.childType(mod); | 2721 | const child_ty = ty.childType(mod); |
| 2731 | const vector_len = ty.vectorLen(mod); | 2722 | const vector_len = ty.vectorLen(mod); |
| | 2723 | const bool_ty_ref_indirect = try self.resolveType(Type.bool, .indirect); |
| 2732 | | 2724 | |
| 2733 | var constituents = try self.gpa.alloc(IdRef, vector_len); | 2725 | var constituents = try self.gpa.alloc(IdRef, vector_len); |
| 2734 | defer self.gpa.free(constituents); | 2726 | defer self.gpa.free(constituents); |
| ... | @@ -2736,11 +2728,12 @@ const DeclGen = struct { | ... | @@ -2736,11 +2728,12 @@ const DeclGen = struct { |
| 2736 | for (constituents, 0..) |*constituent, i| { | 2728 | for (constituents, 0..) |*constituent, i| { |
| 2737 | const lhs_index_id = try self.extractField(child_ty, cmp_lhs_id, @intCast(i)); | 2729 | const lhs_index_id = try self.extractField(child_ty, cmp_lhs_id, @intCast(i)); |
| 2738 | const rhs_index_id = try self.extractField(child_ty, cmp_rhs_id, @intCast(i)); | 2730 | const rhs_index_id = try self.extractField(child_ty, cmp_rhs_id, @intCast(i)); |
| 2739 | const result_id = try self.cmp(op, Type.bool, child_ty, lhs_index_id, rhs_index_id); | 2731 | const result_id = try self.cmp(op, child_ty, lhs_index_id, rhs_index_id); |
| 2740 | constituent.* = try self.convertToIndirect(Type.bool, result_id); | 2732 | constituent.* = try self.convertToIndirect(Type.bool, result_id); |
| 2741 | } | 2733 | } |
| 2742 | | 2734 | |
| 2743 | return try self.constructArray(result_ty, constituents); | 2735 | const result_ty_ref = try self.spv.arrayType(vector_len, bool_ty_ref_indirect); |
| | 2736 | return try self.constructArray(result_ty_ref, constituents); |
| 2744 | }, | 2737 | }, |
| 2745 | else => unreachable, | 2738 | else => unreachable, |
| 2746 | }; | 2739 | }; |
| ... | @@ -2813,9 +2806,8 @@ const DeclGen = struct { | ... | @@ -2813,9 +2806,8 @@ const DeclGen = struct { |
| 2813 | const lhs_id = try self.resolve(bin_op.lhs); | 2806 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2814 | const rhs_id = try self.resolve(bin_op.rhs); | 2807 | const rhs_id = try self.resolve(bin_op.rhs); |
| 2815 | const ty = self.typeOf(bin_op.lhs); | 2808 | const ty = self.typeOf(bin_op.lhs); |
| 2816 | const result_ty = self.typeOfIndex(inst); | | |
| 2817 | | 2809 | |
| 2818 | return try self.cmp(op, result_ty, ty, lhs_id, rhs_id); | 2810 | return try self.cmp(op, ty, lhs_id, rhs_id); |
| 2819 | } | 2811 | } |
| 2820 | | 2812 | |
| 2821 | fn airVectorCmp(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2813 | fn airVectorCmp(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -2827,9 +2819,8 @@ const DeclGen = struct { | ... | @@ -2827,9 +2819,8 @@ const DeclGen = struct { |
| 2827 | const rhs_id = try self.resolve(vec_cmp.rhs); | 2819 | const rhs_id = try self.resolve(vec_cmp.rhs); |
| 2828 | const op = vec_cmp.compareOperator(); | 2820 | const op = vec_cmp.compareOperator(); |
| 2829 | const ty = self.typeOf(vec_cmp.lhs); | 2821 | const ty = self.typeOf(vec_cmp.lhs); |
| 2830 | const result_ty = self.typeOfIndex(inst); | | |
| 2831 | | 2822 | |
| 2832 | return try self.cmp(op, result_ty, ty, lhs_id, rhs_id); | 2823 | return try self.cmp(op, ty, lhs_id, rhs_id); |
| 2833 | } | 2824 | } |
| 2834 | | 2825 | |
| 2835 | fn bitCast( | 2826 | fn bitCast( |
| ... | @@ -2874,17 +2865,23 @@ const DeclGen = struct { | ... | @@ -2874,17 +2865,23 @@ const DeclGen = struct { |
| 2874 | return result_id; | 2865 | return result_id; |
| 2875 | } | 2866 | } |
| 2876 | | 2867 | |
| 2877 | const dst_ptr_ty_ref = try self.ptrType(dst_ty, .Function); | 2868 | const src_ptr_ty_ref = try self.spv.ptrType(src_ty_ref, .Function); |
| | 2869 | const dst_ptr_ty_ref = try self.spv.ptrType(dst_ty_ref, .Function); |
| 2878 | | 2870 | |
| 2879 | const tmp_id = try self.alloc(src_ty, .{ .storage_class = .Function }); | 2871 | const tmp_id = self.spv.allocId(); |
| 2880 | try self.store(src_ty, tmp_id, src_id, .{}); | 2872 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| | 2873 | .id_result_type = self.typeId(src_ptr_ty_ref), |
| | 2874 | .id_result = tmp_id, |
| | 2875 | .storage_class = .Function, |
| | 2876 | }); |
| | 2877 | try self.store(src_ty, tmp_id, src_id, false); |
| 2881 | const casted_ptr_id = self.spv.allocId(); | 2878 | const casted_ptr_id = self.spv.allocId(); |
| 2882 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ | 2879 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 2883 | .id_result_type = self.typeId(dst_ptr_ty_ref), | 2880 | .id_result_type = self.typeId(dst_ptr_ty_ref), |
| 2884 | .id_result = casted_ptr_id, | 2881 | .id_result = casted_ptr_id, |
| 2885 | .operand = tmp_id, | 2882 | .operand = tmp_id, |
| 2886 | }); | 2883 | }); |
| 2887 | return try self.load(dst_ty, casted_ptr_id, .{}); | 2884 | return try self.load(dst_ty, casted_ptr_id, false); |
| 2888 | } | 2885 | } |
| 2889 | | 2886 | |
| 2890 | fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2887 | fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3063,6 +3060,7 @@ const DeclGen = struct { | ... | @@ -3063,6 +3060,7 @@ const DeclGen = struct { |
| 3063 | const elem_ptr_ty = slice_ty.slicePtrFieldType(mod); | 3060 | const elem_ptr_ty = slice_ty.slicePtrFieldType(mod); |
| 3064 | | 3061 | |
| 3065 | const elem_ptr_ty_ref = try self.resolveType(elem_ptr_ty, .direct); | 3062 | const elem_ptr_ty_ref = try self.resolveType(elem_ptr_ty, .direct); |
| | 3063 | const slice_ty_ref = try self.resolveType(slice_ty, .direct); |
| 3066 | const size_ty_ref = try self.sizeType(); | 3064 | const size_ty_ref = try self.sizeType(); |
| 3067 | | 3065 | |
| 3068 | const array_ptr_id = try self.resolve(ty_op.operand); | 3066 | const array_ptr_id = try self.resolve(ty_op.operand); |
| ... | @@ -3075,11 +3073,7 @@ const DeclGen = struct { | ... | @@ -3075,11 +3073,7 @@ const DeclGen = struct { |
| 3075 | // Convert the pointer-to-array to a pointer to the first element. | 3073 | // Convert the pointer-to-array to a pointer to the first element. |
| 3076 | try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0}); | 3074 | try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0}); |
| 3077 | | 3075 | |
| 3078 | return try self.constructStruct( | 3076 | return try self.constructStruct(slice_ty_ref, &.{ elem_ptr_id, len_id }); |
| 3079 | slice_ty, | | |
| 3080 | &.{ elem_ptr_ty, Type.usize }, | | |
| 3081 | &.{ elem_ptr_id, len_id }, | | |
| 3082 | ); | | |
| 3083 | } | 3077 | } |
| 3084 | | 3078 | |
| 3085 | fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3079 | fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3089,16 +3083,13 @@ const DeclGen = struct { | ... | @@ -3089,16 +3083,13 @@ const DeclGen = struct { |
| 3089 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 3083 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3090 | const ptr_id = try self.resolve(bin_op.lhs); | 3084 | const ptr_id = try self.resolve(bin_op.lhs); |
| 3091 | const len_id = try self.resolve(bin_op.rhs); | 3085 | const len_id = try self.resolve(bin_op.rhs); |
| 3092 | const ptr_ty = self.typeOf(bin_op.lhs); | | |
| 3093 | const slice_ty = self.typeOfIndex(inst); | 3086 | const slice_ty = self.typeOfIndex(inst); |
| | 3087 | const slice_ty_ref = try self.resolveType(slice_ty, .direct); |
| 3094 | | 3088 | |
| 3095 | // Note: Types should not need to be converted to direct, these types | 3089 | return try self.constructStruct(slice_ty_ref, &.{ |
| 3096 | // dont need to be converted. | 3090 | ptr_id, // Note: Type should not need to be converted to direct. |
| 3097 | return try self.constructStruct( | 3091 | len_id, // Note: Type should not need to be converted to direct. |
| 3098 | slice_ty, | 3092 | }); |
| 3099 | &.{ ptr_ty, Type.usize }, | | |
| 3100 | &.{ ptr_id, len_id }, | | |
| 3101 | ); | | |
| 3102 | } | 3093 | } |
| 3103 | | 3094 | |
| 3104 | fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3095 | fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3108,6 +3099,7 @@ const DeclGen = struct { | ... | @@ -3108,6 +3099,7 @@ const DeclGen = struct { |
| 3108 | const ip = &mod.intern_pool; | 3099 | const ip = &mod.intern_pool; |
| 3109 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 3100 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3110 | const result_ty = self.typeOfIndex(inst); | 3101 | const result_ty = self.typeOfIndex(inst); |
| | 3102 | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 3111 | const len: usize = @intCast(result_ty.arrayLen(mod)); | 3103 | const len: usize = @intCast(result_ty.arrayLen(mod)); |
| 3112 | const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]); | 3104 | const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]); |
| 3113 | | 3105 | |
| ... | @@ -3119,8 +3111,6 @@ const DeclGen = struct { | ... | @@ -3119,8 +3111,6 @@ const DeclGen = struct { |
| 3119 | unreachable; // TODO | 3111 | unreachable; // TODO |
| 3120 | } | 3112 | } |
| 3121 | | 3113 | |
| 3122 | const types = try self.gpa.alloc(Type, elements.len); | | |
| 3123 | defer self.gpa.free(types); | | |
| 3124 | const constituents = try self.gpa.alloc(IdRef, elements.len); | 3114 | const constituents = try self.gpa.alloc(IdRef, elements.len); |
| 3125 | defer self.gpa.free(constituents); | 3115 | defer self.gpa.free(constituents); |
| 3126 | var index: usize = 0; | 3116 | var index: usize = 0; |
| ... | @@ -3132,7 +3122,6 @@ const DeclGen = struct { | ... | @@ -3132,7 +3122,6 @@ const DeclGen = struct { |
| 3132 | assert(field_ty.toType().hasRuntimeBits(mod)); | 3122 | assert(field_ty.toType().hasRuntimeBits(mod)); |
| 3133 | | 3123 | |
| 3134 | const id = try self.resolve(element); | 3124 | const id = try self.resolve(element); |
| 3135 | types[index] = field_ty.toType(); | | |
| 3136 | constituents[index] = try self.convertToIndirect(field_ty.toType(), id); | 3125 | constituents[index] = try self.convertToIndirect(field_ty.toType(), id); |
| 3137 | index += 1; | 3126 | index += 1; |
| 3138 | } | 3127 | } |
| ... | @@ -3146,7 +3135,6 @@ const DeclGen = struct { | ... | @@ -3146,7 +3135,6 @@ const DeclGen = struct { |
| 3146 | assert(field_ty.hasRuntimeBitsIgnoreComptime(mod)); | 3135 | assert(field_ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 3147 | | 3136 | |
| 3148 | const id = try self.resolve(element); | 3137 | const id = try self.resolve(element); |
| 3149 | types[index] = field_ty; | | |
| 3150 | constituents[index] = try self.convertToIndirect(field_ty, id); | 3138 | constituents[index] = try self.convertToIndirect(field_ty, id); |
| 3151 | index += 1; | 3139 | index += 1; |
| 3152 | } | 3140 | } |
| ... | @@ -3154,11 +3142,7 @@ const DeclGen = struct { | ... | @@ -3154,11 +3142,7 @@ const DeclGen = struct { |
| 3154 | else => unreachable, | 3142 | else => unreachable, |
| 3155 | } | 3143 | } |
| 3156 | | 3144 | |
| 3157 | return try self.constructStruct( | 3145 | return try self.constructStruct(result_ty_ref, constituents[0..index]); |
| 3158 | result_ty, | | |
| 3159 | types[0..index], | | |
| 3160 | constituents[0..index], | | |
| 3161 | ); | | |
| 3162 | }, | 3146 | }, |
| 3163 | .Array => { | 3147 | .Array => { |
| 3164 | const array_info = result_ty.arrayInfo(mod); | 3148 | const array_info = result_ty.arrayInfo(mod); |
| ... | @@ -3175,7 +3159,7 @@ const DeclGen = struct { | ... | @@ -3175,7 +3159,7 @@ const DeclGen = struct { |
| 3175 | elem_ids[n_elems - 1] = try self.constant(array_info.elem_type, sentinel_val, .indirect); | 3159 | elem_ids[n_elems - 1] = try self.constant(array_info.elem_type, sentinel_val, .indirect); |
| 3176 | } | 3160 | } |
| 3177 | | 3161 | |
| 3178 | return try self.constructArray(result_ty, elem_ids); | 3162 | return try self.constructArray(result_ty_ref, elem_ids); |
| 3179 | }, | 3163 | }, |
| 3180 | else => unreachable, | 3164 | else => unreachable, |
| 3181 | } | 3165 | } |
| ... | @@ -3260,14 +3244,15 @@ const DeclGen = struct { | ... | @@ -3260,14 +3244,15 @@ const DeclGen = struct { |
| 3260 | | 3244 | |
| 3261 | const slice_ptr = try self.extractField(ptr_ty, slice_id, 0); | 3245 | const slice_ptr = try self.extractField(ptr_ty, slice_id, 0); |
| 3262 | const elem_ptr = try self.ptrAccessChain(ptr_ty_ref, slice_ptr, index_id, &.{}); | 3246 | const elem_ptr = try self.ptrAccessChain(ptr_ty_ref, slice_ptr, index_id, &.{}); |
| 3263 | return try self.load(slice_ty.childType(mod), elem_ptr, .{ .is_volatile = slice_ty.isVolatilePtr(mod) }); | 3247 | return try self.load(slice_ty.childType(mod), elem_ptr, slice_ty.isVolatilePtr(mod)); |
| 3264 | } | 3248 | } |
| 3265 | | 3249 | |
| 3266 | fn ptrElemPtr(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, index_id: IdRef) !IdRef { | 3250 | fn ptrElemPtr(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, index_id: IdRef) !IdRef { |
| 3267 | const mod = self.module; | 3251 | const mod = self.module; |
| 3268 | // Construct new pointer type for the resulting pointer | 3252 | // Construct new pointer type for the resulting pointer |
| 3269 | const elem_ty = ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. | 3253 | const elem_ty = ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. |
| 3270 | const elem_ptr_ty_ref = try self.ptrType(elem_ty, spvStorageClass(ptr_ty.ptrAddressSpace(mod))); | 3254 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); |
| | 3255 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(ptr_ty.ptrAddressSpace(mod))); |
| 3271 | if (ptr_ty.isSinglePointer(mod)) { | 3256 | if (ptr_ty.isSinglePointer(mod)) { |
| 3272 | // Pointer-to-array. In this case, the resulting pointer is not of the same type | 3257 | // Pointer-to-array. In this case, the resulting pointer is not of the same type |
| 3273 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. | 3258 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. |
| ... | @@ -3303,7 +3288,9 @@ const DeclGen = struct { | ... | @@ -3303,7 +3288,9 @@ const DeclGen = struct { |
| 3303 | const mod = self.module; | 3288 | const mod = self.module; |
| 3304 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 3289 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3305 | const array_ty = self.typeOf(bin_op.lhs); | 3290 | const array_ty = self.typeOf(bin_op.lhs); |
| | 3291 | const array_ty_ref = try self.resolveType(array_ty, .direct); |
| 3306 | const elem_ty = array_ty.childType(mod); | 3292 | const elem_ty = array_ty.childType(mod); |
| | 3293 | const elem_ty_ref = try self.resolveType(elem_ty, .indirect); |
| 3307 | const array_id = try self.resolve(bin_op.lhs); | 3294 | const array_id = try self.resolve(bin_op.lhs); |
| 3308 | const index_id = try self.resolve(bin_op.rhs); | 3295 | const index_id = try self.resolve(bin_op.rhs); |
| 3309 | | 3296 | |
| ... | @@ -3311,12 +3298,22 @@ const DeclGen = struct { | ... | @@ -3311,12 +3298,22 @@ const DeclGen = struct { |
| 3311 | // For now, just generate a temporary and use that. | 3298 | // For now, just generate a temporary and use that. |
| 3312 | // TODO: This backend probably also should use isByRef from llvm... | 3299 | // TODO: This backend probably also should use isByRef from llvm... |
| 3313 | | 3300 | |
| 3314 | const elem_ptr_ty_ref = try self.ptrType(elem_ty, .Function); | 3301 | const array_ptr_ty_ref = try self.spv.ptrType(array_ty_ref, .Function); |
| | 3302 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, .Function); |
| | 3303 | |
| | 3304 | const tmp_id = self.spv.allocId(); |
| | 3305 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| | 3306 | .id_result_type = self.typeId(array_ptr_ty_ref), |
| | 3307 | .id_result = tmp_id, |
| | 3308 | .storage_class = .Function, |
| | 3309 | }); |
| | 3310 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| | 3311 | .pointer = tmp_id, |
| | 3312 | .object = array_id, |
| | 3313 | }); |
| 3315 | | 3314 | |
| 3316 | const tmp_id = try self.alloc(array_ty, .{ .storage_class = .Function }); | | |
| 3317 | try self.store(array_ty, tmp_id, array_id, .{}); | | |
| 3318 | const elem_ptr_id = try self.accessChainId(elem_ptr_ty_ref, tmp_id, &.{index_id}); | 3315 | const elem_ptr_id = try self.accessChainId(elem_ptr_ty_ref, tmp_id, &.{index_id}); |
| 3319 | return try self.load(elem_ty, elem_ptr_id, .{}); | 3316 | return try self.load(elem_ty, elem_ptr_id, false); |
| 3320 | } | 3317 | } |
| 3321 | | 3318 | |
| 3322 | fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3319 | fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3329,7 +3326,7 @@ const DeclGen = struct { | ... | @@ -3329,7 +3326,7 @@ const DeclGen = struct { |
| 3329 | const ptr_id = try self.resolve(bin_op.lhs); | 3326 | const ptr_id = try self.resolve(bin_op.lhs); |
| 3330 | const index_id = try self.resolve(bin_op.rhs); | 3327 | const index_id = try self.resolve(bin_op.rhs); |
| 3331 | const elem_ptr_id = try self.ptrElemPtr(ptr_ty, ptr_id, index_id); | 3328 | const elem_ptr_id = try self.ptrElemPtr(ptr_ty, ptr_id, index_id); |
| 3332 | return try self.load(elem_ty, elem_ptr_id, .{ .is_volatile = ptr_ty.isVolatilePtr(mod) }); | 3329 | return try self.load(elem_ty, elem_ptr_id, ptr_ty.isVolatilePtr(mod)); |
| 3333 | } | 3330 | } |
| 3334 | | 3331 | |
| 3335 | fn airSetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !void { | 3332 | fn airSetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !void { |
| ... | @@ -3337,21 +3334,22 @@ const DeclGen = struct { | ... | @@ -3337,21 +3334,22 @@ const DeclGen = struct { |
| 3337 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 3334 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3338 | const un_ptr_ty = self.typeOf(bin_op.lhs); | 3335 | const un_ptr_ty = self.typeOf(bin_op.lhs); |
| 3339 | const un_ty = un_ptr_ty.childType(mod); | 3336 | const un_ty = un_ptr_ty.childType(mod); |
| 3340 | const layout = self.unionLayout(un_ty); | 3337 | const layout = self.unionLayout(un_ty, null); |
| 3341 | | 3338 | |
| 3342 | if (layout.tag_size == 0) return; | 3339 | if (layout.tag_size == 0) return; |
| 3343 | | 3340 | |
| 3344 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; | 3341 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; |
| 3345 | const tag_ptr_ty_ref = try self.ptrType(tag_ty, spvStorageClass(un_ptr_ty.ptrAddressSpace(mod))); | 3342 | const tag_ty_ref = try self.resolveType(tag_ty, .indirect); |
| | 3343 | const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, spvStorageClass(un_ptr_ty.ptrAddressSpace(mod))); |
| 3346 | | 3344 | |
| 3347 | const union_ptr_id = try self.resolve(bin_op.lhs); | 3345 | const union_ptr_id = try self.resolve(bin_op.lhs); |
| 3348 | const new_tag_id = try self.resolve(bin_op.rhs); | 3346 | const new_tag_id = try self.resolve(bin_op.rhs); |
| 3349 | | 3347 | |
| 3350 | if (!layout.has_payload) { | 3348 | if (layout.payload_size == 0) { |
| 3351 | try self.store(tag_ty, union_ptr_id, new_tag_id, .{ .is_volatile = un_ptr_ty.isVolatilePtr(mod) }); | 3349 | try self.store(tag_ty, union_ptr_id, new_tag_id, un_ptr_ty.isVolatilePtr(mod)); |
| 3352 | } else { | 3350 | } else { |
| 3353 | const ptr_id = try self.accessChain(tag_ptr_ty_ref, union_ptr_id, &.{layout.tag_index}); | 3351 | const ptr_id = try self.accessChain(tag_ptr_ty_ref, union_ptr_id, &.{layout.tag_index}); |
| 3354 | try self.store(tag_ty, ptr_id, new_tag_id, .{ .is_volatile = un_ptr_ty.isVolatilePtr(mod) }); | 3352 | try self.store(tag_ty, ptr_id, new_tag_id, un_ptr_ty.isVolatilePtr(mod)); |
| 3355 | } | 3353 | } |
| 3356 | } | 3354 | } |
| 3357 | | 3355 | |
| ... | @@ -3362,11 +3360,11 @@ const DeclGen = struct { | ... | @@ -3362,11 +3360,11 @@ const DeclGen = struct { |
| 3362 | const un_ty = self.typeOf(ty_op.operand); | 3360 | const un_ty = self.typeOf(ty_op.operand); |
| 3363 | | 3361 | |
| 3364 | const mod = self.module; | 3362 | const mod = self.module; |
| 3365 | const layout = self.unionLayout(un_ty); | 3363 | const layout = self.unionLayout(un_ty, null); |
| 3366 | if (layout.tag_size == 0) return null; | 3364 | if (layout.tag_size == 0) return null; |
| 3367 | | 3365 | |
| 3368 | const union_handle = try self.resolve(ty_op.operand); | 3366 | const union_handle = try self.resolve(ty_op.operand); |
| 3369 | if (!layout.has_payload) return union_handle; | 3367 | if (layout.payload_size == 0) return union_handle; |
| 3370 | | 3368 | |
| 3371 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; | 3369 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; |
| 3372 | return try self.extractField(tag_ty, union_handle, layout.tag_index); | 3370 | return try self.extractField(tag_ty, union_handle, layout.tag_index); |
| ... | @@ -3379,8 +3377,8 @@ const DeclGen = struct { | ... | @@ -3379,8 +3377,8 @@ const DeclGen = struct { |
| 3379 | payload: ?IdRef, | 3377 | payload: ?IdRef, |
| 3380 | ) !IdRef { | 3378 | ) !IdRef { |
| 3381 | // To initialize a union, generate a temporary variable with the | 3379 | // To initialize a union, generate a temporary variable with the |
| 3382 | // union type, then get the field pointer and pointer-cast it to the | 3380 | // type that has the right field active, then pointer-cast and store |
| 3383 | // right type to store it. Finally load the entire union. | 3381 | // the active field, and finally load and return the entire union. |
| 3384 | | 3382 | |
| 3385 | const mod = self.module; | 3383 | const mod = self.module; |
| 3386 | const ip = &mod.intern_pool; | 3384 | const ip = &mod.intern_pool; |
| ... | @@ -3391,7 +3389,7 @@ const DeclGen = struct { | ... | @@ -3391,7 +3389,7 @@ const DeclGen = struct { |
| 3391 | } | 3389 | } |
| 3392 | | 3390 | |
| 3393 | const maybe_tag_ty = ty.unionTagTypeSafety(mod); | 3391 | const maybe_tag_ty = ty.unionTagTypeSafety(mod); |
| 3394 | const layout = self.unionLayout(ty); | 3392 | const layout = self.unionLayout(ty, active_field); |
| 3395 | | 3393 | |
| 3396 | const tag_int = if (layout.tag_size != 0) blk: { | 3394 | const tag_int = if (layout.tag_size != 0) blk: { |
| 3397 | const tag_ty = maybe_tag_ty.?; | 3395 | const tag_ty = maybe_tag_ty.?; |
| ... | @@ -3402,34 +3400,42 @@ const DeclGen = struct { | ... | @@ -3402,34 +3400,42 @@ const DeclGen = struct { |
| 3402 | break :blk tag_int_val.toUnsignedInt(mod); | 3400 | break :blk tag_int_val.toUnsignedInt(mod); |
| 3403 | } else 0; | 3401 | } else 0; |
| 3404 | | 3402 | |
| 3405 | if (!layout.has_payload) { | 3403 | if (layout.payload_size == 0) { |
| 3406 | const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct); | 3404 | const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct); |
| 3407 | return try self.constInt(tag_ty_ref, tag_int); | 3405 | return try self.constInt(tag_ty_ref, tag_int); |
| 3408 | } | 3406 | } |
| 3409 | | 3407 | |
| 3410 | const tmp_id = try self.alloc(ty, .{ .storage_class = .Function }); | 3408 | const un_active_ty_ref = try self.resolveUnionType(ty, active_field); |
| | 3409 | const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); |
| | 3410 | const un_general_ty_ref = try self.resolveType(ty, .direct); |
| | 3411 | const un_general_ptr_ty_ref = try self.spv.ptrType(un_general_ty_ref, .Function); |
| | 3412 | |
| | 3413 | const tmp_id = self.spv.allocId(); |
| | 3414 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| | 3415 | .id_result_type = self.typeId(un_active_ptr_ty_ref), |
| | 3416 | .id_result = tmp_id, |
| | 3417 | .storage_class = .Function, |
| | 3418 | }); |
| 3411 | | 3419 | |
| 3412 | if (layout.tag_size != 0) { | 3420 | if (layout.tag_size != 0) { |
| 3413 | const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct); | 3421 | const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct); |
| 3414 | const tag_ptr_ty_ref = try self.ptrType(maybe_tag_ty.?, .Function); | 3422 | const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); |
| 3415 | const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))}); | 3423 | const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))}); |
| 3416 | const tag_id = try self.constInt(tag_ty_ref, tag_int); | 3424 | const tag_id = try self.constInt(tag_ty_ref, tag_int); |
| 3417 | try self.store(maybe_tag_ty.?, ptr_id, tag_id, .{}); | 3425 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| | 3426 | .pointer = ptr_id, |
| | 3427 | .object = tag_id, |
| | 3428 | }); |
| 3418 | } | 3429 | } |
| 3419 | | 3430 | |
| 3420 | const payload_ty = union_ty.field_types.get(ip)[active_field].toType(); | 3431 | if (layout.active_field_size != 0) { |
| 3421 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 3432 | const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); |
| 3422 | const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, .Function); | 3433 | const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); |
| 3423 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, tmp_id, &.{layout.payload_index}); | 3434 | const ptr_id = try self.accessChain(active_field_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.active_field_index))}); |
| 3424 | const active_pl_ptr_ty_ref = try self.ptrType(payload_ty, .Function); | 3435 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 3425 | const active_pl_ptr_id = self.spv.allocId(); | 3436 | .pointer = ptr_id, |
| 3426 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ | 3437 | .object = payload.?, |
| 3427 | .id_result_type = self.typeId(active_pl_ptr_ty_ref), | | |
| 3428 | .id_result = active_pl_ptr_id, | | |
| 3429 | .operand = pl_ptr_id, | | |
| 3430 | }); | 3438 | }); |
| 3431 | | | |
| 3432 | try self.store(payload_ty, active_pl_ptr_id, payload.?, .{}); | | |
| 3433 | } else { | 3439 | } else { |
| 3434 | assert(payload == null); | 3440 | assert(payload == null); |
| 3435 | } | 3441 | } |
| ... | @@ -3437,21 +3443,34 @@ const DeclGen = struct { | ... | @@ -3437,21 +3443,34 @@ const DeclGen = struct { |
| 3437 | // Just leave the padding fields uninitialized... | 3443 | // Just leave the padding fields uninitialized... |
| 3438 | // TODO: Or should we initialize them with undef explicitly? | 3444 | // TODO: Or should we initialize them with undef explicitly? |
| 3439 | | 3445 | |
| 3440 | return try self.load(ty, tmp_id, .{}); | 3446 | // Now cast the pointer and load it as the 'generic' union type. |
| | 3447 | |
| | 3448 | const casted_var_id = self.spv.allocId(); |
| | 3449 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| | 3450 | .id_result_type = self.typeId(un_general_ptr_ty_ref), |
| | 3451 | .id_result = casted_var_id, |
| | 3452 | .operand = tmp_id, |
| | 3453 | }); |
| | 3454 | |
| | 3455 | const result_id = self.spv.allocId(); |
| | 3456 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| | 3457 | .id_result_type = self.typeId(un_general_ty_ref), |
| | 3458 | .id_result = result_id, |
| | 3459 | .pointer = casted_var_id, |
| | 3460 | }); |
| | 3461 | |
| | 3462 | return result_id; |
| 3441 | } | 3463 | } |
| 3442 | | 3464 | |
| 3443 | fn airUnionInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3465 | fn airUnionInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3444 | if (self.liveness.isUnused(inst)) return null; | 3466 | if (self.liveness.isUnused(inst)) return null; |
| 3445 | | 3467 | |
| 3446 | const mod = self.module; | | |
| 3447 | const ip = &mod.intern_pool; | | |
| 3448 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 3468 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3449 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; | 3469 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 3450 | const ty = self.typeOfIndex(inst); | 3470 | const ty = self.typeOfIndex(inst); |
| | 3471 | const layout = self.unionLayout(ty, extra.field_index); |
| 3451 | | 3472 | |
| 3452 | const union_obj = mod.typeToUnion(ty).?; | 3473 | const payload = if (layout.active_field_size != 0) |
| 3453 | const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType(); | | |
| 3454 | const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod)) | | |
| 3455 | try self.resolve(extra.init) | 3474 | try self.resolve(extra.init) |
| 3456 | else | 3475 | else |
| 3457 | null; | 3476 | null; |
| ... | @@ -3480,24 +3499,30 @@ const DeclGen = struct { | ... | @@ -3480,24 +3499,30 @@ const DeclGen = struct { |
| 3480 | .Union => switch (object_ty.containerLayout(mod)) { | 3499 | .Union => switch (object_ty.containerLayout(mod)) { |
| 3481 | .Packed => unreachable, // TODO | 3500 | .Packed => unreachable, // TODO |
| 3482 | else => { | 3501 | else => { |
| 3483 | // Store, ptr-elem-ptr, pointer-cast, load | 3502 | // Store, pointer-cast, load |
| 3484 | const layout = self.unionLayout(object_ty); | 3503 | const un_general_ty_ref = try self.resolveType(object_ty, .indirect); |
| 3485 | assert(layout.has_payload); | 3504 | const un_general_ptr_ty_ref = try self.spv.ptrType(un_general_ty_ref, .Function); |
| 3486 | | 3505 | const un_active_ty_ref = try self.resolveUnionType(object_ty, field_index); |
| 3487 | const tmp_id = try self.alloc(object_ty, .{ .storage_class = .Function }); | 3506 | const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); |
| 3488 | try self.store(object_ty, tmp_id, object_id, .{}); | 3507 | const field_ty_ref = try self.resolveType(field_ty, .indirect); |
| 3489 | | 3508 | const field_ptr_ty_ref = try self.spv.ptrType(field_ty_ref, .Function); |
| 3490 | const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, .Function); | 3509 | |
| 3491 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, tmp_id, &.{layout.payload_index}); | 3510 | const tmp_id = self.spv.allocId(); |
| 3492 | | 3511 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| 3493 | const active_pl_ptr_ty_ref = try self.ptrType(field_ty, .Function); | 3512 | .id_result_type = self.typeId(un_general_ptr_ty_ref), |
| 3494 | const active_pl_ptr_id = self.spv.allocId(); | 3513 | .id_result = tmp_id, |
| | 3514 | .storage_class = .Function, |
| | 3515 | }); |
| | 3516 | try self.store(object_ty, tmp_id, object_id, false); |
| | 3517 | const casted_tmp_id = self.spv.allocId(); |
| 3495 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ | 3518 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 3496 | .id_result_type = self.typeId(active_pl_ptr_ty_ref), | 3519 | .id_result_type = self.typeId(un_active_ptr_ty_ref), |
| 3497 | .id_result = active_pl_ptr_id, | 3520 | .id_result = casted_tmp_id, |
| 3498 | .operand = pl_ptr_id, | 3521 | .operand = tmp_id, |
| 3499 | }); | 3522 | }); |
| 3500 | return try self.load(field_ty, active_pl_ptr_id, .{}); | 3523 | const layout = self.unionLayout(object_ty, field_index); |
| | 3524 | const field_ptr_id = try self.accessChain(field_ptr_ty_ref, casted_tmp_id, &.{layout.active_field_index}); |
| | 3525 | return try self.load(field_ty, field_ptr_id, false); |
| 3501 | }, | 3526 | }, |
| 3502 | }, | 3527 | }, |
| 3503 | else => unreachable, | 3528 | else => unreachable, |
| ... | @@ -3556,24 +3581,18 @@ const DeclGen = struct { | ... | @@ -3556,24 +3581,18 @@ const DeclGen = struct { |
| 3556 | .Union => switch (object_ty.containerLayout(mod)) { | 3581 | .Union => switch (object_ty.containerLayout(mod)) { |
| 3557 | .Packed => unreachable, // TODO | 3582 | .Packed => unreachable, // TODO |
| 3558 | else => { | 3583 | else => { |
| 3559 | const layout = self.unionLayout(object_ty); | | |
| 3560 | if (!layout.has_payload) { | | |
| 3561 | // Asked to get a pointer to a zero-sized field. Just lower this | | |
| 3562 | // to undefined, there is no reason to make it be a valid pointer. | | |
| 3563 | return try self.spv.constUndef(result_ty_ref); | | |
| 3564 | } | | |
| 3565 | | | |
| 3566 | const storage_class = spvStorageClass(object_ptr_ty.ptrAddressSpace(mod)); | 3584 | const storage_class = spvStorageClass(object_ptr_ty.ptrAddressSpace(mod)); |
| 3567 | const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, storage_class); | 3585 | const un_active_ty_ref = try self.resolveUnionType(object_ty, field_index); |
| 3568 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, object_ptr, &.{layout.payload_index}); | 3586 | const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, storage_class); |
| 3569 | | 3587 | |
| 3570 | const active_pl_ptr_id = self.spv.allocId(); | 3588 | const casted_id = self.spv.allocId(); |
| 3571 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ | 3589 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 3572 | .id_result_type = self.typeId(result_ty_ref), | 3590 | .id_result_type = self.typeId(un_active_ptr_ty_ref), |
| 3573 | .id_result = active_pl_ptr_id, | 3591 | .id_result = casted_id, |
| 3574 | .operand = pl_ptr_id, | 3592 | .operand = object_ptr, |
| 3575 | }); | 3593 | }); |
| 3576 | return active_pl_ptr_id; | 3594 | const layout = self.unionLayout(object_ty, field_index); |
| | 3595 | return try self.accessChain(result_ty_ref, casted_id, &.{layout.active_field_index}); |
| 3577 | }, | 3596 | }, |
| 3578 | }, | 3597 | }, |
| 3579 | else => unreachable, | 3598 | else => unreachable, |
| ... | @@ -3589,13 +3608,23 @@ const DeclGen = struct { | ... | @@ -3589,13 +3608,23 @@ const DeclGen = struct { |
| 3589 | return try self.structFieldPtr(result_ptr_ty, struct_ptr_ty, struct_ptr, field_index); | 3608 | return try self.structFieldPtr(result_ptr_ty, struct_ptr_ty, struct_ptr, field_index); |
| 3590 | } | 3609 | } |
| 3591 | | 3610 | |
| 3592 | const AllocOptions = struct { | 3611 | /// We cannot use an OpVariable directly in an OpSpecConstantOp, but we can |
| 3593 | initializer: ?IdRef = null, | 3612 | /// after we insert a dummy AccessChain... |
| 3594 | /// The final storage class of the pointer. This may be either `.Generic` or `.Function`. | 3613 | /// TODO: Get rid of this |
| 3595 | /// In either case, the local is allocated in the `.Function` storage class, and optionally | 3614 | fn makePointerConstant( |
| 3596 | /// cast back to `.Generic`. | 3615 | self: *DeclGen, |
| 3597 | storage_class: StorageClass = .Generic, | 3616 | section: *SpvSection, |
| 3598 | }; | 3617 | ptr_ty_ref: CacheRef, |
| | 3618 | ptr_id: IdRef, |
| | 3619 | ) !IdRef { |
| | 3620 | const result_id = self.spv.allocId(); |
| | 3621 | try section.emitSpecConstantOp(self.spv.gpa, .OpInBoundsAccessChain, .{ |
| | 3622 | .id_result_type = self.typeId(ptr_ty_ref), |
| | 3623 | .id_result = result_id, |
| | 3624 | .base = ptr_id, |
| | 3625 | }); |
| | 3626 | return result_id; |
| | 3627 | } |
| 3599 | | 3628 | |
| 3600 | // Allocate a function-local variable, with possible initializer. | 3629 | // Allocate a function-local variable, with possible initializer. |
| 3601 | // This function returns a pointer to a variable of type `ty_ref`, | 3630 | // This function returns a pointer to a variable of type `ty_ref`, |
| ... | @@ -3603,36 +3632,30 @@ const DeclGen = struct { | ... | @@ -3603,36 +3632,30 @@ const DeclGen = struct { |
| 3603 | // placed in the Function address space. | 3632 | // placed in the Function address space. |
| 3604 | fn alloc( | 3633 | fn alloc( |
| 3605 | self: *DeclGen, | 3634 | self: *DeclGen, |
| 3606 | ty: Type, | 3635 | ty_ref: CacheRef, |
| 3607 | options: AllocOptions, | 3636 | initializer: ?IdRef, |
| 3608 | ) !IdRef { | 3637 | ) !IdRef { |
| 3609 | const ptr_fn_ty_ref = try self.ptrType(ty, .Function); | 3638 | const fn_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Function); |
| | 3639 | const general_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Generic); |
| 3610 | | 3640 | |
| 3611 | // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to | 3641 | // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to |
| 3612 | // directly generate them into func.prologue instead of the body. | 3642 | // directly generate them into func.prologue instead of the body. |
| 3613 | const var_id = self.spv.allocId(); | 3643 | const var_id = self.spv.allocId(); |
| 3614 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ | 3644 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| 3615 | .id_result_type = self.typeId(ptr_fn_ty_ref), | 3645 | .id_result_type = self.typeId(fn_ptr_ty_ref), |
| 3616 | .id_result = var_id, | 3646 | .id_result = var_id, |
| 3617 | .storage_class = .Function, | 3647 | .storage_class = .Function, |
| 3618 | .initializer = options.initializer, | 3648 | .initializer = initializer, |
| 3619 | }); | 3649 | }); |
| 3620 | | 3650 | |
| 3621 | switch (options.storage_class) { | 3651 | // Convert to a generic pointer |
| 3622 | .Generic => { | 3652 | const result_id = self.spv.allocId(); |
| 3623 | const ptr_gn_ty_ref = try self.ptrType(ty, .Generic); | 3653 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| 3624 | // Convert to a generic pointer | 3654 | .id_result_type = self.typeId(general_ptr_ty_ref), |
| 3625 | const result_id = self.spv.allocId(); | 3655 | .id_result = result_id, |
| 3626 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ | 3656 | .pointer = var_id, |
| 3627 | .id_result_type = self.typeId(ptr_gn_ty_ref), | 3657 | }); |
| 3628 | .id_result = result_id, | 3658 | return result_id; |
| 3629 | .pointer = var_id, | | |
| 3630 | }); | | |
| 3631 | return result_id; | | |
| 3632 | }, | | |
| 3633 | .Function => return var_id, | | |
| 3634 | else => unreachable, | | |
| 3635 | } | | |
| 3636 | } | 3659 | } |
| 3637 | | 3660 | |
| 3638 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3661 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3641,7 +3664,8 @@ const DeclGen = struct { | ... | @@ -3641,7 +3664,8 @@ const DeclGen = struct { |
| 3641 | const ptr_ty = self.typeOfIndex(inst); | 3664 | const ptr_ty = self.typeOfIndex(inst); |
| 3642 | assert(ptr_ty.ptrAddressSpace(mod) == .generic); | 3665 | assert(ptr_ty.ptrAddressSpace(mod) == .generic); |
| 3643 | const child_ty = ptr_ty.childType(mod); | 3666 | const child_ty = ptr_ty.childType(mod); |
| 3644 | return try self.alloc(child_ty, .{}); | 3667 | const child_ty_ref = try self.resolveType(child_ty, .indirect); |
| | 3668 | return try self.alloc(child_ty_ref, null); |
| 3645 | } | 3669 | } |
| 3646 | | 3670 | |
| 3647 | fn airArg(self: *DeclGen) IdRef { | 3671 | fn airArg(self: *DeclGen) IdRef { |
| ... | @@ -3756,7 +3780,7 @@ const DeclGen = struct { | ... | @@ -3756,7 +3780,7 @@ const DeclGen = struct { |
| 3756 | const operand = try self.resolve(ty_op.operand); | 3780 | const operand = try self.resolve(ty_op.operand); |
| 3757 | if (!ptr_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) return null; | 3781 | if (!ptr_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) return null; |
| 3758 | | 3782 | |
| 3759 | return try self.load(elem_ty, operand, .{ .is_volatile = ptr_ty.isVolatilePtr(mod) }); | 3783 | return try self.load(elem_ty, operand, ptr_ty.isVolatilePtr(mod)); |
| 3760 | } | 3784 | } |
| 3761 | | 3785 | |
| 3762 | fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { | 3786 | fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { |
| ... | @@ -3766,7 +3790,7 @@ const DeclGen = struct { | ... | @@ -3766,7 +3790,7 @@ const DeclGen = struct { |
| 3766 | const ptr = try self.resolve(bin_op.lhs); | 3790 | const ptr = try self.resolve(bin_op.lhs); |
| 3767 | const value = try self.resolve(bin_op.rhs); | 3791 | const value = try self.resolve(bin_op.rhs); |
| 3768 | | 3792 | |
| 3769 | try self.store(elem_ty, ptr, value, .{ .is_volatile = ptr_ty.isVolatilePtr(self.module) }); | 3793 | try self.store(elem_ty, ptr, value, ptr_ty.isVolatilePtr(self.module)); |
| 3770 | } | 3794 | } |
| 3771 | | 3795 | |
| 3772 | fn airLoop(self: *DeclGen, inst: Air.Inst.Index) !void { | 3796 | fn airLoop(self: *DeclGen, inst: Air.Inst.Index) !void { |
| ... | @@ -3830,7 +3854,7 @@ const DeclGen = struct { | ... | @@ -3830,7 +3854,7 @@ const DeclGen = struct { |
| 3830 | } | 3854 | } |
| 3831 | | 3855 | |
| 3832 | const ptr = try self.resolve(un_op); | 3856 | const ptr = try self.resolve(un_op); |
| 3833 | const value = try self.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(mod) }); | 3857 | const value = try self.load(ret_ty, ptr, ptr_ty.isVolatilePtr(mod)); |
| 3834 | try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ | 3858 | try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ |
| 3835 | .value = value, | 3859 | .value = value, |
| 3836 | }); | 3860 | }); |
| ... | @@ -3956,11 +3980,8 @@ const DeclGen = struct { | ... | @@ -3956,11 +3980,8 @@ const DeclGen = struct { |
| 3956 | members[eu_layout.errorFieldIndex()] = operand_id; | 3980 | members[eu_layout.errorFieldIndex()] = operand_id; |
| 3957 | members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref); | 3981 | members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref); |
| 3958 | | 3982 | |
| 3959 | var types: [2]Type = undefined; | 3983 | const err_union_ty_ref = try self.resolveType(err_union_ty, .direct); |
| 3960 | types[eu_layout.errorFieldIndex()] = Type.anyerror; | 3984 | return try self.constructStruct(err_union_ty_ref, &members); |
| 3961 | types[eu_layout.payloadFieldIndex()] = payload_ty; | | |
| 3962 | | | |
| 3963 | return try self.constructStruct(err_union_ty, &types, &members); | | |
| 3964 | } | 3985 | } |
| 3965 | | 3986 | |
| 3966 | fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3987 | fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3981,11 +4002,8 @@ const DeclGen = struct { | ... | @@ -3981,11 +4002,8 @@ const DeclGen = struct { |
| 3981 | members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0); | 4002 | members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0); |
| 3982 | members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id); | 4003 | members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id); |
| 3983 | | 4004 | |
| 3984 | var types: [2]Type = undefined; | 4005 | const err_union_ty_ref = try self.resolveType(err_union_ty, .direct); |
| 3985 | types[eu_layout.errorFieldIndex()] = Type.anyerror; | 4006 | return try self.constructStruct(err_union_ty_ref, &members); |
| 3986 | types[eu_layout.payloadFieldIndex()] = payload_ty; | | |
| 3987 | | | |
| 3988 | return try self.constructStruct(err_union_ty, &types, &members); | | |
| 3989 | } | 4007 | } |
| 3990 | | 4008 | |
| 3991 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { | 4009 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { |
| ... | @@ -4019,7 +4037,7 @@ const DeclGen = struct { | ... | @@ -4019,7 +4037,7 @@ const DeclGen = struct { |
| 4019 | .is_null => .eq, | 4037 | .is_null => .eq, |
| 4020 | .is_non_null => .neq, | 4038 | .is_non_null => .neq, |
| 4021 | }; | 4039 | }; |
| 4022 | return try self.cmp(op, Type.bool, ptr_ty, ptr_id, null_id); | 4040 | return try self.cmp(op, ptr_ty, ptr_id, null_id); |
| 4023 | } | 4041 | } |
| 4024 | | 4042 | |
| 4025 | const is_non_null_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) | 4043 | const is_non_null_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| ... | @@ -4117,10 +4135,10 @@ const DeclGen = struct { | ... | @@ -4117,10 +4135,10 @@ const DeclGen = struct { |
| 4117 | return operand_id; | 4135 | return operand_id; |
| 4118 | } | 4136 | } |
| 4119 | | 4137 | |
| | 4138 | const optional_ty_ref = try self.resolveType(optional_ty, .direct); |
| 4120 | const payload_id = try self.convertToIndirect(payload_ty, operand_id); | 4139 | const payload_id = try self.convertToIndirect(payload_ty, operand_id); |
| 4121 | const members = [_]IdRef{ payload_id, try self.constBool(true, .indirect) }; | 4140 | const members = [_]IdRef{ payload_id, try self.constBool(true, .indirect) }; |
| 4122 | const types = [_]Type{ payload_ty, Type.bool }; | 4141 | return try self.constructStruct(optional_ty_ref, &members); |
| 4123 | return try self.constructStruct(optional_ty, &types, &members); | | |
| 4124 | } | 4142 | } |
| 4125 | | 4143 | |
| 4126 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { | 4144 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { |
| ... | @@ -4402,7 +4420,6 @@ const DeclGen = struct { | ... | @@ -4402,7 +4420,6 @@ const DeclGen = struct { |
| 4402 | } | 4420 | } |
| 4403 | | 4421 | |
| 4404 | // TODO: Multiple results | 4422 | // TODO: Multiple results |
| 4405 | // TODO: Check that the output type from assembly is the same as the type actually expected by Zig. | | |
| 4406 | } | 4423 | } |
| 4407 | | 4424 | |
| 4408 | return null; | 4425 | return null; |