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