| ... | @@ -451,12 +451,12 @@ const DeclGen = struct { | ... | @@ -451,12 +451,12 @@ const DeclGen = struct { |
| 451 | const spv_decl_index = blk: { | 451 | const spv_decl_index = blk: { |
| 452 | const entry = try self.object.anon_decl_link.getOrPut(self.object.gpa, .{ val, storage_class }); | 452 | const entry = try self.object.anon_decl_link.getOrPut(self.object.gpa, .{ val, storage_class }); |
| 453 | if (entry.found_existing) { | 453 | if (entry.found_existing) { |
| 454 | try self.func.decl_deps.put(self.spv.gpa, entry.value_ptr.*, {}); | 454 | try self.addFunctionDep(entry.value_ptr.*, storage_class); |
| 455 | return self.spv.declPtr(entry.value_ptr.*).result_id; | 455 | return self.spv.declPtr(entry.value_ptr.*).result_id; |
| 456 | } | 456 | } |
| 457 | | 457 | |
| 458 | const spv_decl_index = try self.spv.allocDecl(.global); | 458 | const spv_decl_index = try self.spv.allocDecl(.global); |
| 459 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); | 459 | try self.addFunctionDep(spv_decl_index, storage_class); |
| 460 | entry.value_ptr.* = spv_decl_index; | 460 | entry.value_ptr.* = spv_decl_index; |
| 461 | break :blk spv_decl_index; | 461 | break :blk spv_decl_index; |
| 462 | }; | 462 | }; |
| ... | @@ -529,6 +529,37 @@ const DeclGen = struct { | ... | @@ -529,6 +529,37 @@ const DeclGen = struct { |
| 529 | return var_id; | 529 | return var_id; |
| 530 | } | 530 | } |
| 531 | | 531 | |
| | 532 | fn addFunctionDep(self: *DeclGen, decl_index: SpvModule.Decl.Index, storage_class: StorageClass) !void { |
| | 533 | const target = self.getTarget(); |
| | 534 | if (target.os.tag == .vulkan) { |
| | 535 | // Shader entry point dependencies must be variables with Input or Output storage class |
| | 536 | switch (storage_class) { |
| | 537 | .Input, .Output => { |
| | 538 | try self.func.decl_deps.put(self.spv.gpa, decl_index, {}); |
| | 539 | }, |
| | 540 | else => {}, |
| | 541 | } |
| | 542 | } else { |
| | 543 | try self.func.decl_deps.put(self.spv.gpa, decl_index, {}); |
| | 544 | } |
| | 545 | } |
| | 546 | |
| | 547 | fn castToGeneric(self: *DeclGen, type_id: IdRef, ptr_id: IdRef) !IdRef { |
| | 548 | const target = self.getTarget(); |
| | 549 | |
| | 550 | if (target.os.tag == .vulkan) { |
| | 551 | return ptr_id; |
| | 552 | } else { |
| | 553 | const result_id = self.spv.allocId(); |
| | 554 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| | 555 | .id_result_type = type_id, |
| | 556 | .id_result = result_id, |
| | 557 | .pointer = ptr_id, |
| | 558 | }); |
| | 559 | return result_id; |
| | 560 | } |
| | 561 | } |
| | 562 | |
| 532 | /// Start a new SPIR-V block, Emits the label of the new block, and stores which | 563 | /// Start a new SPIR-V block, Emits the label of the new block, and stores which |
| 533 | /// block we are currently generating. | 564 | /// block we are currently generating. |
| 534 | /// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to | 565 | /// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to |
| ... | @@ -713,6 +744,30 @@ const DeclGen = struct { | ... | @@ -713,6 +744,30 @@ const DeclGen = struct { |
| 713 | return try self.load(ty, ptr_composite_id, .{}); | 744 | return try self.load(ty, ptr_composite_id, .{}); |
| 714 | } | 745 | } |
| 715 | | 746 | |
| | 747 | /// Construct a vector at runtime. |
| | 748 | /// ty must be an vector type. |
| | 749 | /// Constituents should be in `indirect` representation (as the elements of an vector should be). |
| | 750 | /// Result is in `direct` representation. |
| | 751 | fn constructVector(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| | 752 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| | 753 | // operands are not constant. |
| | 754 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| | 755 | // For now, just initialize the struct by setting the fields manually... |
| | 756 | // TODO: Make this OpCompositeConstruct when we can |
| | 757 | const mod = self.module; |
| | 758 | const ptr_composite_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| | 759 | const ptr_elem_ty_ref = try self.ptrType(ty.elemType2(mod), .Function); |
| | 760 | for (constituents, 0..) |constitent_id, index| { |
| | 761 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| | 762 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| | 763 | .pointer = ptr_id, |
| | 764 | .object = constitent_id, |
| | 765 | }); |
| | 766 | } |
| | 767 | |
| | 768 | return try self.load(ty, ptr_composite_id, .{}); |
| | 769 | } |
| | 770 | |
| 716 | /// Construct an array at runtime. | 771 | /// Construct an array at runtime. |
| 717 | /// ty must be an array type. | 772 | /// ty must be an array type. |
| 718 | /// Constituents should be in `indirect` representation (as the elements of an array should be). | 773 | /// Constituents should be in `indirect` representation (as the elements of an array should be). |
| ... | @@ -932,13 +987,16 @@ const DeclGen = struct { | ... | @@ -932,13 +987,16 @@ const DeclGen = struct { |
| 932 | } | 987 | } |
| 933 | | 988 | |
| 934 | switch (tag) { | 989 | switch (tag) { |
| 935 | inline .array_type => if (array_type.sentinel != .none) { | 990 | inline .array_type => { |
| 936 | constituents[constituents.len - 1] = try self.constant(elem_ty, Value.fromInterned(array_type.sentinel), .indirect); | 991 | if (array_type.sentinel != .none) { |
| | 992 | const sentinel = Value.fromInterned(array_type.sentinel); |
| | 993 | constituents[constituents.len - 1] = try self.constant(elem_ty, sentinel, .indirect); |
| | 994 | } |
| | 995 | return self.constructArray(ty, constituents); |
| 937 | }, | 996 | }, |
| 938 | else => {}, | 997 | inline .vector_type => return self.constructVector(ty, constituents), |
| | 998 | else => unreachable, |
| 939 | } | 999 | } |
| 940 | | | |
| 941 | return try self.constructArray(ty, constituents); | | |
| 942 | }, | 1000 | }, |
| 943 | .struct_type => { | 1001 | .struct_type => { |
| 944 | const struct_type = mod.typeToStruct(ty).?; | 1002 | const struct_type = mod.typeToStruct(ty).?; |
| ... | @@ -1019,7 +1077,7 @@ const DeclGen = struct { | ... | @@ -1019,7 +1077,7 @@ const DeclGen = struct { |
| 1019 | | 1077 | |
| 1020 | // TODO: Can we consolidate this in ptrElemPtr? | 1078 | // TODO: Can we consolidate this in ptrElemPtr? |
| 1021 | const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. | 1079 | const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. |
| 1022 | const elem_ptr_ty_ref = try self.ptrType(elem_ty, spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod))); | 1080 | const elem_ptr_ty_ref = try self.ptrType(elem_ty, self.spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod))); |
| 1023 | | 1081 | |
| 1024 | if (elem_ptr_ty_ref == result_ty_ref) { | 1082 | if (elem_ptr_ty_ref == result_ty_ref) { |
| 1025 | return elem_ptr_id; | 1083 | return elem_ptr_id; |
| ... | @@ -1074,7 +1132,7 @@ const DeclGen = struct { | ... | @@ -1074,7 +1132,7 @@ const DeclGen = struct { |
| 1074 | unreachable; // TODO | 1132 | unreachable; // TODO |
| 1075 | } | 1133 | } |
| 1076 | | 1134 | |
| 1077 | const final_storage_class = spvStorageClass(ty.ptrAddressSpace(mod)); | 1135 | const final_storage_class = self.spvStorageClass(ty.ptrAddressSpace(mod)); |
| 1078 | const actual_storage_class = switch (final_storage_class) { | 1136 | const actual_storage_class = switch (final_storage_class) { |
| 1079 | .Generic => .CrossWorkgroup, | 1137 | .Generic => .CrossWorkgroup, |
| 1080 | else => |other| other, | 1138 | else => |other| other, |
| ... | @@ -1084,15 +1142,7 @@ const DeclGen = struct { | ... | @@ -1084,15 +1142,7 @@ const DeclGen = struct { |
| 1084 | const decl_ptr_ty_ref = try self.ptrType(decl_ty, final_storage_class); | 1142 | const decl_ptr_ty_ref = try self.ptrType(decl_ty, final_storage_class); |
| 1085 | | 1143 | |
| 1086 | const ptr_id = switch (final_storage_class) { | 1144 | const ptr_id = switch (final_storage_class) { |
| 1087 | .Generic => blk: { | 1145 | .Generic => try self.castToGeneric(self.typeId(decl_ptr_ty_ref), decl_id), |
| 1088 | const result_id = self.spv.allocId(); | | |
| 1089 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ | | |
| 1090 | .id_result_type = self.typeId(decl_ptr_ty_ref), | | |
| 1091 | .id_result = result_id, | | |
| 1092 | .pointer = decl_id, | | |
| 1093 | }); | | |
| 1094 | break :blk result_id; | | |
| 1095 | }, | | |
| 1096 | else => decl_id, | 1146 | else => decl_id, |
| 1097 | }; | 1147 | }; |
| 1098 | | 1148 | |
| ... | @@ -1115,6 +1165,7 @@ const DeclGen = struct { | ... | @@ -1115,6 +1165,7 @@ const DeclGen = struct { |
| 1115 | const ty_ref = try self.resolveType(ty, .direct); | 1165 | const ty_ref = try self.resolveType(ty, .direct); |
| 1116 | const ty_id = self.typeId(ty_ref); | 1166 | const ty_id = self.typeId(ty_ref); |
| 1117 | const decl = mod.declPtr(decl_index); | 1167 | const decl = mod.declPtr(decl_index); |
| | 1168 | |
| 1118 | switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { | 1169 | switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { |
| 1119 | .func => { | 1170 | .func => { |
| 1120 | // TODO: Properly lower function pointers. For now we are going to hack around it and | 1171 | // TODO: Properly lower function pointers. For now we are going to hack around it and |
| ... | @@ -1133,23 +1184,13 @@ const DeclGen = struct { | ... | @@ -1133,23 +1184,13 @@ const DeclGen = struct { |
| 1133 | const spv_decl_index = try self.object.resolveDecl(mod, decl_index); | 1184 | const spv_decl_index = try self.object.resolveDecl(mod, decl_index); |
| 1134 | | 1185 | |
| 1135 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; | 1186 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| 1136 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); | 1187 | const final_storage_class = self.spvStorageClass(decl.@"addrspace"); |
| 1137 | | 1188 | try self.addFunctionDep(spv_decl_index, final_storage_class); |
| 1138 | const final_storage_class = spvStorageClass(decl.@"addrspace"); | | |
| 1139 | | 1189 | |
| 1140 | const decl_ptr_ty_ref = try self.ptrType(decl.ty, final_storage_class); | 1190 | const decl_ptr_ty_ref = try self.ptrType(decl.ty, final_storage_class); |
| 1141 | | 1191 | |
| 1142 | const ptr_id = switch (final_storage_class) { | 1192 | const ptr_id = switch (final_storage_class) { |
| 1143 | .Generic => blk: { | 1193 | .Generic => try self.castToGeneric(self.typeId(decl_ptr_ty_ref), decl_id), |
| 1144 | // Pointer should be Generic, but is actually placed in CrossWorkgroup. | | |
| 1145 | const result_id = self.spv.allocId(); | | |
| 1146 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ | | |
| 1147 | .id_result_type = self.typeId(decl_ptr_ty_ref), | | |
| 1148 | .id_result = result_id, | | |
| 1149 | .pointer = decl_id, | | |
| 1150 | }); | | |
| 1151 | break :blk result_id; | | |
| 1152 | }, | | |
| 1153 | else => decl_id, | 1194 | else => decl_id, |
| 1154 | }; | 1195 | }; |
| 1155 | | 1196 | |
| ... | @@ -1195,8 +1236,12 @@ const DeclGen = struct { | ... | @@ -1195,8 +1236,12 @@ const DeclGen = struct { |
| 1195 | // An array of largestSupportedIntBits. | 1236 | // An array of largestSupportedIntBits. |
| 1196 | return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits }); | 1237 | return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits }); |
| 1197 | }; | 1238 | }; |
| | 1239 | |
| 1198 | // Kernel only supports unsigned ints. | 1240 | // Kernel only supports unsigned ints. |
| 1199 | // TODO: Only do this with Kernels | 1241 | if (self.getTarget().os.tag == .vulkan) { |
| | 1242 | return self.spv.intType(signedness, backing_bits); |
| | 1243 | } |
| | 1244 | |
| 1200 | return self.spv.intType(.unsigned, backing_bits); | 1245 | return self.spv.intType(.unsigned, backing_bits); |
| 1201 | } | 1246 | } |
| 1202 | | 1247 | |
| ... | @@ -1453,7 +1498,7 @@ const DeclGen = struct { | ... | @@ -1453,7 +1498,7 @@ const DeclGen = struct { |
| 1453 | // Note: Don't cache this pointer type, it would mess up the recursive pointer functionality | 1498 | // Note: Don't cache this pointer type, it would mess up the recursive pointer functionality |
| 1454 | // in ptrType()! | 1499 | // in ptrType()! |
| 1455 | | 1500 | |
| 1456 | const storage_class = spvStorageClass(ptr_info.flags.address_space); | 1501 | const storage_class = self.spvStorageClass(ptr_info.flags.address_space); |
| 1457 | const ptr_ty_ref = try self.ptrType(Type.fromInterned(ptr_info.child), storage_class); | 1502 | const ptr_ty_ref = try self.ptrType(Type.fromInterned(ptr_info.child), storage_class); |
| 1458 | | 1503 | |
| 1459 | if (ptr_info.flags.size != .Slice) { | 1504 | if (ptr_info.flags.size != .Slice) { |
| ... | @@ -1474,8 +1519,14 @@ const DeclGen = struct { | ... | @@ -1474,8 +1519,14 @@ const DeclGen = struct { |
| 1474 | | 1519 | |
| 1475 | const elem_ty = ty.childType(mod); | 1520 | const elem_ty = ty.childType(mod); |
| 1476 | const elem_ty_ref = try self.resolveType(elem_ty, .indirect); | 1521 | const elem_ty_ref = try self.resolveType(elem_ty, .indirect); |
| | 1522 | const len = ty.vectorLen(mod); |
| | 1523 | const is_scalar = elem_ty.isNumeric(mod) or elem_ty.toIntern() == .bool_type; |
| | 1524 | |
| | 1525 | const ty_ref = if (is_scalar and len > 1 and len <= 4) |
| | 1526 | try self.spv.vectorType(ty.vectorLen(mod), elem_ty_ref) |
| | 1527 | else |
| | 1528 | try self.spv.arrayType(ty.vectorLen(mod), elem_ty_ref); |
| 1477 | | 1529 | |
| 1478 | const ty_ref = try self.spv.arrayType(ty.vectorLen(mod), elem_ty_ref); | | |
| 1479 | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); | 1530 | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); |
| 1480 | return ty_ref; | 1531 | return ty_ref; |
| 1481 | }, | 1532 | }, |
| ... | @@ -1634,13 +1685,20 @@ const DeclGen = struct { | ... | @@ -1634,13 +1685,20 @@ const DeclGen = struct { |
| 1634 | } | 1685 | } |
| 1635 | } | 1686 | } |
| 1636 | | 1687 | |
| 1637 | fn spvStorageClass(as: std.builtin.AddressSpace) StorageClass { | 1688 | fn spvStorageClass(self: *DeclGen, as: std.builtin.AddressSpace) StorageClass { |
| | 1689 | const target = self.getTarget(); |
| 1638 | return switch (as) { | 1690 | return switch (as) { |
| 1639 | .generic => .Generic, | 1691 | .generic => switch (target.os.tag) { |
| | 1692 | .vulkan => .Private, |
| | 1693 | else => .Generic, |
| | 1694 | }, |
| 1640 | .shared => .Workgroup, | 1695 | .shared => .Workgroup, |
| 1641 | .local => .Private, | 1696 | .local => .Private, |
| 1642 | .global => .CrossWorkgroup, | 1697 | .global => .CrossWorkgroup, |
| 1643 | .constant => .UniformConstant, | 1698 | .constant => .UniformConstant, |
| | 1699 | .input => .Input, |
| | 1700 | .output => .Output, |
| | 1701 | .uniform => .Uniform, |
| 1644 | .gs, | 1702 | .gs, |
| 1645 | .fs, | 1703 | .fs, |
| 1646 | .ss, | 1704 | .ss, |
| ... | @@ -1920,7 +1978,7 @@ const DeclGen = struct { | ... | @@ -1920,7 +1978,7 @@ const DeclGen = struct { |
| 1920 | // point name is the same as a different OpName. | 1978 | // point name is the same as a different OpName. |
| 1921 | const test_name = try std.fmt.allocPrint(self.gpa, "test {s}", .{name}); | 1979 | const test_name = try std.fmt.allocPrint(self.gpa, "test {s}", .{name}); |
| 1922 | defer self.gpa.free(test_name); | 1980 | defer self.gpa.free(test_name); |
| 1923 | try self.spv.declareEntryPoint(spv_decl_index, test_name); | 1981 | try self.spv.declareEntryPoint(spv_decl_index, test_name, .Kernel); |
| 1924 | } | 1982 | } |
| 1925 | | 1983 | |
| 1926 | fn genDecl(self: *DeclGen) !void { | 1984 | fn genDecl(self: *DeclGen) !void { |
| ... | @@ -1928,6 +1986,7 @@ const DeclGen = struct { | ... | @@ -1928,6 +1986,7 @@ const DeclGen = struct { |
| 1928 | const ip = &mod.intern_pool; | 1986 | const ip = &mod.intern_pool; |
| 1929 | const decl = mod.declPtr(self.decl_index); | 1987 | const decl = mod.declPtr(self.decl_index); |
| 1930 | const spv_decl_index = try self.object.resolveDecl(mod, self.decl_index); | 1988 | const spv_decl_index = try self.object.resolveDecl(mod, self.decl_index); |
| | 1989 | const target = self.getTarget(); |
| 1931 | | 1990 | |
| 1932 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; | 1991 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| 1933 | | 1992 | |
| ... | @@ -1994,30 +2053,24 @@ const DeclGen = struct { | ... | @@ -1994,30 +2053,24 @@ const DeclGen = struct { |
| 1994 | try self.generateTestEntryPoint(fqn, spv_decl_index); | 2053 | try self.generateTestEntryPoint(fqn, spv_decl_index); |
| 1995 | } | 2054 | } |
| 1996 | } else { | 2055 | } else { |
| 1997 | const init_val = if (decl.val.getVariable(mod)) |payload| | 2056 | const opt_init_val: ?Value = blk: { |
| 1998 | Value.fromInterned(payload.init) | 2057 | if (decl.val.getVariable(mod)) |payload| { |
| 1999 | else | 2058 | if (payload.is_extern) break :blk null; |
| 2000 | decl.val; | 2059 | break :blk Value.fromInterned(payload.init); |
| 2001 | | 2060 | } |
| 2002 | if (init_val.ip_index == .unreachable_value) { | 2061 | break :blk decl.val; |
| 2003 | return self.todo("importing extern variables", .{}); | 2062 | }; |
| 2004 | } | | |
| 2005 | | | |
| 2006 | // Currently, initializers for CrossWorkgroup variables is not implemented | | |
| 2007 | // in Mesa. Therefore we generate an initialization kernel instead. | | |
| 2008 | | | |
| 2009 | const void_ty_ref = try self.resolveType(Type.void, .direct); | | |
| 2010 | | | |
| 2011 | const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{ | | |
| 2012 | .return_type = void_ty_ref, | | |
| 2013 | .parameters = &.{}, | | |
| 2014 | } }); | | |
| 2015 | | 2063 | |
| 2016 | // Generate the actual variable for the global... | 2064 | // Generate the actual variable for the global... |
| 2017 | const final_storage_class = spvStorageClass(decl.@"addrspace"); | 2065 | const final_storage_class = self.spvStorageClass(decl.@"addrspace"); |
| 2018 | const actual_storage_class = switch (final_storage_class) { | 2066 | const actual_storage_class = blk: { |
| 2019 | .Generic => .CrossWorkgroup, | 2067 | if (target.os.tag != .vulkan) { |
| 2020 | else => final_storage_class, | 2068 | break :blk switch (final_storage_class) { |
| | 2069 | .Generic => .CrossWorkgroup, |
| | 2070 | else => final_storage_class, |
| | 2071 | }; |
| | 2072 | } |
| | 2073 | break :blk final_storage_class; |
| 2021 | }; | 2074 | }; |
| 2022 | | 2075 | |
| 2023 | const ptr_ty_ref = try self.ptrType(decl.ty, actual_storage_class); | 2076 | const ptr_ty_ref = try self.ptrType(decl.ty, actual_storage_class); |
| ... | @@ -2028,37 +2081,51 @@ const DeclGen = struct { | ... | @@ -2028,37 +2081,51 @@ const DeclGen = struct { |
| 2028 | .id_result = decl_id, | 2081 | .id_result = decl_id, |
| 2029 | .storage_class = actual_storage_class, | 2082 | .storage_class = actual_storage_class, |
| 2030 | }); | 2083 | }); |
| | 2084 | const fqn = ip.stringToSlice(try decl.getFullyQualifiedName(self.module)); |
| | 2085 | try self.spv.debugName(decl_id, fqn); |
| 2031 | | 2086 | |
| 2032 | // Now emit the instructions that initialize the variable. | 2087 | if (opt_init_val) |init_val| { |
| 2033 | const initializer_id = self.spv.allocId(); | 2088 | // Currently, initializers for CrossWorkgroup variables is not implemented |
| 2034 | try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ | 2089 | // in Mesa. Therefore we generate an initialization kernel instead. |
| 2035 | .id_result_type = self.typeId(void_ty_ref), | 2090 | const void_ty_ref = try self.resolveType(Type.void, .direct); |
| 2036 | .id_result = initializer_id, | | |
| 2037 | .function_control = .{}, | | |
| 2038 | .function_type = self.typeId(initializer_proto_ty_ref), | | |
| 2039 | }); | | |
| 2040 | const root_block_id = self.spv.allocId(); | | |
| 2041 | try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{ | | |
| 2042 | .id_result = root_block_id, | | |
| 2043 | }); | | |
| 2044 | self.current_block_label = root_block_id; | | |
| 2045 | | 2091 | |
| 2046 | const val_id = try self.constant(decl.ty, init_val, .indirect); | 2092 | const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{ |
| 2047 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 2093 | .return_type = void_ty_ref, |
| 2048 | .pointer = decl_id, | 2094 | .parameters = &.{}, |
| 2049 | .object = val_id, | 2095 | } }); |
| 2050 | }); | 2096 | |
| | 2097 | // Now emit the instructions that initialize the variable. |
| | 2098 | const initializer_id = self.spv.allocId(); |
| | 2099 | try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ |
| | 2100 | .id_result_type = self.typeId(void_ty_ref), |
| | 2101 | .id_result = initializer_id, |
| | 2102 | .function_control = .{}, |
| | 2103 | .function_type = self.typeId(initializer_proto_ty_ref), |
| | 2104 | }); |
| | 2105 | const root_block_id = self.spv.allocId(); |
| | 2106 | try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{ |
| | 2107 | .id_result = root_block_id, |
| | 2108 | }); |
| | 2109 | self.current_block_label = root_block_id; |
| 2051 | | 2110 | |
| 2052 | // TODO: We should be able to get rid of this by now... | 2111 | const val_id = try self.constant(decl.ty, init_val, .indirect); |
| 2053 | self.spv.endGlobal(spv_decl_index, begin, decl_id, initializer_id); | 2112 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| | 2113 | .pointer = decl_id, |
| | 2114 | .object = val_id, |
| | 2115 | }); |
| 2054 | | 2116 | |
| 2055 | try self.func.body.emit(self.spv.gpa, .OpReturn, {}); | 2117 | // TODO: We should be able to get rid of this by now... |
| 2056 | try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); | 2118 | self.spv.endGlobal(spv_decl_index, begin, decl_id, initializer_id); |
| 2057 | try self.spv.addFunction(spv_decl_index, self.func); | | |
| 2058 | | 2119 | |
| 2059 | const fqn = ip.stringToSlice(try decl.getFullyQualifiedName(self.module)); | 2120 | try self.func.body.emit(self.spv.gpa, .OpReturn, {}); |
| 2060 | try self.spv.debugName(decl_id, fqn); | 2121 | try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); |
| 2061 | try self.spv.debugNameFmt(initializer_id, "initializer of {s}", .{fqn}); | 2122 | try self.spv.addFunction(spv_decl_index, self.func); |
| | 2123 | |
| | 2124 | try self.spv.debugNameFmt(initializer_id, "initializer of {s}", .{fqn}); |
| | 2125 | } else { |
| | 2126 | self.spv.endGlobal(spv_decl_index, begin, decl_id, null); |
| | 2127 | try self.spv.declareDeclDeps(spv_decl_index, &.{}); |
| | 2128 | } |
| 2062 | } | 2129 | } |
| 2063 | } | 2130 | } |
| 2064 | | 2131 | |
| ... | @@ -3654,7 +3721,19 @@ const DeclGen = struct { | ... | @@ -3654,7 +3721,19 @@ const DeclGen = struct { |
| 3654 | constituents[0..index], | 3721 | constituents[0..index], |
| 3655 | ); | 3722 | ); |
| 3656 | }, | 3723 | }, |
| 3657 | .Vector, .Array => { | 3724 | .Vector => { |
| | 3725 | const n_elems = result_ty.vectorLen(mod); |
| | 3726 | const elem_ids = try self.gpa.alloc(IdRef, n_elems); |
| | 3727 | defer self.gpa.free(elem_ids); |
| | 3728 | |
| | 3729 | for (elements, 0..) |element, i| { |
| | 3730 | const id = try self.resolve(element); |
| | 3731 | elem_ids[i] = try self.convertToIndirect(result_ty.childType(mod), id); |
| | 3732 | } |
| | 3733 | |
| | 3734 | return try self.constructVector(result_ty, elem_ids); |
| | 3735 | }, |
| | 3736 | .Array => { |
| 3658 | const array_info = result_ty.arrayInfo(mod); | 3737 | const array_info = result_ty.arrayInfo(mod); |
| 3659 | const n_elems: usize = @intCast(result_ty.arrayLenIncludingSentinel(mod)); | 3738 | const n_elems: usize = @intCast(result_ty.arrayLenIncludingSentinel(mod)); |
| 3660 | const elem_ids = try self.gpa.alloc(IdRef, n_elems); | 3739 | const elem_ids = try self.gpa.alloc(IdRef, n_elems); |
| ... | @@ -3761,7 +3840,7 @@ const DeclGen = struct { | ... | @@ -3761,7 +3840,7 @@ const DeclGen = struct { |
| 3761 | const mod = self.module; | 3840 | const mod = self.module; |
| 3762 | // Construct new pointer type for the resulting pointer | 3841 | // Construct new pointer type for the resulting pointer |
| 3763 | const elem_ty = ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. | 3842 | const elem_ty = ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. |
| 3764 | const elem_ptr_ty_ref = try self.ptrType(elem_ty, spvStorageClass(ptr_ty.ptrAddressSpace(mod))); | 3843 | const elem_ptr_ty_ref = try self.ptrType(elem_ty, self.spvStorageClass(ptr_ty.ptrAddressSpace(mod))); |
| 3765 | if (ptr_ty.isSinglePointer(mod)) { | 3844 | if (ptr_ty.isSinglePointer(mod)) { |
| 3766 | // Pointer-to-array. In this case, the resulting pointer is not of the same type | 3845 | // Pointer-to-array. In this case, the resulting pointer is not of the same type |
| 3767 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. | 3846 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. |
| ... | @@ -3835,7 +3914,7 @@ const DeclGen = struct { | ... | @@ -3835,7 +3914,7 @@ const DeclGen = struct { |
| 3835 | const vector_ty = vector_ptr_ty.childType(mod); | 3914 | const vector_ty = vector_ptr_ty.childType(mod); |
| 3836 | const scalar_ty = vector_ty.scalarType(mod); | 3915 | const scalar_ty = vector_ty.scalarType(mod); |
| 3837 | | 3916 | |
| 3838 | const storage_class = spvStorageClass(vector_ptr_ty.ptrAddressSpace(mod)); | 3917 | const storage_class = self.spvStorageClass(vector_ptr_ty.ptrAddressSpace(mod)); |
| 3839 | const scalar_ptr_ty_ref = try self.ptrType(scalar_ty, storage_class); | 3918 | const scalar_ptr_ty_ref = try self.ptrType(scalar_ty, storage_class); |
| 3840 | | 3919 | |
| 3841 | const vector_ptr = try self.resolve(data.vector_ptr); | 3920 | const vector_ptr = try self.resolve(data.vector_ptr); |
| ... | @@ -3858,7 +3937,7 @@ const DeclGen = struct { | ... | @@ -3858,7 +3937,7 @@ const DeclGen = struct { |
| 3858 | if (layout.tag_size == 0) return; | 3937 | if (layout.tag_size == 0) return; |
| 3859 | | 3938 | |
| 3860 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; | 3939 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; |
| 3861 | const tag_ptr_ty_ref = try self.ptrType(tag_ty, spvStorageClass(un_ptr_ty.ptrAddressSpace(mod))); | 3940 | const tag_ptr_ty_ref = try self.ptrType(tag_ty, self.spvStorageClass(un_ptr_ty.ptrAddressSpace(mod))); |
| 3862 | | 3941 | |
| 3863 | const union_ptr_id = try self.resolve(bin_op.lhs); | 3942 | const union_ptr_id = try self.resolve(bin_op.lhs); |
| 3864 | const new_tag_id = try self.resolve(bin_op.rhs); | 3943 | const new_tag_id = try self.resolve(bin_op.rhs); |
| ... | @@ -4079,7 +4158,7 @@ const DeclGen = struct { | ... | @@ -4079,7 +4158,7 @@ const DeclGen = struct { |
| 4079 | return try self.spv.constUndef(result_ty_ref); | 4158 | return try self.spv.constUndef(result_ty_ref); |
| 4080 | } | 4159 | } |
| 4081 | | 4160 | |
| 4082 | const storage_class = spvStorageClass(object_ptr_ty.ptrAddressSpace(mod)); | 4161 | const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(mod)); |
| 4083 | const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, storage_class); | 4162 | const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, storage_class); |
| 4084 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, object_ptr, &.{layout.payload_index}); | 4163 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, object_ptr, &.{layout.payload_index}); |
| 4085 | | 4164 | |
| ... | @@ -4134,17 +4213,16 @@ const DeclGen = struct { | ... | @@ -4134,17 +4213,16 @@ const DeclGen = struct { |
| 4134 | .initializer = options.initializer, | 4213 | .initializer = options.initializer, |
| 4135 | }); | 4214 | }); |
| 4136 | | 4215 | |
| | 4216 | const target = self.getTarget(); |
| | 4217 | if (target.os.tag == .vulkan) { |
| | 4218 | return var_id; |
| | 4219 | } |
| | 4220 | |
| 4137 | switch (options.storage_class) { | 4221 | switch (options.storage_class) { |
| 4138 | .Generic => { | 4222 | .Generic => { |
| 4139 | const ptr_gn_ty_ref = try self.ptrType(ty, .Generic); | 4223 | const ptr_gn_ty_ref = try self.ptrType(ty, .Generic); |
| 4140 | // Convert to a generic pointer | 4224 | // Convert to a generic pointer |
| 4141 | const result_id = self.spv.allocId(); | 4225 | return self.castToGeneric(self.typeId(ptr_gn_ty_ref), var_id); |
| 4142 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ | | |
| 4143 | .id_result_type = self.typeId(ptr_gn_ty_ref), | | |
| 4144 | .id_result = result_id, | | |
| 4145 | .pointer = var_id, | | |
| 4146 | }); | | |
| 4147 | return result_id; | | |
| 4148 | }, | 4226 | }, |
| 4149 | .Function => return var_id, | 4227 | .Function => return var_id, |
| 4150 | else => unreachable, | 4228 | else => unreachable, |
| ... | @@ -4880,7 +4958,7 @@ const DeclGen = struct { | ... | @@ -4880,7 +4958,7 @@ const DeclGen = struct { |
| 4880 | const is_non_null_id = blk: { | 4958 | const is_non_null_id = blk: { |
| 4881 | if (is_pointer) { | 4959 | if (is_pointer) { |
| 4882 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 4960 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4883 | const storage_class = spvStorageClass(operand_ty.ptrAddressSpace(mod)); | 4961 | const storage_class = self.spvStorageClass(operand_ty.ptrAddressSpace(mod)); |
| 4884 | const bool_ptr_ty = try self.ptrType(Type.bool, storage_class); | 4962 | const bool_ptr_ty = try self.ptrType(Type.bool, storage_class); |
| 4885 | const tag_ptr_id = try self.accessChain(bool_ptr_ty, operand_id, &.{1}); | 4963 | const tag_ptr_id = try self.accessChain(bool_ptr_ty, operand_id, &.{1}); |
| 4886 | break :blk try self.load(Type.bool, tag_ptr_id, .{}); | 4964 | break :blk try self.load(Type.bool, tag_ptr_id, .{}); |