| ... | @@ -358,8 +358,7 @@ const DeclGen = struct { | ... | @@ -358,8 +358,7 @@ const DeclGen = struct { |
| 358 | | 358 | |
| 359 | const mod = self.module; | 359 | const mod = self.module; |
| 360 | const ty = mod.intern_pool.typeOf(val).toType(); | 360 | const ty = mod.intern_pool.typeOf(val).toType(); |
| 361 | const ty_ref = try self.resolveType(ty, .indirect); | 361 | const ptr_ty_ref = try self.ptrType(ty, storage_class); |
| 362 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class); | | |
| 363 | | 362 | |
| 364 | const var_id = self.spv.declPtr(spv_decl_index).result_id; | 363 | const var_id = self.spv.declPtr(spv_decl_index).result_id; |
| 365 | | 364 | |
| ... | @@ -623,25 +622,15 @@ const DeclGen = struct { | ... | @@ -623,25 +622,15 @@ const DeclGen = struct { |
| 623 | /// result_ty_ref must be an array type. | 622 | /// result_ty_ref must be an array type. |
| 624 | /// Constituents should be in `indirect` representation (as the elements of an array should be). | 623 | /// Constituents should be in `indirect` representation (as the elements of an array should be). |
| 625 | /// Result is in `direct` representation. | 624 | /// Result is in `direct` representation. |
| 626 | fn constructArray(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef { | 625 | fn constructArray(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| 627 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' | 626 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 628 | // operands are not constant. | 627 | // operands are not constant. |
| 629 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 | 628 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 630 | // For now, just initialize the struct by setting the fields manually... | 629 | // For now, just initialize the struct by setting the fields manually... |
| 631 | // TODO: Make this OpCompositeConstruct when we can | 630 | // TODO: Make this OpCompositeConstruct when we can |
| 632 | // TODO: Make this Function storage type | 631 | const mod = self.module; |
| 633 | const ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); | 632 | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| 634 | const ptr_composite_id = self.spv.allocId(); | 633 | 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| { | 634 | for (constituents, 0..) |constitent_id, index| { |
| 646 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); | 635 | 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, .{ | 636 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| ... | @@ -649,13 +638,8 @@ const DeclGen = struct { | ... | @@ -649,13 +638,8 @@ const DeclGen = struct { |
| 649 | .object = constitent_id, | 638 | .object = constitent_id, |
| 650 | }); | 639 | }); |
| 651 | } | 640 | } |
| 652 | const result_id = self.spv.allocId(); | 641 | |
| 653 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ | 642 | 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 | } | 643 | } |
| 660 | | 644 | |
| 661 | /// This function generates a load for a constant in direct (ie, non-memory) representation. | 645 | /// This function generates a load for a constant in direct (ie, non-memory) representation. |
| ... | @@ -857,7 +841,7 @@ const DeclGen = struct { | ... | @@ -857,7 +841,7 @@ const DeclGen = struct { |
| 857 | else => {}, | 841 | else => {}, |
| 858 | } | 842 | } |
| 859 | | 843 | |
| 860 | return try self.constructArray(result_ty_ref, constituents); | 844 | return try self.constructArray(ty, constituents); |
| 861 | }, | 845 | }, |
| 862 | .struct_type => { | 846 | .struct_type => { |
| 863 | const struct_type = mod.typeToStruct(ty).?; | 847 | const struct_type = mod.typeToStruct(ty).?; |
| ... | @@ -892,7 +876,7 @@ const DeclGen = struct { | ... | @@ -892,7 +876,7 @@ const DeclGen = struct { |
| 892 | const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; | 876 | const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; |
| 893 | const layout = self.unionLayout(ty, active_field); | 877 | const layout = self.unionLayout(ty, active_field); |
| 894 | const payload = if (layout.active_field_size != 0) | 878 | const payload = if (layout.active_field_size != 0) |
| 895 | try self.constant(layout.active_field_ty, un.val.toValue(), .indirect) | 879 | try self.constant(layout.active_field_ty, un.val.toValue(), .direct) |
| 896 | else | 880 | else |
| 897 | null; | 881 | null; |
| 898 | | 882 | |
| ... | @@ -934,8 +918,7 @@ const DeclGen = struct { | ... | @@ -934,8 +918,7 @@ const DeclGen = struct { |
| 934 | | 918 | |
| 935 | // TODO: Can we consolidate this in ptrElemPtr? | 919 | // TODO: Can we consolidate this in ptrElemPtr? |
| 936 | const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. | 920 | const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. |
| 937 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); | 921 | const elem_ptr_ty_ref = try self.ptrType(elem_ty, spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod))); |
| 938 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod))); | | |
| 939 | | 922 | |
| 940 | if (elem_ptr_ty_ref == result_ty_ref) { | 923 | if (elem_ptr_ty_ref == result_ty_ref) { |
| 941 | return elem_ptr_id; | 924 | return elem_ptr_id; |
| ... | @@ -992,8 +975,7 @@ const DeclGen = struct { | ... | @@ -992,8 +975,7 @@ const DeclGen = struct { |
| 992 | }; | 975 | }; |
| 993 | | 976 | |
| 994 | const decl_id = try self.resolveAnonDecl(decl_val, actual_storage_class); | 977 | const decl_id = try self.resolveAnonDecl(decl_val, actual_storage_class); |
| 995 | const decl_ty_ref = try self.resolveType(decl_ty, .indirect); | 978 | const decl_ptr_ty_ref = try self.ptrType(decl_ty, final_storage_class); |
| 996 | const decl_ptr_ty_ref = try self.spv.ptrType(decl_ty_ref, final_storage_class); | | |
| 997 | | 979 | |
| 998 | const ptr_id = switch (final_storage_class) { | 980 | const ptr_id = switch (final_storage_class) { |
| 999 | .Generic => blk: { | 981 | .Generic => blk: { |
| ... | @@ -1049,8 +1031,7 @@ const DeclGen = struct { | ... | @@ -1049,8 +1031,7 @@ const DeclGen = struct { |
| 1049 | | 1031 | |
| 1050 | const final_storage_class = spvStorageClass(decl.@"addrspace"); | 1032 | const final_storage_class = spvStorageClass(decl.@"addrspace"); |
| 1051 | | 1033 | |
| 1052 | const decl_ty_ref = try self.resolveType(decl.ty, .indirect); | 1034 | const decl_ptr_ty_ref = try self.ptrType(decl.ty, final_storage_class); |
| 1053 | const decl_ptr_ty_ref = try self.spv.ptrType(decl_ty_ref, final_storage_class); | | |
| 1054 | | 1035 | |
| 1055 | const ptr_id = switch (final_storage_class) { | 1036 | const ptr_id = switch (final_storage_class) { |
| 1056 | .Generic => blk: { | 1037 | .Generic => blk: { |
| ... | @@ -1118,6 +1099,12 @@ const DeclGen = struct { | ... | @@ -1118,6 +1099,12 @@ const DeclGen = struct { |
| 1118 | return try self.intType(.unsigned, self.getTarget().ptrBitWidth()); | 1099 | return try self.intType(.unsigned, self.getTarget().ptrBitWidth()); |
| 1119 | } | 1100 | } |
| 1120 | | 1101 | |
| | 1102 | fn ptrType(self: *DeclGen, child_ty: Type, storage_class: StorageClass) !CacheRef { |
| | 1103 | // TODO: This function will be rewritten so that forward declarations work properly |
| | 1104 | const child_ty_ref = try self.resolveType(child_ty, .indirect); |
| | 1105 | return try self.spv.ptrType(child_ty_ref, storage_class); |
| | 1106 | } |
| | 1107 | |
| 1121 | /// Generate a union type, optionally with a known field. If the tag alignment is greater | 1108 | /// Generate a union type, optionally with a known field. If the tag alignment is greater |
| 1122 | /// than that of the payload, a regular union (non-packed, with both tag and payload), will | 1109 | /// than that of the payload, a regular union (non-packed, with both tag and payload), will |
| 1123 | /// be generated as follows: | 1110 | /// be generated as follows: |
| ... | @@ -1678,7 +1665,7 @@ const DeclGen = struct { | ... | @@ -1678,7 +1665,7 @@ const DeclGen = struct { |
| 1678 | /// the name of an error in the text executor. | 1665 | /// the name of an error in the text executor. |
| 1679 | fn generateTestEntryPoint(self: *DeclGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void { | 1666 | fn generateTestEntryPoint(self: *DeclGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void { |
| 1680 | const anyerror_ty_ref = try self.resolveType(Type.anyerror, .direct); | 1667 | const anyerror_ty_ref = try self.resolveType(Type.anyerror, .direct); |
| 1681 | const ptr_anyerror_ty_ref = try self.spv.ptrType(anyerror_ty_ref, .CrossWorkgroup); | 1668 | const ptr_anyerror_ty_ref = try self.ptrType(Type.anyerror, .CrossWorkgroup); |
| 1682 | const void_ty_ref = try self.resolveType(Type.void, .direct); | 1669 | const void_ty_ref = try self.resolveType(Type.void, .direct); |
| 1683 | | 1670 | |
| 1684 | const kernel_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{ | 1671 | const kernel_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{ |
| ... | @@ -1713,6 +1700,7 @@ const DeclGen = struct { | ... | @@ -1713,6 +1700,7 @@ const DeclGen = struct { |
| 1713 | .id_result = error_id, | 1700 | .id_result = error_id, |
| 1714 | .function = test_id, | 1701 | .function = test_id, |
| 1715 | }); | 1702 | }); |
| | 1703 | // Note: Convert to direct not required. |
| 1716 | try section.emit(self.spv.gpa, .OpStore, .{ | 1704 | try section.emit(self.spv.gpa, .OpStore, .{ |
| 1717 | .pointer = p_error_id, | 1705 | .pointer = p_error_id, |
| 1718 | .object = error_id, | 1706 | .object = error_id, |
| ... | @@ -1817,8 +1805,7 @@ const DeclGen = struct { | ... | @@ -1817,8 +1805,7 @@ const DeclGen = struct { |
| 1817 | else => final_storage_class, | 1805 | else => final_storage_class, |
| 1818 | }; | 1806 | }; |
| 1819 | | 1807 | |
| 1820 | const ty_ref = try self.resolveType(decl.ty, .indirect); | 1808 | const ptr_ty_ref = try self.ptrType(decl.ty, actual_storage_class); |
| 1821 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, actual_storage_class); | | |
| 1822 | | 1809 | |
| 1823 | const begin = self.spv.beginGlobal(); | 1810 | const begin = self.spv.beginGlobal(); |
| 1824 | try self.spv.globals.section.emit(self.spv.gpa, .OpVariable, .{ | 1811 | try self.spv.globals.section.emit(self.spv.gpa, .OpVariable, .{ |
| ... | @@ -2113,9 +2100,7 @@ const DeclGen = struct { | ... | @@ -2113,9 +2100,7 @@ const DeclGen = struct { |
| 2113 | constituent.* = try self.convertToIndirect(child_ty, result_id); | 2100 | constituent.* = try self.convertToIndirect(child_ty, result_id); |
| 2114 | } | 2101 | } |
| 2115 | | 2102 | |
| 2116 | const result_ty = try self.resolveType(child_ty, .indirect); | 2103 | return try self.constructArray(ty, constituents); |
| 2117 | const result_ty_ref = try self.spv.arrayType(vector_len, result_ty); | | |
| 2118 | return try self.constructArray(result_ty_ref, constituents); | | |
| 2119 | } | 2104 | } |
| 2120 | | 2105 | |
| 2121 | const result_id = self.spv.allocId(); | 2106 | const result_id = self.spv.allocId(); |
| ... | @@ -2176,7 +2161,7 @@ const DeclGen = struct { | ... | @@ -2176,7 +2161,7 @@ const DeclGen = struct { |
| 2176 | | 2161 | |
| 2177 | const info = try self.arithmeticTypeInfo(result_ty); | 2162 | const info = try self.arithmeticTypeInfo(result_ty); |
| 2178 | // TODO: Use fmin for OpenCL | 2163 | // TODO: Use fmin for OpenCL |
| 2179 | const cmp_id = try self.cmp(op, result_ty, lhs_id, rhs_id); | 2164 | const cmp_id = try self.cmp(op, Type.bool, result_ty, lhs_id, rhs_id); |
| 2180 | const selection_id = switch (info.class) { | 2165 | const selection_id = switch (info.class) { |
| 2181 | .float => blk: { | 2166 | .float => blk: { |
| 2182 | // cmp uses OpFOrd. When we have 0 [<>] nan this returns false, | 2167 | // cmp uses OpFOrd. When we have 0 [<>] nan this returns false, |
| ... | @@ -2311,7 +2296,7 @@ const DeclGen = struct { | ... | @@ -2311,7 +2296,7 @@ const DeclGen = struct { |
| 2311 | constituent.* = try self.arithOp(child_ty, lhs_index_id, rhs_index_id, fop, sop, uop, modular); | 2296 | constituent.* = try self.arithOp(child_ty, lhs_index_id, rhs_index_id, fop, sop, uop, modular); |
| 2312 | } | 2297 | } |
| 2313 | | 2298 | |
| 2314 | return self.constructArray(result_ty_ref, constituents); | 2299 | return self.constructArray(ty, constituents); |
| 2315 | } | 2300 | } |
| 2316 | | 2301 | |
| 2317 | // Binary operations are generally applicable to both scalar and vector operations | 2302 | // Binary operations are generally applicable to both scalar and vector operations |
| ... | @@ -2629,6 +2614,7 @@ const DeclGen = struct { | ... | @@ -2629,6 +2614,7 @@ const DeclGen = struct { |
| 2629 | fn cmp( | 2614 | fn cmp( |
| 2630 | self: *DeclGen, | 2615 | self: *DeclGen, |
| 2631 | op: std.math.CompareOperator, | 2616 | op: std.math.CompareOperator, |
| | 2617 | result_ty: Type, |
| 2632 | ty: Type, | 2618 | ty: Type, |
| 2633 | lhs_id: IdRef, | 2619 | lhs_id: IdRef, |
| 2634 | rhs_id: IdRef, | 2620 | rhs_id: IdRef, |
| ... | @@ -2669,7 +2655,7 @@ const DeclGen = struct { | ... | @@ -2669,7 +2655,7 @@ const DeclGen = struct { |
| 2669 | if (ty.optionalReprIsPayload(mod)) { | 2655 | if (ty.optionalReprIsPayload(mod)) { |
| 2670 | assert(payload_ty.hasRuntimeBitsIgnoreComptime(mod)); | 2656 | assert(payload_ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 2671 | assert(!payload_ty.isSlice(mod)); | 2657 | assert(!payload_ty.isSlice(mod)); |
| 2672 | return self.cmp(op, payload_ty, lhs_id, rhs_id); | 2658 | return self.cmp(op, Type.bool, payload_ty, lhs_id, rhs_id); |
| 2673 | } | 2659 | } |
| 2674 | | 2660 | |
| 2675 | const lhs_valid_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) | 2661 | const lhs_valid_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| ... | @@ -2682,7 +2668,7 @@ const DeclGen = struct { | ... | @@ -2682,7 +2668,7 @@ const DeclGen = struct { |
| 2682 | else | 2668 | else |
| 2683 | try self.convertToDirect(Type.bool, rhs_id); | 2669 | try self.convertToDirect(Type.bool, rhs_id); |
| 2684 | | 2670 | |
| 2685 | const valid_cmp_id = try self.cmp(op, Type.bool, lhs_valid_id, rhs_valid_id); | 2671 | const valid_cmp_id = try self.cmp(op, Type.bool, Type.bool, lhs_valid_id, rhs_valid_id); |
| 2686 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 2672 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2687 | return valid_cmp_id; | 2673 | return valid_cmp_id; |
| 2688 | } | 2674 | } |
| ... | @@ -2693,7 +2679,7 @@ const DeclGen = struct { | ... | @@ -2693,7 +2679,7 @@ const DeclGen = struct { |
| 2693 | const lhs_pl_id = try self.extractField(payload_ty, lhs_id, 0); | 2679 | const lhs_pl_id = try self.extractField(payload_ty, lhs_id, 0); |
| 2694 | const rhs_pl_id = try self.extractField(payload_ty, rhs_id, 0); | 2680 | const rhs_pl_id = try self.extractField(payload_ty, rhs_id, 0); |
| 2695 | | 2681 | |
| 2696 | const pl_cmp_id = try self.cmp(op, payload_ty, lhs_pl_id, rhs_pl_id); | 2682 | const pl_cmp_id = try self.cmp(op, Type.bool, payload_ty, lhs_pl_id, rhs_pl_id); |
| 2697 | | 2683 | |
| 2698 | // op == .eq => lhs_valid == rhs_valid && lhs_pl == rhs_pl | 2684 | // op == .eq => lhs_valid == rhs_valid && lhs_pl == rhs_pl |
| 2699 | // op == .neq => lhs_valid != rhs_valid || lhs_pl != rhs_pl | 2685 | // op == .neq => lhs_valid != rhs_valid || lhs_pl != rhs_pl |
| ... | @@ -2715,7 +2701,6 @@ const DeclGen = struct { | ... | @@ -2715,7 +2701,6 @@ const DeclGen = struct { |
| 2715 | .Vector => { | 2701 | .Vector => { |
| 2716 | const child_ty = ty.childType(mod); | 2702 | const child_ty = ty.childType(mod); |
| 2717 | const vector_len = ty.vectorLen(mod); | 2703 | const vector_len = ty.vectorLen(mod); |
| 2718 | const bool_ty_ref_indirect = try self.resolveType(Type.bool, .indirect); | | |
| 2719 | | 2704 | |
| 2720 | var constituents = try self.gpa.alloc(IdRef, vector_len); | 2705 | var constituents = try self.gpa.alloc(IdRef, vector_len); |
| 2721 | defer self.gpa.free(constituents); | 2706 | defer self.gpa.free(constituents); |
| ... | @@ -2723,12 +2708,11 @@ const DeclGen = struct { | ... | @@ -2723,12 +2708,11 @@ const DeclGen = struct { |
| 2723 | for (constituents, 0..) |*constituent, i| { | 2708 | for (constituents, 0..) |*constituent, i| { |
| 2724 | const lhs_index_id = try self.extractField(child_ty, cmp_lhs_id, @intCast(i)); | 2709 | const lhs_index_id = try self.extractField(child_ty, cmp_lhs_id, @intCast(i)); |
| 2725 | const rhs_index_id = try self.extractField(child_ty, cmp_rhs_id, @intCast(i)); | 2710 | const rhs_index_id = try self.extractField(child_ty, cmp_rhs_id, @intCast(i)); |
| 2726 | const result_id = try self.cmp(op, child_ty, lhs_index_id, rhs_index_id); | 2711 | const result_id = try self.cmp(op, Type.bool, child_ty, lhs_index_id, rhs_index_id); |
| 2727 | constituent.* = try self.convertToIndirect(Type.bool, result_id); | 2712 | constituent.* = try self.convertToIndirect(Type.bool, result_id); |
| 2728 | } | 2713 | } |
| 2729 | | 2714 | |
| 2730 | const result_ty_ref = try self.spv.arrayType(vector_len, bool_ty_ref_indirect); | 2715 | return try self.constructArray(result_ty, constituents); |
| 2731 | return try self.constructArray(result_ty_ref, constituents); | | |
| 2732 | }, | 2716 | }, |
| 2733 | else => unreachable, | 2717 | else => unreachable, |
| 2734 | }; | 2718 | }; |
| ... | @@ -2801,8 +2785,9 @@ const DeclGen = struct { | ... | @@ -2801,8 +2785,9 @@ const DeclGen = struct { |
| 2801 | const lhs_id = try self.resolve(bin_op.lhs); | 2785 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2802 | const rhs_id = try self.resolve(bin_op.rhs); | 2786 | const rhs_id = try self.resolve(bin_op.rhs); |
| 2803 | const ty = self.typeOf(bin_op.lhs); | 2787 | const ty = self.typeOf(bin_op.lhs); |
| | 2788 | const result_ty = self.typeOfIndex(inst); |
| 2804 | | 2789 | |
| 2805 | return try self.cmp(op, ty, lhs_id, rhs_id); | 2790 | return try self.cmp(op, result_ty, ty, lhs_id, rhs_id); |
| 2806 | } | 2791 | } |
| 2807 | | 2792 | |
| 2808 | fn airVectorCmp(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2793 | fn airVectorCmp(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -2814,8 +2799,9 @@ const DeclGen = struct { | ... | @@ -2814,8 +2799,9 @@ const DeclGen = struct { |
| 2814 | const rhs_id = try self.resolve(vec_cmp.rhs); | 2799 | const rhs_id = try self.resolve(vec_cmp.rhs); |
| 2815 | const op = vec_cmp.compareOperator(); | 2800 | const op = vec_cmp.compareOperator(); |
| 2816 | const ty = self.typeOf(vec_cmp.lhs); | 2801 | const ty = self.typeOf(vec_cmp.lhs); |
| | 2802 | const result_ty = self.typeOfIndex(inst); |
| 2817 | | 2803 | |
| 2818 | return try self.cmp(op, ty, lhs_id, rhs_id); | 2804 | return try self.cmp(op, result_ty, ty, lhs_id, rhs_id); |
| 2819 | } | 2805 | } |
| 2820 | | 2806 | |
| 2821 | fn bitCast( | 2807 | fn bitCast( |
| ... | @@ -2860,15 +2846,9 @@ const DeclGen = struct { | ... | @@ -2860,15 +2846,9 @@ const DeclGen = struct { |
| 2860 | return result_id; | 2846 | return result_id; |
| 2861 | } | 2847 | } |
| 2862 | | 2848 | |
| 2863 | const src_ptr_ty_ref = try self.spv.ptrType(src_ty_ref, .Function); | 2849 | const dst_ptr_ty_ref = try self.ptrType(dst_ty, .Function); |
| 2864 | const dst_ptr_ty_ref = try self.spv.ptrType(dst_ty_ref, .Function); | | |
| 2865 | | 2850 | |
| 2866 | const tmp_id = self.spv.allocId(); | 2851 | const tmp_id = try self.alloc(src_ty, .{ .storage_class = .Function }); |
| 2867 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ | | |
| 2868 | .id_result_type = self.typeId(src_ptr_ty_ref), | | |
| 2869 | .id_result = tmp_id, | | |
| 2870 | .storage_class = .Function, | | |
| 2871 | }); | | |
| 2872 | try self.store(src_ty, tmp_id, src_id, false); | 2852 | try self.store(src_ty, tmp_id, src_id, false); |
| 2873 | const casted_ptr_id = self.spv.allocId(); | 2853 | const casted_ptr_id = self.spv.allocId(); |
| 2874 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ | 2854 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| ... | @@ -3154,7 +3134,7 @@ const DeclGen = struct { | ... | @@ -3154,7 +3134,7 @@ const DeclGen = struct { |
| 3154 | elem_ids[n_elems - 1] = try self.constant(array_info.elem_type, sentinel_val, .indirect); | 3134 | elem_ids[n_elems - 1] = try self.constant(array_info.elem_type, sentinel_val, .indirect); |
| 3155 | } | 3135 | } |
| 3156 | | 3136 | |
| 3157 | return try self.constructArray(result_ty_ref, elem_ids); | 3137 | return try self.constructArray(result_ty, elem_ids); |
| 3158 | }, | 3138 | }, |
| 3159 | else => unreachable, | 3139 | else => unreachable, |
| 3160 | } | 3140 | } |
| ... | @@ -3246,8 +3226,7 @@ const DeclGen = struct { | ... | @@ -3246,8 +3226,7 @@ const DeclGen = struct { |
| 3246 | const mod = self.module; | 3226 | const mod = self.module; |
| 3247 | // Construct new pointer type for the resulting pointer | 3227 | // Construct new pointer type for the resulting pointer |
| 3248 | const elem_ty = ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. | 3228 | const elem_ty = ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. |
| 3249 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); | 3229 | const elem_ptr_ty_ref = try self.ptrType(elem_ty, spvStorageClass(ptr_ty.ptrAddressSpace(mod))); |
| 3250 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(ptr_ty.ptrAddressSpace(mod))); | | |
| 3251 | if (ptr_ty.isSinglePointer(mod)) { | 3230 | if (ptr_ty.isSinglePointer(mod)) { |
| 3252 | // Pointer-to-array. In this case, the resulting pointer is not of the same type | 3231 | // Pointer-to-array. In this case, the resulting pointer is not of the same type |
| 3253 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. | 3232 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. |
| ... | @@ -3283,9 +3262,7 @@ const DeclGen = struct { | ... | @@ -3283,9 +3262,7 @@ const DeclGen = struct { |
| 3283 | const mod = self.module; | 3262 | const mod = self.module; |
| 3284 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 3263 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3285 | const array_ty = self.typeOf(bin_op.lhs); | 3264 | const array_ty = self.typeOf(bin_op.lhs); |
| 3286 | const array_ty_ref = try self.resolveType(array_ty, .direct); | | |
| 3287 | const elem_ty = array_ty.childType(mod); | 3265 | const elem_ty = array_ty.childType(mod); |
| 3288 | const elem_ty_ref = try self.resolveType(elem_ty, .indirect); | | |
| 3289 | const array_id = try self.resolve(bin_op.lhs); | 3266 | const array_id = try self.resolve(bin_op.lhs); |
| 3290 | const index_id = try self.resolve(bin_op.rhs); | 3267 | const index_id = try self.resolve(bin_op.rhs); |
| 3291 | | 3268 | |
| ... | @@ -3293,20 +3270,10 @@ const DeclGen = struct { | ... | @@ -3293,20 +3270,10 @@ const DeclGen = struct { |
| 3293 | // For now, just generate a temporary and use that. | 3270 | // For now, just generate a temporary and use that. |
| 3294 | // TODO: This backend probably also should use isByRef from llvm... | 3271 | // TODO: This backend probably also should use isByRef from llvm... |
| 3295 | | 3272 | |
| 3296 | const array_ptr_ty_ref = try self.spv.ptrType(array_ty_ref, .Function); | 3273 | const elem_ptr_ty_ref = try self.ptrType(elem_ty, .Function); |
| 3297 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, .Function); | | |
| 3298 | | | |
| 3299 | const tmp_id = self.spv.allocId(); | | |
| 3300 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ | | |
| 3301 | .id_result_type = self.typeId(array_ptr_ty_ref), | | |
| 3302 | .id_result = tmp_id, | | |
| 3303 | .storage_class = .Function, | | |
| 3304 | }); | | |
| 3305 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | | |
| 3306 | .pointer = tmp_id, | | |
| 3307 | .object = array_id, | | |
| 3308 | }); | | |
| 3309 | | 3274 | |
| | 3275 | const tmp_id = try self.alloc(array_ty, .{ .storage_class = .Function }); |
| | 3276 | try self.store(array_ty, tmp_id, array_id, false); |
| 3310 | const elem_ptr_id = try self.accessChainId(elem_ptr_ty_ref, tmp_id, &.{index_id}); | 3277 | const elem_ptr_id = try self.accessChainId(elem_ptr_ty_ref, tmp_id, &.{index_id}); |
| 3311 | return try self.load(elem_ty, elem_ptr_id, false); | 3278 | return try self.load(elem_ty, elem_ptr_id, false); |
| 3312 | } | 3279 | } |
| ... | @@ -3334,8 +3301,7 @@ const DeclGen = struct { | ... | @@ -3334,8 +3301,7 @@ const DeclGen = struct { |
| 3334 | if (layout.tag_size == 0) return; | 3301 | if (layout.tag_size == 0) return; |
| 3335 | | 3302 | |
| 3336 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; | 3303 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; |
| 3337 | const tag_ty_ref = try self.resolveType(tag_ty, .indirect); | 3304 | const tag_ptr_ty_ref = try self.ptrType(tag_ty, spvStorageClass(un_ptr_ty.ptrAddressSpace(mod))); |
| 3338 | const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, spvStorageClass(un_ptr_ty.ptrAddressSpace(mod))); | | |
| 3339 | | 3305 | |
| 3340 | const union_ptr_id = try self.resolve(bin_op.lhs); | 3306 | const union_ptr_id = try self.resolve(bin_op.lhs); |
| 3341 | const new_tag_id = try self.resolve(bin_op.rhs); | 3307 | const new_tag_id = try self.resolve(bin_op.rhs); |
| ... | @@ -3400,6 +3366,7 @@ const DeclGen = struct { | ... | @@ -3400,6 +3366,7 @@ const DeclGen = struct { |
| 3400 | return try self.constInt(tag_ty_ref, tag_int); | 3366 | return try self.constInt(tag_ty_ref, tag_int); |
| 3401 | } | 3367 | } |
| 3402 | | 3368 | |
| | 3369 | // TODO: Make this use self.ptrType |
| 3403 | const un_active_ty_ref = try self.resolveUnionType(ty, active_field); | 3370 | const un_active_ty_ref = try self.resolveUnionType(ty, active_field); |
| 3404 | const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); | 3371 | const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); |
| 3405 | const un_general_ty_ref = try self.resolveType(ty, .direct); | 3372 | const un_general_ty_ref = try self.resolveType(ty, .direct); |
| ... | @@ -3414,23 +3381,16 @@ const DeclGen = struct { | ... | @@ -3414,23 +3381,16 @@ const DeclGen = struct { |
| 3414 | | 3381 | |
| 3415 | if (layout.tag_size != 0) { | 3382 | if (layout.tag_size != 0) { |
| 3416 | const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct); | 3383 | const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct); |
| 3417 | const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); | 3384 | const tag_ptr_ty_ref = try self.ptrType(maybe_tag_ty.?, .Function); |
| 3418 | const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))}); | 3385 | const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))}); |
| 3419 | const tag_id = try self.constInt(tag_ty_ref, tag_int); | 3386 | const tag_id = try self.constInt(tag_ty_ref, tag_int); |
| 3420 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 3387 | try self.store(maybe_tag_ty.?, ptr_id, tag_id, false); |
| 3421 | .pointer = ptr_id, | | |
| 3422 | .object = tag_id, | | |
| 3423 | }); | | |
| 3424 | } | 3388 | } |
| 3425 | | 3389 | |
| 3426 | if (layout.active_field_size != 0) { | 3390 | if (layout.active_field_size != 0) { |
| 3427 | const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); | 3391 | const active_field_ptr_ty_ref = try self.ptrType(layout.active_field_ty, .Function); |
| 3428 | const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); | | |
| 3429 | const ptr_id = try self.accessChain(active_field_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.active_field_index))}); | 3392 | const ptr_id = try self.accessChain(active_field_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.active_field_index))}); |
| 3430 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 3393 | try self.store(layout.active_field_ty, ptr_id, payload.?, false); |
| 3431 | .pointer = ptr_id, | | |
| 3432 | .object = payload.?, | | |
| 3433 | }); | | |
| 3434 | } else { | 3394 | } else { |
| 3435 | assert(payload == null); | 3395 | assert(payload == null); |
| 3436 | } | 3396 | } |
| ... | @@ -3603,23 +3563,13 @@ const DeclGen = struct { | ... | @@ -3603,23 +3563,13 @@ const DeclGen = struct { |
| 3603 | return try self.structFieldPtr(result_ptr_ty, struct_ptr_ty, struct_ptr, field_index); | 3563 | return try self.structFieldPtr(result_ptr_ty, struct_ptr_ty, struct_ptr, field_index); |
| 3604 | } | 3564 | } |
| 3605 | | 3565 | |
| 3606 | /// We cannot use an OpVariable directly in an OpSpecConstantOp, but we can | 3566 | const AllocOptions = struct { |
| 3607 | /// after we insert a dummy AccessChain... | 3567 | initializer: ?IdRef = null, |
| 3608 | /// TODO: Get rid of this | 3568 | /// The final storage class of the pointer. This may be either `.Generic` or `.Function`. |
| 3609 | fn makePointerConstant( | 3569 | /// In either case, the local is allocated in the `.Function` storage class, and optionally |
| 3610 | self: *DeclGen, | 3570 | /// cast back to `.Generic`. |
| 3611 | section: *SpvSection, | 3571 | storage_class: StorageClass = .Generic, |
| 3612 | ptr_ty_ref: CacheRef, | 3572 | }; |
| 3613 | ptr_id: IdRef, | | |
| 3614 | ) !IdRef { | | |
| 3615 | const result_id = self.spv.allocId(); | | |
| 3616 | try section.emitSpecConstantOp(self.spv.gpa, .OpInBoundsAccessChain, .{ | | |
| 3617 | .id_result_type = self.typeId(ptr_ty_ref), | | |
| 3618 | .id_result = result_id, | | |
| 3619 | .base = ptr_id, | | |
| 3620 | }); | | |
| 3621 | return result_id; | | |
| 3622 | } | | |
| 3623 | | 3573 | |
| 3624 | // Allocate a function-local variable, with possible initializer. | 3574 | // Allocate a function-local variable, with possible initializer. |
| 3625 | // This function returns a pointer to a variable of type `ty_ref`, | 3575 | // This function returns a pointer to a variable of type `ty_ref`, |
| ... | @@ -3627,30 +3577,36 @@ const DeclGen = struct { | ... | @@ -3627,30 +3577,36 @@ const DeclGen = struct { |
| 3627 | // placed in the Function address space. | 3577 | // placed in the Function address space. |
| 3628 | fn alloc( | 3578 | fn alloc( |
| 3629 | self: *DeclGen, | 3579 | self: *DeclGen, |
| 3630 | ty_ref: CacheRef, | 3580 | ty: Type, |
| 3631 | initializer: ?IdRef, | 3581 | options: AllocOptions, |
| 3632 | ) !IdRef { | 3582 | ) !IdRef { |
| 3633 | const fn_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Function); | 3583 | const ptr_fn_ty_ref = try self.ptrType(ty, .Function); |
| 3634 | const general_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Generic); | | |
| 3635 | | 3584 | |
| 3636 | // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to | 3585 | // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to |
| 3637 | // directly generate them into func.prologue instead of the body. | 3586 | // directly generate them into func.prologue instead of the body. |
| 3638 | const var_id = self.spv.allocId(); | 3587 | const var_id = self.spv.allocId(); |
| 3639 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ | 3588 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| 3640 | .id_result_type = self.typeId(fn_ptr_ty_ref), | 3589 | .id_result_type = self.typeId(ptr_fn_ty_ref), |
| 3641 | .id_result = var_id, | 3590 | .id_result = var_id, |
| 3642 | .storage_class = .Function, | 3591 | .storage_class = .Function, |
| 3643 | .initializer = initializer, | 3592 | .initializer = options.initializer, |
| 3644 | }); | 3593 | }); |
| 3645 | | 3594 | |
| 3646 | // Convert to a generic pointer | 3595 | switch (options.storage_class) { |
| 3647 | const result_id = self.spv.allocId(); | 3596 | .Generic => { |
| 3648 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ | 3597 | const ptr_gn_ty_ref = try self.ptrType(ty, .Generic); |
| 3649 | .id_result_type = self.typeId(general_ptr_ty_ref), | 3598 | // Convert to a generic pointer |
| 3650 | .id_result = result_id, | 3599 | const result_id = self.spv.allocId(); |
| 3651 | .pointer = var_id, | 3600 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| 3652 | }); | 3601 | .id_result_type = self.typeId(ptr_gn_ty_ref), |
| 3653 | return result_id; | 3602 | .id_result = result_id, |
| | 3603 | .pointer = var_id, |
| | 3604 | }); |
| | 3605 | return result_id; |
| | 3606 | }, |
| | 3607 | .Function => return var_id, |
| | 3608 | else => unreachable, |
| | 3609 | } |
| 3654 | } | 3610 | } |
| 3655 | | 3611 | |
| 3656 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3612 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3659,8 +3615,7 @@ const DeclGen = struct { | ... | @@ -3659,8 +3615,7 @@ const DeclGen = struct { |
| 3659 | const ptr_ty = self.typeOfIndex(inst); | 3615 | const ptr_ty = self.typeOfIndex(inst); |
| 3660 | assert(ptr_ty.ptrAddressSpace(mod) == .generic); | 3616 | assert(ptr_ty.ptrAddressSpace(mod) == .generic); |
| 3661 | const child_ty = ptr_ty.childType(mod); | 3617 | const child_ty = ptr_ty.childType(mod); |
| 3662 | const child_ty_ref = try self.resolveType(child_ty, .indirect); | 3618 | return try self.alloc(child_ty, .{}); |
| 3663 | return try self.alloc(child_ty_ref, null); | | |
| 3664 | } | 3619 | } |
| 3665 | | 3620 | |
| 3666 | fn airArg(self: *DeclGen) IdRef { | 3621 | fn airArg(self: *DeclGen) IdRef { |
| ... | @@ -4032,7 +3987,7 @@ const DeclGen = struct { | ... | @@ -4032,7 +3987,7 @@ const DeclGen = struct { |
| 4032 | .is_null => .eq, | 3987 | .is_null => .eq, |
| 4033 | .is_non_null => .neq, | 3988 | .is_non_null => .neq, |
| 4034 | }; | 3989 | }; |
| 4035 | return try self.cmp(op, ptr_ty, ptr_id, null_id); | 3990 | return try self.cmp(op, Type.bool, ptr_ty, ptr_id, null_id); |
| 4036 | } | 3991 | } |
| 4037 | | 3992 | |
| 4038 | const is_non_null_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) | 3993 | const is_non_null_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) |