authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2025-08-02 11:07:20+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2025-08-03 04:54:28+03:30
logd15a7b1b219b7f0b9ab9b870fb051005e3890a37
tree57a481c690b4c7f5043baf36056a0e29b07dce54
parent5525a90a478e4c3d9e9b8cd2d78f9238d7b8795a
signaturelock-open Commit is signed but in an unrecognized format.

spirv: move more type emitting functions to `Module`


2 files changed, 246 insertions(+), 281 deletions(-)

src/arch/spirv/CodeGen.zig+159-251
......@@ -40,7 +40,6 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
4040}
4141
4242pub const zig_call_abi_ver = 3;
43pub const big_int_bits = 32;
4443
4544const ControlFlow = union(enum) {
4645 const Structured = struct {
......@@ -183,6 +182,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
183182 const gpa = cg.module.gpa;
184183 const zcu = cg.module.zcu;
185184 const ip = &zcu.intern_pool;
185 const target = zcu.getTarget();
186186
187187 const nav = ip.getNav(cg.owner_nav);
188188 const val = zcu.navValue(cg.owner_nav);
......@@ -251,19 +251,19 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
251251 // Append the actual code into the functions section.
252252 try cg.module.sections.functions.append(cg.module.gpa, cg.prologue);
253253 try cg.module.sections.functions.append(cg.module.gpa, cg.body);
254 try cg.module.declareDeclDeps(spv_decl_index, cg.decl_deps.keys());
255
256 try cg.module.debugName(func_result_id, nav.fqn.toSlice(ip));
257254
258255 // Temporarily generate a test kernel declaration if this is a test function.
259256 if (is_test) {
260257 try cg.generateTestEntryPoint(nav.fqn.toSlice(ip), spv_decl_index, func_result_id);
261258 }
259
260 try cg.module.declareDeclDeps(spv_decl_index, cg.decl_deps.keys());
261 try cg.module.debugName(func_result_id, nav.fqn.toSlice(ip));
262262 },
263263 .global => {
264264 const maybe_init_val: ?Value = switch (ip.indexToKey(val.toIntern())) {
265265 .func => unreachable,
266 .variable => |variable| Value.fromInterned(variable.init),
266 .variable => |variable| .fromInterned(variable.init),
267267 .@"extern" => null,
268268 else => val,
269269 };
......@@ -272,7 +272,8 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
272272 const storage_class = cg.module.storageClass(nav.getAddrspace());
273273 assert(storage_class != .generic); // These should be instance globals
274274
275 const ptr_ty_id = try cg.ptrType(ty, storage_class, .indirect);
275 const ty_id = try cg.resolveType(ty, .indirect);
276 const ptr_ty_id = try cg.module.ptrType(ty_id, storage_class);
276277
277278 try cg.module.sections.globals.emit(cg.module.gpa, .OpVariable, .{
278279 .id_result_type = ptr_ty_id,
......@@ -280,6 +281,27 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
280281 .storage_class = storage_class,
281282 });
282283
284 switch (target.os.tag) {
285 .vulkan, .opengl => {
286 if (ty.zigTypeTag(zcu) == .@"struct") {
287 switch (storage_class) {
288 .uniform, .push_constant => try cg.module.decorate(ty_id, .block),
289 else => {},
290 }
291 }
292
293 switch (ip.indexToKey(ty.toIntern())) {
294 .func_type, .opaque_type => {},
295 else => {
296 try cg.module.decorate(ptr_ty_id, .{
297 .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) },
298 });
299 },
300 }
301 },
302 else => {},
303 }
304
283305 if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |builtin| {
284306 try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = builtin } });
285307 }
......@@ -290,18 +312,20 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
290312 .invocation_global => {
291313 const maybe_init_val: ?Value = switch (ip.indexToKey(val.toIntern())) {
292314 .func => unreachable,
293 .variable => |variable| Value.fromInterned(variable.init),
315 .variable => |variable| .fromInterned(variable.init),
294316 .@"extern" => null,
295317 else => val,
296318 };
297319
298320 try cg.module.declareDeclDeps(spv_decl_index, &.{});
299321
300 const ptr_ty_id = try cg.ptrType(ty, .function, .indirect);
322 const ty_id = try cg.resolveType(ty, .indirect);
323 const ptr_ty_id = try cg.module.ptrType(ty_id, .function);
301324
302325 if (maybe_init_val) |init_val| {
303326 // TODO: Combine with resolveAnonDecl?
304 const initializer_proto_ty_id = try cg.functionType(.void, &.{});
327 const void_ty_id = try cg.resolveType(.void, .direct);
328 const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});
305329
306330 const initializer_id = cg.module.allocId();
307331 try cg.prologue.emit(cg.module.gpa, .OpFunction, .{
......@@ -406,7 +430,8 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
406430
407431 const zcu = cg.module.zcu;
408432 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));
409 const decl_ptr_ty_id = try cg.ptrType(ty, cg.module.storageClass(.generic), .indirect);
433 const ty_id = try cg.resolveType(ty, .indirect);
434 const decl_ptr_ty_id = try cg.module.ptrType(ty_id, cg.module.storageClass(.generic));
410435
411436 const spv_decl_index = blk: {
412437 const entry = try cg.module.uav_link.getOrPut(cg.module.gpa, .{ val, .function });
......@@ -454,7 +479,8 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
454479 cg.decl_deps.deinit(gpa);
455480 }
456481
457 const initializer_proto_ty_id = try cg.functionType(.void, &.{});
482 const void_ty_id = try cg.resolveType(.void, .direct);
483 const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});
458484
459485 const initializer_id = cg.module.allocId();
460486 try cg.prologue.emit(cg.module.gpa, .OpFunction, .{
......@@ -469,7 +495,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
469495 });
470496 cg.block_label = root_block_id;
471497
472 const val_id = try cg.constant(ty, Value.fromInterned(val), .indirect);
498 const val_id = try cg.constant(ty, .fromInterned(val), .indirect);
473499 try cg.body.emit(cg.module.gpa, .OpStore, .{
474500 .pointer = result_id,
475501 .object = val_id,
......@@ -484,7 +510,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
484510
485511 try cg.module.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});
486512
487 const fn_decl_ptr_ty_id = try cg.ptrType(ty, .function, .indirect);
513 const fn_decl_ptr_ty_id = try cg.module.ptrType(ty_id, .function);
488514 try cg.module.sections.globals.emit(cg.module.gpa, .OpExtInst, .{
489515 .id_result_type = fn_decl_ptr_ty_id,
490516 .id_result = result_id,
......@@ -533,44 +559,6 @@ fn beginSpvBlock(cg: *CodeGen, label: Id) !void {
533559 cg.block_label = label;
534560}
535561
536/// SPIR-V requires enabling specific integer sizes through capabilities, and so if they are not enabled, we need
537/// to emulate them in other instructions/types. This function returns, given an integer bit width (signed or unsigned, sign
538/// included), the width of the underlying type which represents it, given the enabled features for the current target.
539/// If the result is `null`, the largest type the target platform supports natively is not able to perform computations using
540/// that size. In this case, multiple elements of the largest type should be used.
541/// The backing type will be chosen as the smallest supported integer larger or equal to it in number of bits.
542/// The result is valid to be used with OpTypeInt.
543/// TODO: Should the result of this function be cached?
544fn backingIntBits(cg: *CodeGen, bits: u16) struct { u16, bool } {
545 const target = cg.module.zcu.getTarget();
546
547 // The backend will never be asked to compiler a 0-bit integer, so we won't have to handle those in this function.
548 assert(bits != 0);
549
550 if (target.cpu.has(.spirv, .arbitrary_precision_integers) and bits <= 32) {
551 return .{ bits, false };
552 }
553
554 // We require Int8 and Int16 capabilities and benefit Int64 when available.
555 // 32-bit integers are always supported (see spec, 2.16.1, Data rules).
556 const ints = [_]struct { bits: u16, enabled: bool }{
557 .{ .bits = 8, .enabled = true },
558 .{ .bits = 16, .enabled = true },
559 .{ .bits = 32, .enabled = true },
560 .{
561 .bits = 64,
562 .enabled = target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64,
563 },
564 };
565
566 for (ints) |int| {
567 if (bits <= int.bits and int.enabled) return .{ int.bits, false };
568 }
569
570 // Big int
571 return .{ std.mem.alignForward(u16, bits, big_int_bits), true };
572}
573
574562/// Return the amount of bits in the largest supported integer type. This is either 32 (always supported), or 64 (if
575563/// the Int64 capability is enabled).
576564/// Note: The extension SPV_INTEL_arbitrary_precision_integers allows any integer size (at least up to 32 bits).
......@@ -632,7 +620,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
632620 return switch (scalar_ty.zigTypeTag(zcu)) {
633621 .bool => .{
634622 .bits = 1, // Doesn't matter for this class.
635 .backing_bits = cg.backingIntBits(1).@"0",
623 .backing_bits = cg.module.backingIntBits(1).@"0",
636624 .vector_len = vector_len,
637625 .signedness = .unsigned, // Technically, but doesn't matter for this class.
638626 .class = .bool,
......@@ -647,7 +635,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
647635 .int => blk: {
648636 const int_info = scalar_ty.intInfo(zcu);
649637 // TODO: Maybe it's useful to also return this value.
650 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
638 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);
651639 break :blk .{
652640 .bits = int_info.bits,
653641 .backing_bits = backing_bits,
......@@ -711,7 +699,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
711699 const scalar_ty = ty.scalarType(zcu);
712700 const int_info = scalar_ty.intInfo(zcu);
713701 // Use backing bits so that negatives are sign extended
714 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
702 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);
715703 assert(backing_bits != 0); // u0 is comptime
716704
717705 const result_ty_id = try cg.resolveType(scalar_ty, .indirect);
......@@ -922,8 +910,8 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
922910 },
923911 .ptr => return cg.constantPtr(val),
924912 .slice => |slice| {
925 const ptr_id = try cg.constantPtr(Value.fromInterned(slice.ptr));
926 const len_id = try cg.constant(.usize, Value.fromInterned(slice.len), .indirect);
913 const ptr_id = try cg.constantPtr(.fromInterned(slice.ptr));
914 const len_id = try cg.constant(.usize, .fromInterned(slice.len), .indirect);
927915 const comp_ty_id = try cg.resolveType(ty, .direct);
928916 return try cg.constructComposite(comp_ty_id, &.{ ptr_id, len_id });
929917 },
......@@ -977,11 +965,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
977965 },
978966 .elems => |elems| {
979967 for (constituents, elems) |*constituent, elem| {
980 constituent.* = try cg.constant(elem_ty, Value.fromInterned(elem), child_repr);
968 constituent.* = try cg.constant(elem_ty, .fromInterned(elem), child_repr);
981969 }
982970 },
983971 .repeated_elem => |elem| {
984 @memset(constituents, try cg.constant(elem_ty, Value.fromInterned(elem), child_repr));
972 @memset(constituents, try cg.constant(elem_ty, .fromInterned(elem), child_repr));
985973 },
986974 }
987975
......@@ -995,7 +983,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
995983 // TODO: composite int
996984 // TODO: endianness
997985 const bits: u16 = @intCast(ty.bitSize(zcu));
998 const bytes = std.mem.alignForward(u16, cg.backingIntBits(bits).@"0", 8) / 8;
986 const bytes = std.mem.alignForward(u16, cg.module.backingIntBits(bits).@"0", 8) / 8;
999987 var limbs: [8]u8 = undefined;
1000988 @memset(&limbs, 0);
1001989 val.writeToPackedMemory(ty, pt, limbs[0..bytes], 0) catch unreachable;
......@@ -1035,13 +1023,13 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
10351023 if (un.tag == .none) {
10361024 assert(ty.containerLayout(zcu) == .@"packed"); // TODO
10371025 const int_ty = try pt.intType(.unsigned, @intCast(ty.bitSize(zcu)));
1038 return try cg.constant(int_ty, Value.fromInterned(un.val), .direct);
1026 return try cg.constInt(int_ty, Value.toUnsignedInt(.fromInterned(un.val), zcu));
10391027 }
1040 const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
1028 const active_field = ty.unionTagFieldIndex(.fromInterned(un.tag), zcu).?;
10411029 const union_obj = zcu.typeToUnion(ty).?;
10421030 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[active_field]);
10431031 const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(zcu))
1044 try cg.constant(field_ty, Value.fromInterned(un.val), .direct)
1032 try cg.constant(field_ty, .fromInterned(un.val), .direct)
10451033 else
10461034 null;
10471035 return try cg.unionInit(ty, active_field, payload);
......@@ -1084,10 +1072,11 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
10841072 // that is not implemented by Mesa yet. Therefore, just generate it
10851073 // as a runtime operation.
10861074 const result_ptr_id = cg.module.allocId();
1075 const value_id = try cg.constInt(.usize, int.addr);
10871076 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{
10881077 .id_result_type = result_ty_id,
10891078 .id_result = result_ptr_id,
1090 .integer_value = try cg.constant(.usize, try pt.intValue(.usize, int.addr), .direct),
1079 .integer_value = value_id,
10911080 });
10921081 return result_ptr_id;
10931082 },
......@@ -1174,7 +1163,8 @@ fn constantUavRef(
11741163
11751164 // Uav refs are always generic.
11761165 assert(ty.ptrAddressSpace(zcu) == .generic);
1177 const decl_ptr_ty_id = try cg.ptrType(uav_ty, .generic, .indirect);
1166 const uav_ty_id = try cg.resolveType(uav_ty, .indirect);
1167 const decl_ptr_ty_id = try cg.module.ptrType(uav_ty_id, .generic);
11781168 const ptr_id = try cg.resolveUav(uav.val);
11791169
11801170 if (decl_ptr_ty_id != ty_id) {
......@@ -1228,7 +1218,8 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {
12281218 const storage_class = cg.module.storageClass(nav.getAddrspace());
12291219 try cg.addFunctionDep(spv_decl_index, storage_class);
12301220
1231 const decl_ptr_ty_id = try cg.ptrType(nav_ty, storage_class, .indirect);
1221 const nav_ty_id = try cg.resolveType(nav_ty, .indirect);
1222 const decl_ptr_ty_id = try cg.module.ptrType(nav_ty_id, storage_class);
12321223
12331224 const ptr_id = switch (storage_class) {
12341225 .generic => try cg.castToGeneric(decl_ptr_ty_id, decl_id),
......@@ -1260,104 +1251,6 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
12601251 return try aw.toOwnedSlice();
12611252}
12621253
1263/// Create an integer type suitable for storing at least 'bits' bits.
1264/// The integer type that is returned by this function is the type that is used to perform
1265/// actual operations (as well as store) a Zig type of a particular number of bits. To create
1266/// a type with an exact size, use Module.intType.
1267fn intType(cg: *CodeGen, signedness: std.builtin.Signedness, bits: u16) !Id {
1268 const target = cg.module.zcu.getTarget();
1269
1270 const backing_bits, const big_int = cg.backingIntBits(bits);
1271 if (big_int) {
1272 if (backing_bits > 64) {
1273 return cg.fail("composite integers larger than 64bit aren't supported", .{});
1274 }
1275 const int_ty = try cg.resolveType(.u32, .direct);
1276 return cg.arrayType(backing_bits / big_int_bits, int_ty);
1277 }
1278
1279 return switch (target.os.tag) {
1280 // Kernel only supports unsigned ints.
1281 .opencl, .amdhsa => return cg.module.intType(.unsigned, backing_bits),
1282 else => cg.module.intType(signedness, backing_bits),
1283 };
1284}
1285
1286fn arrayType(cg: *CodeGen, len: u32, child_ty: Id) !Id {
1287 const len_id = try cg.constInt(.u32, len);
1288 return cg.module.arrayType(len_id, child_ty);
1289}
1290
1291fn ptrType(cg: *CodeGen, child_ty: Type, storage_class: StorageClass, child_repr: Repr) !Id {
1292 const gpa = cg.module.gpa;
1293 const zcu = cg.module.zcu;
1294 const ip = &zcu.intern_pool;
1295 const target = cg.module.zcu.getTarget();
1296
1297 const child_ty_id = try cg.resolveType(child_ty, child_repr);
1298 const key = .{ child_ty_id, storage_class };
1299 const entry = try cg.module.ptr_types.getOrPut(gpa, key);
1300 if (entry.found_existing) {
1301 const fwd_id = entry.value_ptr.ty_id;
1302 if (!entry.value_ptr.fwd_emitted) {
1303 try cg.module.sections.globals.emit(cg.module.gpa, .OpTypeForwardPointer, .{
1304 .pointer_type = fwd_id,
1305 .storage_class = storage_class,
1306 });
1307 entry.value_ptr.fwd_emitted = true;
1308 }
1309 return fwd_id;
1310 }
1311
1312 const result_id = cg.module.allocId();
1313 entry.value_ptr.* = .{
1314 .ty_id = result_id,
1315 .fwd_emitted = false,
1316 };
1317
1318 switch (target.os.tag) {
1319 .vulkan, .opengl => {
1320 if (child_ty.zigTypeTag(zcu) == .@"struct") {
1321 switch (storage_class) {
1322 .uniform, .push_constant => try cg.module.decorate(child_ty_id, .block),
1323 else => {},
1324 }
1325 }
1326
1327 switch (ip.indexToKey(child_ty.toIntern())) {
1328 .func_type, .opaque_type => {},
1329 else => {
1330 try cg.module.decorate(result_id, .{ .array_stride = .{ .array_stride = @intCast(child_ty.abiSize(zcu)) } });
1331 },
1332 }
1333 },
1334 else => {},
1335 }
1336
1337 try cg.module.sections.globals.emit(cg.module.gpa, .OpTypePointer, .{
1338 .id_result = result_id,
1339 .storage_class = storage_class,
1340 .type = child_ty_id,
1341 });
1342
1343 cg.module.ptr_types.getPtr(key).?.fwd_emitted = true;
1344
1345 return result_id;
1346}
1347
1348fn functionType(cg: *CodeGen, return_ty: Type, param_types: []const Type) !Id {
1349 const gpa = cg.module.gpa;
1350 const return_ty_id = try cg.resolveFnReturnType(return_ty);
1351 const param_ids = try gpa.alloc(Id, param_types.len);
1352 defer gpa.free(param_ids);
1353
1354 for (param_types, param_ids) |param_ty, *param_id| {
1355 param_id.* = try cg.resolveType(param_ty, .direct);
1356 }
1357
1358 return cg.module.functionType(return_ty_id, param_ids);
1359}
1360
13611254/// Generate a union type. Union types are always generated with the
13621255/// most aligned field active. If the tag alignment is greater
13631256/// than that of the payload, a regular union (non-packed, with both tag and
......@@ -1383,7 +1276,7 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
13831276 const union_obj = zcu.typeToUnion(ty).?;
13841277
13851278 if (union_obj.flagsUnordered(ip).layout == .@"packed") {
1386 return try cg.intType(.unsigned, @intCast(ty.bitSize(zcu)));
1279 return try cg.module.intType(.unsigned, @intCast(ty.bitSize(zcu)));
13871280 }
13881281
13891282 const layout = cg.unionLayout(ty);
......@@ -1410,13 +1303,15 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
14101303 }
14111304
14121305 if (layout.payload_padding_size != 0) {
1413 const payload_padding_ty_id = try cg.arrayType(@intCast(layout.payload_padding_size), u8_ty_id);
1306 const len_id = try cg.constInt(.u32, layout.payload_padding_size);
1307 const payload_padding_ty_id = try cg.module.arrayType(len_id, u8_ty_id);
14141308 member_types[layout.payload_padding_index] = payload_padding_ty_id;
14151309 member_names[layout.payload_padding_index] = "(payload padding)";
14161310 }
14171311
14181312 if (layout.padding_size != 0) {
1419 const padding_ty_id = try cg.arrayType(@intCast(layout.padding_size), u8_ty_id);
1313 const len_id = try cg.constInt(.u32, layout.padding_size);
1314 const padding_ty_id = try cg.module.arrayType(len_id, u8_ty_id);
14201315 member_types[layout.padding_index] = padding_ty_id;
14211316 member_names[layout.padding_index] = "(padding)";
14221317 }
......@@ -1479,7 +1374,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
14791374 assert(repr == .indirect);
14801375 return try cg.module.opaqueType("u0");
14811376 }
1482 return try cg.intType(int_info.signedness, int_info.bits);
1377 return try cg.module.intType(int_info.signedness, int_info.bits);
14831378 },
14841379 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),
14851380 .float => {
......@@ -1519,9 +1414,11 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
15191414 // In this case, we have an array of a non-zero sized type. In this case,
15201415 // generate an array of 1 element instead, so that ptr_elem_ptr instructions
15211416 // can be lowered to ptrAccessChain instead of manually performing the math.
1522 return try cg.arrayType(1, elem_ty_id);
1417 const len_id = try cg.constInt(.u32, 1);
1418 return try cg.module.arrayType(len_id, elem_ty_id);
15231419 } else {
1524 const result_id = try cg.arrayType(total_len, elem_ty_id);
1420 const total_len_id = try cg.constInt(.u32, total_len);
1421 const result_id = try cg.module.arrayType(total_len_id, elem_ty_id);
15251422 switch (target.os.tag) {
15261423 .vulkan, .opengl => {
15271424 try cg.module.decorate(result_id, .{
......@@ -1540,7 +1437,8 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
15401437 const elem_ty_id = try cg.resolveType(elem_ty, repr);
15411438 const len = ty.vectorLen(zcu);
15421439 if (cg.isSpvVector(ty)) return try cg.module.vectorType(len, elem_ty_id);
1543 return try cg.arrayType(len, elem_ty_id);
1440 const len_id = try cg.constInt(.u32, len);
1441 return try cg.module.arrayType(len_id, elem_ty_id);
15441442 },
15451443 .@"fn" => switch (repr) {
15461444 .direct => {
......@@ -1582,8 +1480,9 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
15821480 const ptr_info = ty.ptrInfo(zcu);
15831481
15841482 const child_ty: Type = .fromInterned(ptr_info.child);
1483 const child_ty_id = try cg.resolveType(child_ty, .indirect);
15851484 const storage_class = cg.module.storageClass(ptr_info.flags.address_space);
1586 const ptr_ty_id = try cg.ptrType(child_ty, storage_class, .indirect);
1485 const ptr_ty_id = try cg.module.ptrType(child_ty_id, storage_class);
15871486
15881487 if (ptr_info.flags.size != .slice) {
15891488 return ptr_ty_id;
......@@ -2142,7 +2041,7 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
21422041
21432042 for (0..ops) |i| {
21442043 try cg.body.emitRaw(cg.module.gpa, opcode, 3);
2145 cg.body.writeOperand(spec.Id, op_result_ty_id);
2044 cg.body.writeOperand(Id, op_result_ty_id);
21462045 cg.body.writeOperand(Id, results.at(i));
21472046 cg.body.writeOperand(Id, op_src.at(i));
21482047 }
......@@ -2277,7 +2176,7 @@ fn buildCmp(cg: *CodeGen, pred: CmpPredicate, lhs: Temporary, rhs: Temporary) !T
22772176
22782177 for (0..ops) |i| {
22792178 try cg.body.emitRaw(cg.module.gpa, opcode, 4);
2280 cg.body.writeOperand(spec.Id, op_result_ty_id);
2179 cg.body.writeOperand(Id, op_result_ty_id);
22812180 cg.body.writeOperand(Id, results.at(i));
22822181 cg.body.writeOperand(Id, op_lhs.at(i));
22832182 cg.body.writeOperand(Id, op_rhs.at(i));
......@@ -2331,7 +2230,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
23312230 }) |opcode| {
23322231 for (0..ops) |i| {
23332232 try cg.body.emitRaw(cg.module.gpa, opcode, 3);
2334 cg.body.writeOperand(spec.Id, op_result_ty_id);
2233 cg.body.writeOperand(Id, op_result_ty_id);
23352234 cg.body.writeOperand(Id, results.at(i));
23362235 cg.body.writeOperand(Id, op_operand.at(i));
23372236 }
......@@ -2472,7 +2371,7 @@ fn buildBinary(cg: *CodeGen, op: BinaryOp, lhs: Temporary, rhs: Temporary) !Temp
24722371 }) |opcode| {
24732372 for (0..ops) |i| {
24742373 try cg.body.emitRaw(cg.module.gpa, opcode, 4);
2475 cg.body.writeOperand(spec.Id, op_result_ty_id);
2374 cg.body.writeOperand(Id, op_result_ty_id);
24762375 cg.body.writeOperand(Id, results.at(i));
24772376 cg.body.writeOperand(Id, op_lhs.at(i));
24782377 cg.body.writeOperand(Id, op_rhs.at(i));
......@@ -2591,7 +2490,7 @@ fn buildWideMul(
25912490 const op_result = cg.module.allocId();
25922491
25932492 try cg.body.emitRaw(cg.module.gpa, opcode, 4);
2594 cg.body.writeOperand(spec.Id, op_result_ty_id);
2493 cg.body.writeOperand(Id, op_result_ty_id);
25952494 cg.body.writeOperand(Id, op_result);
25962495 cg.body.writeOperand(Id, lhs_op.at(i));
25972496 cg.body.writeOperand(Id, rhs_op.at(i));
......@@ -2664,30 +2563,27 @@ fn generateTestEntryPoint(
26642563
26652564 const kernel_id = cg.module.declPtr(spv_decl_index).result_id;
26662565
2667 var decl_deps = std.ArrayList(Module.Decl.Index).init(gpa);
2668 defer decl_deps.deinit();
2669 try decl_deps.append(spv_decl_index);
2670
26712566 const section = &cg.module.sections.functions;
26722567
26732568 const p_error_id = cg.module.allocId();
26742569 switch (target.os.tag) {
26752570 .opencl, .amdhsa => {
2676 const kernel_proto_ty_id = try cg.functionType(.void, &.{ptr_anyerror_ty});
2571 const void_ty_id = try cg.resolveType(.void, .direct);
2572 const kernel_proto_ty_id = try cg.module.functionType(void_ty_id, &.{ptr_anyerror_ty_id});
26772573
2678 try section.emit(cg.module.gpa, .OpFunction, .{
2574 try section.emit(gpa, .OpFunction, .{
26792575 .id_result_type = try cg.resolveType(.void, .direct),
26802576 .id_result = kernel_id,
26812577 .function_control = .{},
26822578 .function_type = kernel_proto_ty_id,
26832579 });
26842580
2685 try section.emit(cg.module.gpa, .OpFunctionParameter, .{
2581 try section.emit(gpa, .OpFunctionParameter, .{
26862582 .id_result_type = ptr_anyerror_ty_id,
26872583 .id_result = p_error_id,
26882584 });
26892585
2690 try section.emit(cg.module.gpa, .OpLabel, .{
2586 try section.emit(gpa, .OpLabel, .{
26912587 .id_result = cg.module.allocId(),
26922588 });
26932589 },
......@@ -2706,14 +2602,14 @@ fn generateTestEntryPoint(
27062602 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });
27072603
27082604 const ptr_buffer_struct_ty_id = cg.module.allocId();
2709 try cg.module.sections.globals.emit(cg.module.gpa, .OpTypePointer, .{
2605 try cg.module.sections.globals.emit(gpa, .OpTypePointer, .{
27102606 .id_result = ptr_buffer_struct_ty_id,
27112607 .storage_class = cg.module.storageClass(.global),
27122608 .type = buffer_struct_ty_id,
27132609 });
27142610
27152611 const buffer_struct_id = cg.module.declPtr(spv_err_decl_index).result_id;
2716 try cg.module.sections.globals.emit(cg.module.gpa, .OpVariable, .{
2612 try cg.module.sections.globals.emit(gpa, .OpVariable, .{
27172613 .id_result_type = ptr_buffer_struct_ty_id,
27182614 .id_result = buffer_struct_id,
27192615 .storage_class = cg.module.storageClass(.global),
......@@ -2724,7 +2620,7 @@ fn generateTestEntryPoint(
27242620 cg.module.error_buffer = spv_err_decl_index;
27252621 }
27262622
2727 try cg.module.sections.execution_modes.emit(cg.module.gpa, .OpExecutionMode, .{
2623 try cg.module.sections.execution_modes.emit(gpa, .OpExecutionMode, .{
27282624 .entry_point = kernel_id,
27292625 .mode = .{ .local_size = .{
27302626 .x_size = 1,
......@@ -2733,23 +2629,24 @@ fn generateTestEntryPoint(
27332629 } },
27342630 });
27352631
2736 const kernel_proto_ty_id = try cg.functionType(.void, &.{});
2737 try section.emit(cg.module.gpa, .OpFunction, .{
2632 const void_ty_id = try cg.resolveType(.void, .direct);
2633 const kernel_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});
2634 try section.emit(gpa, .OpFunction, .{
27382635 .id_result_type = try cg.resolveType(.void, .direct),
27392636 .id_result = kernel_id,
27402637 .function_control = .{},
27412638 .function_type = kernel_proto_ty_id,
27422639 });
2743 try section.emit(cg.module.gpa, .OpLabel, .{
2640 try section.emit(gpa, .OpLabel, .{
27442641 .id_result = cg.module.allocId(),
27452642 });
27462643
27472644 const spv_err_decl_index = cg.module.error_buffer.?;
27482645 const buffer_id = cg.module.declPtr(spv_err_decl_index).result_id;
2749 try decl_deps.append(spv_err_decl_index);
2646 try cg.decl_deps.put(gpa, spv_err_decl_index, {});
27502647
27512648 const zero_id = try cg.constInt(.u32, 0);
2752 try section.emit(cg.module.gpa, .OpInBoundsAccessChain, .{
2649 try section.emit(gpa, .OpInBoundsAccessChain, .{
27532650 .id_result_type = ptr_anyerror_ty_id,
27542651 .id_result = p_error_id,
27552652 .base = buffer_id,
......@@ -2760,25 +2657,25 @@ fn generateTestEntryPoint(
27602657 }
27612658
27622659 const error_id = cg.module.allocId();
2763 try section.emit(cg.module.gpa, .OpFunctionCall, .{
2660 try section.emit(gpa, .OpFunctionCall, .{
27642661 .id_result_type = anyerror_ty_id,
27652662 .id_result = error_id,
27662663 .function = test_id,
27672664 });
27682665 // Note: Convert to direct not required.
2769 try section.emit(cg.module.gpa, .OpStore, .{
2666 try section.emit(gpa, .OpStore, .{
27702667 .pointer = p_error_id,
27712668 .object = error_id,
27722669 .memory_access = .{
27732670 .aligned = .{ .literal_integer = @intCast(Type.abiAlignment(.anyerror, zcu).toByteUnits().?) },
27742671 },
27752672 });
2776 try section.emit(cg.module.gpa, .OpReturn, {});
2777 try section.emit(cg.module.gpa, .OpFunctionEnd, {});
2673 try section.emit(gpa, .OpReturn, {});
2674 try section.emit(gpa, .OpFunctionEnd, {});
27782675
27792676 // Just generate a quick other name because the intel runtime crashes when the entry-
27802677 // point name is the same as a different OpName.
2781 const test_name = try std.fmt.allocPrint(gpa, "test {s}", .{name});
2678 const test_name = try std.fmt.allocPrint(cg.module.arena, "test {s}", .{name});
27822679
27832680 const execution_mode: spec.ExecutionModel = switch (target.os.tag) {
27842681 .vulkan, .opengl => .gl_compute,
......@@ -2786,7 +2683,6 @@ fn generateTestEntryPoint(
27862683 else => unreachable,
27872684 };
27882685
2789 try cg.module.declareDeclDeps(spv_decl_index, decl_deps.items);
27902686 try cg.module.declareEntryPoint(spv_decl_index, test_name, execution_mode, null);
27912687}
27922688
......@@ -3760,10 +3656,10 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
37603656 result_id = cg.module.allocId();
37613657
37623658 try cg.body.emitRaw(cg.module.gpa, opcode, 4);
3763 cg.body.writeOperand(spec.Id, scalar_ty_id);
3764 cg.body.writeOperand(spec.Id, result_id);
3765 cg.body.writeOperand(spec.Id, lhs);
3766 cg.body.writeOperand(spec.Id, rhs);
3659 cg.body.writeOperand(Id, scalar_ty_id);
3660 cg.body.writeOperand(Id, result_id);
3661 cg.body.writeOperand(Id, lhs);
3662 cg.body.writeOperand(Id, rhs);
37673663 }
37683664
37693665 return result_id;
......@@ -4189,7 +4085,7 @@ fn bitCast(
41894085 break :blk result_id;
41904086 }
41914087
4192 const dst_ptr_ty_id = try cg.ptrType(dst_ty, .function, .indirect);
4088 const dst_ptr_ty_id = try cg.module.ptrType(dst_ty_id, .function);
41934089
41944090 const tmp_id = try cg.alloc(src_ty, .{ .storage_class = .function });
41954091 try cg.store(src_ty, tmp_id, src_id, .{});
......@@ -4594,7 +4490,8 @@ fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
45944490 const zcu = cg.module.zcu;
45954491 // Construct new pointer type for the resulting pointer
45964492 const elem_ty = ptr_ty.elemType2(zcu); // use elemType() so that we get T for *[N]T.
4597 const elem_ptr_ty_id = try cg.ptrType(elem_ty, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)), .indirect);
4493 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);
4494 const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)));
45984495 if (ptr_ty.isSinglePointer(zcu)) {
45994496 // Pointer-to-array. In this case, the resulting pointer is not of the same type
46004497 // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain.
......@@ -4637,8 +4534,10 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
46374534 const is_vector = array_ty.isVector(zcu);
46384535
46394536 const elem_repr: Repr = if (is_vector) .direct else .indirect;
4640 const ptr_array_ty_id = try cg.ptrType(array_ty, .function, .direct);
4641 const ptr_elem_ty_id = try cg.ptrType(elem_ty, .function, elem_repr);
4537 const array_ty_id = try cg.resolveType(array_ty, .direct);
4538 const elem_ty_id = try cg.resolveType(elem_ty, elem_repr);
4539 const ptr_array_ty_id = try cg.module.ptrType(array_ty_id, .function);
4540 const ptr_elem_ty_id = try cg.module.ptrType(elem_ty_id, .function);
46424541
46434542 const tmp_id = cg.module.allocId();
46444543 try cg.prologue.emit(cg.module.gpa, .OpVariable, .{
......@@ -4692,8 +4591,9 @@ fn airVectorStoreElem(cg: *CodeGen, inst: Air.Inst.Index) !void {
46924591 const vector_ty = vector_ptr_ty.childType(zcu);
46934592 const scalar_ty = vector_ty.scalarType(zcu);
46944593
4594 const scalar_ty_id = try cg.resolveType(scalar_ty, .indirect);
46954595 const storage_class = cg.module.storageClass(vector_ptr_ty.ptrAddressSpace(zcu));
4696 const scalar_ptr_ty_id = try cg.ptrType(scalar_ty, storage_class, .indirect);
4596 const scalar_ptr_ty_id = try cg.module.ptrType(scalar_ty_id, storage_class);
46974597
46984598 const vector_ptr = try cg.resolve(data.vector_ptr);
46994599 const index = try cg.resolve(extra.lhs);
......@@ -4715,7 +4615,8 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
47154615 if (layout.tag_size == 0) return;
47164616
47174617 const tag_ty = un_ty.unionTagTypeSafety(zcu).?;
4718 const tag_ptr_ty_id = try cg.ptrType(tag_ty, cg.module.storageClass(un_ptr_ty.ptrAddressSpace(zcu)), .indirect);
4618 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);
4619 const tag_ptr_ty_id = try cg.module.ptrType(tag_ty_id, cg.module.storageClass(un_ptr_ty.ptrAddressSpace(zcu)));
47194620
47204621 const union_ptr_id = try cg.resolve(bin_op.lhs);
47214622 const new_tag_id = try cg.resolve(bin_op.rhs);
......@@ -4802,17 +4703,20 @@ fn unionInit(
48024703 const tmp_id = try cg.alloc(ty, .{ .storage_class = .function });
48034704
48044705 if (layout.tag_size != 0) {
4805 const tag_ptr_ty_id = try cg.ptrType(tag_ty, .function, .indirect);
4706 const tag_ty_id = try cg.resolveType(tag_ty, .indirect);
4707 const tag_ptr_ty_id = try cg.module.ptrType(tag_ty_id, .function);
48064708 const ptr_id = try cg.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});
48074709 const tag_id = try cg.constInt(tag_ty, tag_int);
48084710 try cg.store(tag_ty, ptr_id, tag_id, .{});
48094711 }
48104712
48114713 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4812 const pl_ptr_ty_id = try cg.ptrType(layout.payload_ty, .function, .indirect);
4714 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
4715 const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, .function);
48134716 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
48144717 const active_pl_ptr_id = if (!layout.payload_ty.eql(payload_ty, zcu)) blk: {
4815 const active_pl_ptr_ty_id = try cg.ptrType(payload_ty, .function, .indirect);
4718 const payload_ty_id = try cg.resolveType(payload_ty, .indirect);
4719 const active_pl_ptr_ty_id = try cg.module.ptrType(payload_ty_id, .function);
48164720 const active_pl_ptr_id = cg.module.allocId();
48174721 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
48184722 .id_result_type = active_pl_ptr_ty_id,
......@@ -4876,7 +4780,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
48764780 const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1);
48774781 const masked = try cg.buildBinary(.bit_and, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } });
48784782 const result_id = blk: {
4879 if (cg.backingIntBits(field_bit_size).@"0" == cg.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0")
4783 if (cg.module.backingIntBits(field_bit_size).@"0" == cg.module.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0")
48804784 break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg));
48814785 const trunc = try cg.buildConvert(field_int_ty, masked);
48824786 break :blk try trunc.materialize(cg);
......@@ -4900,7 +4804,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
49004804 .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } },
49014805 );
49024806 const result_id = blk: {
4903 if (cg.backingIntBits(field_bit_size).@"0" == cg.backingIntBits(@intCast(backing_int_ty.bitSize(zcu))).@"0")
4807 if (cg.module.backingIntBits(field_bit_size).@"0" == cg.module.backingIntBits(@intCast(backing_int_ty.bitSize(zcu))).@"0")
49044808 break :blk try cg.bitCast(int_ty, backing_int_ty, try masked.materialize(cg));
49054809 const trunc = try cg.buildConvert(int_ty, masked);
49064810 break :blk try trunc.materialize(cg);
......@@ -4917,10 +4821,12 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
49174821 const tmp_id = try cg.alloc(object_ty, .{ .storage_class = .function });
49184822 try cg.store(object_ty, tmp_id, object_id, .{});
49194823
4920 const pl_ptr_ty_id = try cg.ptrType(layout.payload_ty, .function, .indirect);
4824 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
4825 const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, .function);
49214826 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
49224827
4923 const active_pl_ptr_ty_id = try cg.ptrType(field_ty, .function, .indirect);
4828 const field_ty_id = try cg.resolveType(field_ty, .indirect);
4829 const active_pl_ptr_ty_id = try cg.module.ptrType(field_ty_id, .function);
49244830 const active_pl_ptr_id = cg.module.allocId();
49254831 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
49264832 .id_result_type = active_pl_ptr_ty_id,
......@@ -4997,7 +4903,8 @@ fn structFieldPtr(
49974903 }
49984904
49994905 const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu));
5000 const pl_ptr_ty_id = try cg.ptrType(layout.payload_ty, storage_class, .indirect);
4906 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
4907 const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, storage_class);
50014908 const pl_ptr_id = blk: {
50024909 if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;
50034910 break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
......@@ -5041,7 +4948,8 @@ fn alloc(
50414948 options: AllocOptions,
50424949) !Id {
50434950 const target = cg.module.zcu.getTarget();
5044 const ptr_fn_ty_id = try cg.ptrType(ty, .function, .indirect);
4951 const ty_id = try cg.resolveType(ty, .indirect);
4952 const ptr_fn_ty_id = try cg.module.ptrType(ty_id, .function);
50454953
50464954 // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to
50474955 // directly generate them into func.prologue instead of the body.
......@@ -5060,7 +4968,7 @@ fn alloc(
50604968
50614969 switch (options.storage_class) {
50624970 .generic => {
5063 const ptr_gn_ty_id = try cg.ptrType(ty, .generic, .indirect);
4971 const ptr_gn_ty_id = try cg.module.ptrType(ty_id, .generic);
50644972 // Convert to a generic pointer
50654973 return cg.castToGeneric(ptr_gn_ty_id, var_id);
50664974 },
......@@ -5093,8 +5001,8 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const ControlFlow.Structured.Bl
50935001 const result_id = cg.module.allocId();
50945002 const block_id_ty_id = try cg.resolveType(.u32, .direct);
50955003 try cg.body.emitRaw(cg.module.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent...
5096 cg.body.writeOperand(spec.Id, block_id_ty_id);
5097 cg.body.writeOperand(spec.Id, result_id);
5004 cg.body.writeOperand(Id, block_id_ty_id);
5005 cg.body.writeOperand(Id, result_id);
50985006
50995007 for (incoming) |incoming_block| {
51005008 cg.body.writeOperand(spec.PairIdRefIdRef, .{ incoming_block.next_block, incoming_block.src_label });
......@@ -5285,8 +5193,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
52855193 // result type + result + variable/parent...
52865194 2 + @as(u16, @intCast(block.incoming_blocks.items.len * 2)),
52875195 );
5288 cg.body.writeOperand(spec.Id, result_type_id);
5289 cg.body.writeOperand(spec.Id, result_id);
5196 cg.body.writeOperand(Id, result_type_id);
5197 cg.body.writeOperand(Id, result_id);
52905198
52915199 for (block.incoming_blocks.items) |incoming| {
52925200 cg.body.writeOperand(
......@@ -5793,7 +5701,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
57935701 if (is_pointer) {
57945702 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
57955703 const storage_class = cg.module.storageClass(operand_ty.ptrAddressSpace(zcu));
5796 const bool_ptr_ty_id = try cg.ptrType(.bool, storage_class, .indirect);
5704 const bool_indirect_ty_id = try cg.resolveType(.bool, .indirect);
5705 const bool_ptr_ty_id = try cg.module.ptrType(bool_indirect_ty_id, storage_class);
57975706 const tag_ptr_id = try cg.accessChain(bool_ptr_ty_id, operand_id, &.{1});
57985707 break :blk try cg.load(.bool, tag_ptr_id, .{});
57995708 }
......@@ -5939,14 +5848,14 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
59395848 .bool, .error_set => 1,
59405849 .int => blk: {
59415850 const bits = cond_ty.intInfo(zcu).bits;
5942 const backing_bits, const big_int = cg.backingIntBits(bits);
5851 const backing_bits, const big_int = cg.module.backingIntBits(bits);
59435852 if (big_int) return cg.todo("implement composite int switch", .{});
59445853 break :blk if (backing_bits <= 32) 1 else 2;
59455854 },
59465855 .@"enum" => blk: {
59475856 const int_ty = cond_ty.intTagType(zcu);
59485857 const int_info = int_ty.intInfo(zcu);
5949 const backing_bits, const big_int = cg.backingIntBits(int_info.bits);
5858 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);
59505859 if (big_int) return cg.todo("implement composite int switch", .{});
59515860 break :blk if (backing_bits <= 32) 1 else 2;
59525861 },
......@@ -6298,7 +6207,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
62986207 const callee_id = try cg.resolve(pl_op.operand);
62996208
63006209 comptime assert(zig_call_abi_ver == 3);
6301 const params = try gpa.alloc(spec.Id, args.len);
6210 const params = try gpa.alloc(Id, args.len);
63026211 defer gpa.free(params);
63036212 var n_params: usize = 0;
63046213 for (args) |arg| {
......@@ -6327,50 +6236,49 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
63276236 return result_id;
63286237}
63296238
6330fn builtin3D(cg: *CodeGen, result_ty: Type, builtin: spec.BuiltIn, dimension: u32, out_of_range_value: anytype) !Id {
6331 if (dimension >= 3) {
6332 return try cg.constInt(result_ty, out_of_range_value);
6333 }
6334 const vec_ty = try cg.pt.vectorType(.{
6335 .len = 3,
6336 .child = result_ty.toIntern(),
6337 });
6338 const ptr_ty_id = try cg.ptrType(vec_ty, .input, .indirect);
6339 const spv_decl_index = try cg.module.builtin(ptr_ty_id, builtin);
6239fn builtin3D(
6240 cg: *CodeGen,
6241 result_ty: Type,
6242 builtin: spec.BuiltIn,
6243 dimension: u32,
6244 out_of_range_value: anytype,
6245) !Id {
6246 if (dimension >= 3) return try cg.constInt(result_ty, out_of_range_value);
6247 const u32_ty_id = try cg.module.intType(.unsigned, 32);
6248 const vec_ty_id = try cg.module.vectorType(3, u32_ty_id);
6249 const ptr_ty_id = try cg.module.ptrType(vec_ty_id, .input);
6250 const spv_decl_index = try cg.module.builtin(ptr_ty_id, builtin, .input);
63406251 try cg.decl_deps.put(cg.module.gpa, spv_decl_index, {});
6341 const ptr = cg.module.declPtr(spv_decl_index).result_id;
6342 const vec = try cg.load(vec_ty, ptr, .{});
6343 return try cg.extractVectorComponent(result_ty, vec, dimension);
6252 const ptr_id = cg.module.declPtr(spv_decl_index).result_id;
6253 const vec_id = cg.module.allocId();
6254 try cg.body.emit(cg.module.gpa, .OpLoad, .{
6255 .id_result_type = vec_ty_id,
6256 .id_result = vec_id,
6257 .pointer = ptr_id,
6258 });
6259 return try cg.extractVectorComponent(result_ty, vec_id, dimension);
63446260}
63456261
63466262fn airWorkItemId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63476263 if (cg.liveness.isUnused(inst)) return null;
63486264 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
63496265 const dimension = pl_op.payload;
6350 const result_id = try cg.builtin3D(.u32, .local_invocation_id, dimension, 0);
6351 const tmp: Temporary = .init(.u32, result_id);
6352 const result = try cg.buildConvert(.u32, tmp);
6353 return try result.materialize(cg);
6266 return try cg.builtin3D(.u32, .local_invocation_id, dimension, 0);
63546267}
63556268
6269// TODO: this must be an OpConstant/OpSpec but even then the driver crashes.
63566270fn airWorkGroupSize(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63576271 if (cg.liveness.isUnused(inst)) return null;
63586272 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
63596273 const dimension = pl_op.payload;
6360 const result_id = try cg.builtin3D(.u32, .workgroup_size, dimension, 0);
6361 const tmp: Temporary = .init(.u32, result_id);
6362 const result = try cg.buildConvert(.u32, tmp);
6363 return try result.materialize(cg);
6274 return try cg.builtin3D(.u32, .workgroup_id, dimension, 0);
63646275}
63656276
63666277fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
63676278 if (cg.liveness.isUnused(inst)) return null;
63686279 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
63696280 const dimension = pl_op.payload;
6370 const result_id = try cg.builtin3D(.u32, .workgroup_id, dimension, 0);
6371 const tmp: Temporary = .init(.u32, result_id);
6372 const result = try cg.buildConvert(.u32, tmp);
6373 return try result.materialize(cg);
6281 return try cg.builtin3D(.u32, .workgroup_id, dimension, 0);
63746282}
63756283
63766284fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
src/arch/spirv/Module.zig+87-30
......@@ -35,10 +35,7 @@ entry_points: std.AutoArrayHashMapUnmanaged(Id, EntryPoint) = .empty,
3535/// - It caches pointers by child-type. This is required because sometimes we rely on
3636/// ID-equality for pointers, and pointers constructed via `ptrType()` aren't interned
3737/// via the usual `intern_map` mechanism.
38ptr_types: std.AutoHashMapUnmanaged(
39 struct { Id, spec.StorageClass },
40 struct { ty_id: Id, fwd_emitted: bool },
41) = .{},
38ptr_types: std.AutoHashMapUnmanaged(struct { Id, spec.StorageClass }, Id) = .{},
4239/// For test declarations compiled for Vulkan target, we have to add a buffer.
4340/// We only need to generate this once, this holds the link information related to that.
4441error_buffer: ?Decl.Index = null,
......@@ -68,7 +65,7 @@ cache: struct {
6865 extensions: std.StringHashMapUnmanaged(void) = .empty,
6966 extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, Id) = .empty,
7067 decorations: std.AutoHashMapUnmanaged(struct { Id, spec.Decoration }, void) = .empty,
71 builtins: std.AutoHashMapUnmanaged(struct { Id, spec.BuiltIn }, Decl.Index) = .empty,
68 builtins: std.AutoHashMapUnmanaged(struct { spec.BuiltIn, spec.StorageClass }, Decl.Index) = .empty,
7269 strings: std.StringArrayHashMapUnmanaged(Id) = .empty,
7370
7471 bool_const: [2]?Id = .{ null, null },
......@@ -88,6 +85,8 @@ sections: struct {
8885 functions: Section = .{},
8986} = .{},
9087
88pub const big_int_bits = 32;
89
9190/// Data can be lowered into in two basic representations: indirect, which is when
9291/// a type is stored in memory, and direct, which is how a type is stored when its
9392/// a direct SPIR-V value.
......@@ -241,10 +240,6 @@ pub fn deinit(module: *Module) void {
241240
242241 module.decls.deinit(module.gpa);
243242 module.decl_deps.deinit(module.gpa);
244
245 for (module.entry_points.values()) |ep| {
246 module.gpa.free(ep.name);
247 }
248243 module.entry_points.deinit(module.gpa);
249244
250245 module.* = undefined;
......@@ -546,24 +541,68 @@ pub fn opaqueType(module: *Module, name: []const u8) !Id {
546541 return result_id;
547542}
548543
544pub fn backingIntBits(module: *Module, bits: u16) struct { u16, bool } {
545 assert(bits != 0);
546 const target = module.zcu.getTarget();
547
548 if (target.cpu.has(.spirv, .arbitrary_precision_integers) and bits <= 32) {
549 return .{ bits, false };
550 }
551
552 // We require Int8 and Int16 capabilities and benefit Int64 when available.
553 // 32-bit integers are always supported (see spec, 2.16.1, Data rules).
554 const ints = [_]struct { bits: u16, enabled: bool }{
555 .{ .bits = 8, .enabled = true },
556 .{ .bits = 16, .enabled = true },
557 .{ .bits = 32, .enabled = true },
558 .{
559 .bits = 64,
560 .enabled = target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64,
561 },
562 };
563
564 for (ints) |int| {
565 if (bits <= int.bits and int.enabled) return .{ int.bits, false };
566 }
567
568 // Big int
569 return .{ std.mem.alignForward(u16, bits, big_int_bits), true };
570}
571
549572pub fn intType(module: *Module, signedness: std.builtin.Signedness, bits: u16) !Id {
550573 assert(bits > 0);
551 const entry = try module.cache.int_types.getOrPut(module.gpa, .{ .signedness = signedness, .bits = bits });
574
575 const target = module.zcu.getTarget();
576 const actual_signedness = switch (target.os.tag) {
577 // Kernel only supports unsigned ints.
578 .opencl, .amdhsa => .unsigned,
579 else => signedness,
580 };
581 const backing_bits, const big_int = module.backingIntBits(bits);
582 if (big_int) {
583 // TODO: support composite integers larger than 64 bit
584 assert(backing_bits <= 64);
585 const u32_ty = try module.intType(.unsigned, 32);
586 const len_id = try module.constant(u32_ty, .{ .uint32 = backing_bits / big_int_bits });
587 return module.arrayType(len_id, u32_ty);
588 }
589
590 const entry = try module.cache.int_types.getOrPut(module.gpa, .{ .signedness = actual_signedness, .bits = backing_bits });
552591 if (!entry.found_existing) {
553592 const result_id = module.allocId();
554593 entry.value_ptr.* = result_id;
555594 try module.sections.globals.emit(module.gpa, .OpTypeInt, .{
556595 .id_result = result_id,
557 .width = bits,
558 .signedness = switch (signedness) {
596 .width = backing_bits,
597 .signedness = switch (actual_signedness) {
559598 .signed => 1,
560599 .unsigned => 0,
561600 },
562601 });
563602
564 switch (signedness) {
565 .signed => try module.debugNameFmt(result_id, "i{}", .{bits}),
566 .unsigned => try module.debugNameFmt(result_id, "u{}", .{bits}),
603 switch (actual_signedness) {
604 .signed => try module.debugNameFmt(result_id, "i{}", .{backing_bits}),
605 .unsigned => try module.debugNameFmt(result_id, "u{}", .{backing_bits}),
567606 }
568607 }
569608 return entry.value_ptr.*;
......@@ -612,6 +651,21 @@ pub fn arrayType(module: *Module, len_id: Id, child_ty_id: Id) !Id {
612651 return entry.value_ptr.*;
613652}
614653
654pub fn ptrType(module: *Module, child_ty_id: Id, storage_class: spec.StorageClass) !Id {
655 const key = .{ child_ty_id, storage_class };
656 const gop = try module.ptr_types.getOrPut(module.gpa, key);
657 if (!gop.found_existing) {
658 gop.value_ptr.* = module.allocId();
659 try module.sections.globals.emit(module.gpa, .OpTypePointer, .{
660 .id_result = gop.value_ptr.*,
661 .storage_class = storage_class,
662 .type = child_ty_id,
663 });
664 return gop.value_ptr.*;
665 }
666 return gop.value_ptr.*;
667}
668
615669pub fn structType(
616670 module: *Module,
617671 types: []const Id,
......@@ -683,16 +737,16 @@ pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const I
683737}
684738
685739pub fn constant(module: *Module, ty_id: Id, value: spec.LiteralContextDependentNumber) !Id {
686 const entry = try module.cache.constants.getOrPut(module.gpa, .{ .ty = ty_id, .value = value });
687 if (!entry.found_existing) {
688 entry.value_ptr.* = module.allocId();
740 const gop = try module.cache.constants.getOrPut(module.gpa, .{ .ty = ty_id, .value = value });
741 if (!gop.found_existing) {
742 gop.value_ptr.* = module.allocId();
689743 try module.sections.globals.emit(module.gpa, .OpConstant, .{
690744 .id_result_type = ty_id,
691 .id_result = entry.value_ptr.*,
745 .id_result = gop.value_ptr.*,
692746 .value = value,
693747 });
694748 }
695 return entry.value_ptr.*;
749 return gop.value_ptr.*;
696750}
697751
698752pub fn constBool(module: *Module, value: bool) !Id {
......@@ -716,23 +770,26 @@ pub fn constBool(module: *Module, value: bool) !Id {
716770 return result_id;
717771}
718772
719/// Return a pointer to a builtin variable. `result_ty_id` must be a **pointer**
720/// with storage class `.Input`.
721pub fn builtin(module: *Module, result_ty_id: Id, spirv_builtin: spec.BuiltIn) !Decl.Index {
722 const entry = try module.cache.builtins.getOrPut(module.gpa, .{ result_ty_id, spirv_builtin });
723 if (!entry.found_existing) {
773pub fn builtin(
774 module: *Module,
775 result_ty_id: Id,
776 spirv_builtin: spec.BuiltIn,
777 storage_class: spec.StorageClass,
778) !Decl.Index {
779 const gop = try module.cache.builtins.getOrPut(module.gpa, .{ spirv_builtin, storage_class });
780 if (!gop.found_existing) {
724781 const decl_index = try module.allocDecl(.global);
725782 const result_id = module.declPtr(decl_index).result_id;
726 entry.value_ptr.* = decl_index;
783 gop.value_ptr.* = decl_index;
727784 try module.sections.globals.emit(module.gpa, .OpVariable, .{
728785 .id_result_type = result_ty_id,
729786 .id_result = result_id,
730 .storage_class = .input,
787 .storage_class = storage_class,
731788 });
732789 try module.decorate(result_id, .{ .built_in = .{ .built_in = spirv_builtin } });
733790 try module.declareDeclDeps(decl_index, &.{});
734791 }
735 return entry.value_ptr.*;
792 return gop.value_ptr.*;
736793}
737794
738795pub fn constUndef(module: *Module, ty_id: Id) !Id {
......@@ -759,8 +816,8 @@ pub fn decorate(
759816 target: Id,
760817 decoration: spec.Decoration.Extended,
761818) !void {
762 const entry = try module.cache.decorations.getOrPut(module.gpa, .{ target, decoration });
763 if (!entry.found_existing) {
819 const gop = try module.cache.decorations.getOrPut(module.gpa, .{ target, decoration });
820 if (!gop.found_existing) {
764821 try module.sections.annotations.emit(module.gpa, .OpDecorate, .{
765822 .target = target,
766823 .decoration = decoration,