authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-21 12:53:13+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-21 17:46:50+02:00
log200bca360e333abeb29f4af6d050adf42c2ca5a7
treefed7782d93a84b7b0bfa53d200b1ce25538cb20d
parentb403ca0aabb4529949b48e68f1392afc31098a98
signaturebadge-check Signed by SSH key SHA256:CQ99aPxq+RueiL9u7z0FEki5Fm7V6T8q4PrEGmINrA4

spirv: replace most use of spv.ptrType with self.ptrType

To support self-referential pointers, in the future we will need to pass the Zig type to any pointer that is created. This lays some ground work for that by replacing most uses of spv.ptrType with a new ptrType function that also accepts the Zig type. This function's contents will soon be replaced by a version that also supports self-referential pointers. Also fixed some bugs regarding the use of direct/indirect.

1 files changed, 76 insertions(+), 121 deletions(-)

src/codegen/spirv.zig+76-121
...@@ -358,8 +358,7 @@ const DeclGen = struct {...@@ -358,8 +358,7 @@ const DeclGen = struct {
358358
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);
363362
364 const var_id = self.spv.declPtr(spv_decl_index).result_id;363 const var_id = self.spv.declPtr(spv_decl_index).result_id;
365364
...@@ -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/1349628 // 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 can630 // TODO: Make this OpCompositeConstruct when we can
632 // TODO: Make this Function storage type631 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 }
660644
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 }
859843
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 else880 else
897 null;881 null;
898882
...@@ -934,8 +918,7 @@ const DeclGen = struct {...@@ -934,8 +918,7 @@ const DeclGen = struct {
934918
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)));
939922
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 };
993976
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);
997979
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 {
10491031
1050 const final_storage_class = spvStorageClass(decl.@"addrspace");1032 const final_storage_class = spvStorageClass(decl.@"addrspace");
10511033
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);
10541035
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 }
11201101
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 greater1108 /// 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), will1109 /// 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);
16831670
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 };
18191807
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);
18221809
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 }
21152102
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 }
21202105
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 {
21762161
2177 const info = try self.arithmeticTypeInfo(result_ty);2162 const info = try self.arithmeticTypeInfo(result_ty);
2178 // TODO: Use fmin for OpenCL2163 // 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 }
23132298
2314 return self.constructArray(result_ty_ref, constituents);2299 return self.constructArray(ty, constituents);
2315 }2300 }
23162301
2317 // Binary operations are generally applicable to both scalar and vector operations2302 // 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 }
26742660
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 else2668 else
2683 try self.convertToDirect(Type.bool, rhs_id);2669 try self.convertToDirect(Type.bool, rhs_id);
26842670
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);
26952681
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);
26972683
2698 // op == .eq => lhs_valid == rhs_valid && lhs_pl == rhs_pl2684 // op == .eq => lhs_valid == rhs_valid && lhs_pl == rhs_pl
2699 // op == .neq => lhs_valid != rhs_valid || lhs_pl != rhs_pl2685 // 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);
27192704
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 }
27292714
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);
28042789
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 }
28072792
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);
28172803
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 }
28202806
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 }
28622848
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);
28652850
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 }
31563136
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 pointer3227 // 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 type3231 // 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);
32913268
...@@ -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...
32953272
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 });
33093274
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;
33353302
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)));
33393305
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 }
34023368
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 {
34143381
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 }
34253389
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 }
36053565
3606 /// We cannot use an OpVariable directly in an OpSpecConstantOp, but we can3566 const AllocOptions = struct {
3607 /// after we insert a dummy AccessChain...3567 initializer: ?IdRef = null,
3608 /// TODO: Get rid of this3568 /// 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 }
36233573
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);
36353584
3636 // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to3585 // 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 });
36453594
3646 // Convert to a generic pointer3595 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 }
36553611
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 }
36653620
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 }
40373992
4038 const is_non_null_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod))3993 const is_non_null_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod))