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 {...@@ -40,7 +40,6 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
40}40}
4141
42pub const zig_call_abi_ver = 3;42pub const zig_call_abi_ver = 3;
43pub const big_int_bits = 32;
4443
45const ControlFlow = union(enum) {44const ControlFlow = union(enum) {
46 const Structured = struct {45 const Structured = struct {
...@@ -183,6 +182,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -183,6 +182,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
183 const gpa = cg.module.gpa;182 const gpa = cg.module.gpa;
184 const zcu = cg.module.zcu;183 const zcu = cg.module.zcu;
185 const ip = &zcu.intern_pool;184 const ip = &zcu.intern_pool;
185 const target = zcu.getTarget();
186186
187 const nav = ip.getNav(cg.owner_nav);187 const nav = ip.getNav(cg.owner_nav);
188 const val = zcu.navValue(cg.owner_nav);188 const val = zcu.navValue(cg.owner_nav);
...@@ -251,19 +251,19 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -251,19 +251,19 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
251 // Append the actual code into the functions section.251 // Append the actual code into the functions section.
252 try cg.module.sections.functions.append(cg.module.gpa, cg.prologue);252 try cg.module.sections.functions.append(cg.module.gpa, cg.prologue);
253 try cg.module.sections.functions.append(cg.module.gpa, cg.body);253 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
258 // Temporarily generate a test kernel declaration if this is a test function.255 // Temporarily generate a test kernel declaration if this is a test function.
259 if (is_test) {256 if (is_test) {
260 try cg.generateTestEntryPoint(nav.fqn.toSlice(ip), spv_decl_index, func_result_id);257 try cg.generateTestEntryPoint(nav.fqn.toSlice(ip), spv_decl_index, func_result_id);
261 }258 }
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));
262 },262 },
263 .global => {263 .global => {
264 const maybe_init_val: ?Value = switch (ip.indexToKey(val.toIntern())) {264 const maybe_init_val: ?Value = switch (ip.indexToKey(val.toIntern())) {
265 .func => unreachable,265 .func => unreachable,
266 .variable => |variable| Value.fromInterned(variable.init),266 .variable => |variable| .fromInterned(variable.init),
267 .@"extern" => null,267 .@"extern" => null,
268 else => val,268 else => val,
269 };269 };
...@@ -272,7 +272,8 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -272,7 +272,8 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
272 const storage_class = cg.module.storageClass(nav.getAddrspace());272 const storage_class = cg.module.storageClass(nav.getAddrspace());
273 assert(storage_class != .generic); // These should be instance globals273 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
277 try cg.module.sections.globals.emit(cg.module.gpa, .OpVariable, .{278 try cg.module.sections.globals.emit(cg.module.gpa, .OpVariable, .{
278 .id_result_type = ptr_ty_id,279 .id_result_type = ptr_ty_id,
...@@ -280,6 +281,27 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -280,6 +281,27 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
280 .storage_class = storage_class,281 .storage_class = storage_class,
281 });282 });
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
283 if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |builtin| {305 if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |builtin| {
284 try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = builtin } });306 try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = builtin } });
285 }307 }
...@@ -290,18 +312,20 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -290,18 +312,20 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
290 .invocation_global => {312 .invocation_global => {
291 const maybe_init_val: ?Value = switch (ip.indexToKey(val.toIntern())) {313 const maybe_init_val: ?Value = switch (ip.indexToKey(val.toIntern())) {
292 .func => unreachable,314 .func => unreachable,
293 .variable => |variable| Value.fromInterned(variable.init),315 .variable => |variable| .fromInterned(variable.init),
294 .@"extern" => null,316 .@"extern" => null,
295 else => val,317 else => val,
296 };318 };
297319
298 try cg.module.declareDeclDeps(spv_decl_index, &.{});320 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
302 if (maybe_init_val) |init_val| {325 if (maybe_init_val) |init_val| {
303 // TODO: Combine with resolveAnonDecl?326 // 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
306 const initializer_id = cg.module.allocId();330 const initializer_id = cg.module.allocId();
307 try cg.prologue.emit(cg.module.gpa, .OpFunction, .{331 try cg.prologue.emit(cg.module.gpa, .OpFunction, .{
...@@ -406,7 +430,8 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -406,7 +430,8 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
406430
407 const zcu = cg.module.zcu;431 const zcu = cg.module.zcu;
408 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));432 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
411 const spv_decl_index = blk: {436 const spv_decl_index = blk: {
412 const entry = try cg.module.uav_link.getOrPut(cg.module.gpa, .{ val, .function });437 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 {...@@ -454,7 +479,8 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
454 cg.decl_deps.deinit(gpa);479 cg.decl_deps.deinit(gpa);
455 }480 }
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
459 const initializer_id = cg.module.allocId();485 const initializer_id = cg.module.allocId();
460 try cg.prologue.emit(cg.module.gpa, .OpFunction, .{486 try cg.prologue.emit(cg.module.gpa, .OpFunction, .{
...@@ -469,7 +495,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -469,7 +495,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
469 });495 });
470 cg.block_label = root_block_id;496 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);
473 try cg.body.emit(cg.module.gpa, .OpStore, .{499 try cg.body.emit(cg.module.gpa, .OpStore, .{
474 .pointer = result_id,500 .pointer = result_id,
475 .object = val_id,501 .object = val_id,
...@@ -484,7 +510,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -484,7 +510,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
484510
485 try cg.module.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});511 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);
488 try cg.module.sections.globals.emit(cg.module.gpa, .OpExtInst, .{514 try cg.module.sections.globals.emit(cg.module.gpa, .OpExtInst, .{
489 .id_result_type = fn_decl_ptr_ty_id,515 .id_result_type = fn_decl_ptr_ty_id,
490 .id_result = result_id,516 .id_result = result_id,
...@@ -533,44 +559,6 @@ fn beginSpvBlock(cg: *CodeGen, label: Id) !void {...@@ -533,44 +559,6 @@ fn beginSpvBlock(cg: *CodeGen, label: Id) !void {
533 cg.block_label = label;559 cg.block_label = label;
534}560}
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
574/// Return the amount of bits in the largest supported integer type. This is either 32 (always supported), or 64 (if562/// Return the amount of bits in the largest supported integer type. This is either 32 (always supported), or 64 (if
575/// the Int64 capability is enabled).563/// the Int64 capability is enabled).
576/// Note: The extension SPV_INTEL_arbitrary_precision_integers allows any integer size (at least up to 32 bits).564/// 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 {...@@ -632,7 +620,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
632 return switch (scalar_ty.zigTypeTag(zcu)) {620 return switch (scalar_ty.zigTypeTag(zcu)) {
633 .bool => .{621 .bool => .{
634 .bits = 1, // Doesn't matter for this class.622 .bits = 1, // Doesn't matter for this class.
635 .backing_bits = cg.backingIntBits(1).@"0",623 .backing_bits = cg.module.backingIntBits(1).@"0",
636 .vector_len = vector_len,624 .vector_len = vector_len,
637 .signedness = .unsigned, // Technically, but doesn't matter for this class.625 .signedness = .unsigned, // Technically, but doesn't matter for this class.
638 .class = .bool,626 .class = .bool,
...@@ -647,7 +635,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {...@@ -647,7 +635,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
647 .int => blk: {635 .int => blk: {
648 const int_info = scalar_ty.intInfo(zcu);636 const int_info = scalar_ty.intInfo(zcu);
649 // TODO: Maybe it's useful to also return this value.637 // 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);
651 break :blk .{639 break :blk .{
652 .bits = int_info.bits,640 .bits = int_info.bits,
653 .backing_bits = backing_bits,641 .backing_bits = backing_bits,
...@@ -711,7 +699,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {...@@ -711,7 +699,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
711 const scalar_ty = ty.scalarType(zcu);699 const scalar_ty = ty.scalarType(zcu);
712 const int_info = scalar_ty.intInfo(zcu);700 const int_info = scalar_ty.intInfo(zcu);
713 // Use backing bits so that negatives are sign extended701 // 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);
715 assert(backing_bits != 0); // u0 is comptime703 assert(backing_bits != 0); // u0 is comptime
716704
717 const result_ty_id = try cg.resolveType(scalar_ty, .indirect);705 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 {...@@ -922,8 +910,8 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
922 },910 },
923 .ptr => return cg.constantPtr(val),911 .ptr => return cg.constantPtr(val),
924 .slice => |slice| {912 .slice => |slice| {
925 const ptr_id = try cg.constantPtr(Value.fromInterned(slice.ptr));913 const ptr_id = try cg.constantPtr(.fromInterned(slice.ptr));
926 const len_id = try cg.constant(.usize, Value.fromInterned(slice.len), .indirect);914 const len_id = try cg.constant(.usize, .fromInterned(slice.len), .indirect);
927 const comp_ty_id = try cg.resolveType(ty, .direct);915 const comp_ty_id = try cg.resolveType(ty, .direct);
928 return try cg.constructComposite(comp_ty_id, &.{ ptr_id, len_id });916 return try cg.constructComposite(comp_ty_id, &.{ ptr_id, len_id });
929 },917 },
...@@ -977,11 +965,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -977,11 +965,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
977 },965 },
978 .elems => |elems| {966 .elems => |elems| {
979 for (constituents, elems) |*constituent, elem| {967 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);
981 }969 }
982 },970 },
983 .repeated_elem => |elem| {971 .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));
985 },973 },
986 }974 }
987975
...@@ -995,7 +983,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -995,7 +983,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
995 // TODO: composite int983 // TODO: composite int
996 // TODO: endianness984 // TODO: endianness
997 const bits: u16 = @intCast(ty.bitSize(zcu));985 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;
999 var limbs: [8]u8 = undefined;987 var limbs: [8]u8 = undefined;
1000 @memset(&limbs, 0);988 @memset(&limbs, 0);
1001 val.writeToPackedMemory(ty, pt, limbs[0..bytes], 0) catch unreachable;989 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 {...@@ -1035,13 +1023,13 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1035 if (un.tag == .none) {1023 if (un.tag == .none) {
1036 assert(ty.containerLayout(zcu) == .@"packed"); // TODO1024 assert(ty.containerLayout(zcu) == .@"packed"); // TODO
1037 const int_ty = try pt.intType(.unsigned, @intCast(ty.bitSize(zcu)));1025 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));
1039 }1027 }
1040 const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?;1028 const active_field = ty.unionTagFieldIndex(.fromInterned(un.tag), zcu).?;
1041 const union_obj = zcu.typeToUnion(ty).?;1029 const union_obj = zcu.typeToUnion(ty).?;
1042 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[active_field]);1030 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[active_field]);
1043 const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(zcu))1031 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)
1045 else1033 else
1046 null;1034 null;
1047 return try cg.unionInit(ty, active_field, payload);1035 return try cg.unionInit(ty, active_field, payload);
...@@ -1084,10 +1072,11 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {...@@ -1084,10 +1072,11 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1084 // that is not implemented by Mesa yet. Therefore, just generate it1072 // that is not implemented by Mesa yet. Therefore, just generate it
1085 // as a runtime operation.1073 // as a runtime operation.
1086 const result_ptr_id = cg.module.allocId();1074 const result_ptr_id = cg.module.allocId();
1075 const value_id = try cg.constInt(.usize, int.addr);
1087 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{1076 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{
1088 .id_result_type = result_ty_id,1077 .id_result_type = result_ty_id,
1089 .id_result = result_ptr_id,1078 .id_result = result_ptr_id,
1090 .integer_value = try cg.constant(.usize, try pt.intValue(.usize, int.addr), .direct),1079 .integer_value = value_id,
1091 });1080 });
1092 return result_ptr_id;1081 return result_ptr_id;
1093 },1082 },
...@@ -1174,7 +1163,8 @@ fn constantUavRef(...@@ -1174,7 +1163,8 @@ fn constantUavRef(
11741163
1175 // Uav refs are always generic.1164 // Uav refs are always generic.
1176 assert(ty.ptrAddressSpace(zcu) == .generic);1165 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);
1178 const ptr_id = try cg.resolveUav(uav.val);1168 const ptr_id = try cg.resolveUav(uav.val);
11791169
1180 if (decl_ptr_ty_id != ty_id) {1170 if (decl_ptr_ty_id != ty_id) {
...@@ -1228,7 +1218,8 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {...@@ -1228,7 +1218,8 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {
1228 const storage_class = cg.module.storageClass(nav.getAddrspace());1218 const storage_class = cg.module.storageClass(nav.getAddrspace());
1229 try cg.addFunctionDep(spv_decl_index, storage_class);1219 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
1233 const ptr_id = switch (storage_class) {1224 const ptr_id = switch (storage_class) {
1234 .generic => try cg.castToGeneric(decl_ptr_ty_id, decl_id),1225 .generic => try cg.castToGeneric(decl_ptr_ty_id, decl_id),
...@@ -1260,104 +1251,6 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {...@@ -1260,104 +1251,6 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
1260 return try aw.toOwnedSlice();1251 return try aw.toOwnedSlice();
1261}1252}
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
1361/// Generate a union type. Union types are always generated with the1254/// Generate a union type. Union types are always generated with the
1362/// most aligned field active. If the tag alignment is greater1255/// most aligned field active. If the tag alignment is greater
1363/// than that of the payload, a regular union (non-packed, with both tag and1256/// 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 {...@@ -1383,7 +1276,7 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
1383 const union_obj = zcu.typeToUnion(ty).?;1276 const union_obj = zcu.typeToUnion(ty).?;
13841277
1385 if (union_obj.flagsUnordered(ip).layout == .@"packed") {1278 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)));
1387 }1280 }
13881281
1389 const layout = cg.unionLayout(ty);1282 const layout = cg.unionLayout(ty);
...@@ -1410,13 +1303,15 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {...@@ -1410,13 +1303,15 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
1410 }1303 }
14111304
1412 if (layout.payload_padding_size != 0) {1305 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);
1414 member_types[layout.payload_padding_index] = payload_padding_ty_id;1308 member_types[layout.payload_padding_index] = payload_padding_ty_id;
1415 member_names[layout.payload_padding_index] = "(payload padding)";1309 member_names[layout.payload_padding_index] = "(payload padding)";
1416 }1310 }
14171311
1418 if (layout.padding_size != 0) {1312 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);
1420 member_types[layout.padding_index] = padding_ty_id;1315 member_types[layout.padding_index] = padding_ty_id;
1421 member_names[layout.padding_index] = "(padding)";1316 member_names[layout.padding_index] = "(padding)";
1422 }1317 }
...@@ -1479,7 +1374,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1479,7 +1374,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1479 assert(repr == .indirect);1374 assert(repr == .indirect);
1480 return try cg.module.opaqueType("u0");1375 return try cg.module.opaqueType("u0");
1481 }1376 }
1482 return try cg.intType(int_info.signedness, int_info.bits);1377 return try cg.module.intType(int_info.signedness, int_info.bits);
1483 },1378 },
1484 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),1379 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),
1485 .float => {1380 .float => {
...@@ -1519,9 +1414,11 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1519,9 +1414,11 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1519 // In this case, we have an array of a non-zero sized type. In this case,1414 // In this case, we have an array of a non-zero sized type. In this case,
1520 // generate an array of 1 element instead, so that ptr_elem_ptr instructions1415 // generate an array of 1 element instead, so that ptr_elem_ptr instructions
1521 // can be lowered to ptrAccessChain instead of manually performing the math.1416 // 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);
1523 } else {1419 } 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);
1525 switch (target.os.tag) {1422 switch (target.os.tag) {
1526 .vulkan, .opengl => {1423 .vulkan, .opengl => {
1527 try cg.module.decorate(result_id, .{1424 try cg.module.decorate(result_id, .{
...@@ -1540,7 +1437,8 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1540,7 +1437,8 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1540 const elem_ty_id = try cg.resolveType(elem_ty, repr);1437 const elem_ty_id = try cg.resolveType(elem_ty, repr);
1541 const len = ty.vectorLen(zcu);1438 const len = ty.vectorLen(zcu);
1542 if (cg.isSpvVector(ty)) return try cg.module.vectorType(len, elem_ty_id);1439 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);
1544 },1442 },
1545 .@"fn" => switch (repr) {1443 .@"fn" => switch (repr) {
1546 .direct => {1444 .direct => {
...@@ -1582,8 +1480,9 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1582,8 +1480,9 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1582 const ptr_info = ty.ptrInfo(zcu);1480 const ptr_info = ty.ptrInfo(zcu);
15831481
1584 const child_ty: Type = .fromInterned(ptr_info.child);1482 const child_ty: Type = .fromInterned(ptr_info.child);
1483 const child_ty_id = try cg.resolveType(child_ty, .indirect);
1585 const storage_class = cg.module.storageClass(ptr_info.flags.address_space);1484 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
1588 if (ptr_info.flags.size != .slice) {1487 if (ptr_info.flags.size != .slice) {
1589 return ptr_ty_id;1488 return ptr_ty_id;
...@@ -2142,7 +2041,7 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {...@@ -2142,7 +2041,7 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
21422041
2143 for (0..ops) |i| {2042 for (0..ops) |i| {
2144 try cg.body.emitRaw(cg.module.gpa, opcode, 3);2043 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);
2146 cg.body.writeOperand(Id, results.at(i));2045 cg.body.writeOperand(Id, results.at(i));
2147 cg.body.writeOperand(Id, op_src.at(i));2046 cg.body.writeOperand(Id, op_src.at(i));
2148 }2047 }
...@@ -2277,7 +2176,7 @@ fn buildCmp(cg: *CodeGen, pred: CmpPredicate, lhs: Temporary, rhs: Temporary) !T...@@ -2277,7 +2176,7 @@ fn buildCmp(cg: *CodeGen, pred: CmpPredicate, lhs: Temporary, rhs: Temporary) !T
22772176
2278 for (0..ops) |i| {2177 for (0..ops) |i| {
2279 try cg.body.emitRaw(cg.module.gpa, opcode, 4);2178 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);
2281 cg.body.writeOperand(Id, results.at(i));2180 cg.body.writeOperand(Id, results.at(i));
2282 cg.body.writeOperand(Id, op_lhs.at(i));2181 cg.body.writeOperand(Id, op_lhs.at(i));
2283 cg.body.writeOperand(Id, op_rhs.at(i));2182 cg.body.writeOperand(Id, op_rhs.at(i));
...@@ -2331,7 +2230,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {...@@ -2331,7 +2230,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
2331 }) |opcode| {2230 }) |opcode| {
2332 for (0..ops) |i| {2231 for (0..ops) |i| {
2333 try cg.body.emitRaw(cg.module.gpa, opcode, 3);2232 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);
2335 cg.body.writeOperand(Id, results.at(i));2234 cg.body.writeOperand(Id, results.at(i));
2336 cg.body.writeOperand(Id, op_operand.at(i));2235 cg.body.writeOperand(Id, op_operand.at(i));
2337 }2236 }
...@@ -2472,7 +2371,7 @@ fn buildBinary(cg: *CodeGen, op: BinaryOp, lhs: Temporary, rhs: Temporary) !Temp...@@ -2472,7 +2371,7 @@ fn buildBinary(cg: *CodeGen, op: BinaryOp, lhs: Temporary, rhs: Temporary) !Temp
2472 }) |opcode| {2371 }) |opcode| {
2473 for (0..ops) |i| {2372 for (0..ops) |i| {
2474 try cg.body.emitRaw(cg.module.gpa, opcode, 4);2373 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);
2476 cg.body.writeOperand(Id, results.at(i));2375 cg.body.writeOperand(Id, results.at(i));
2477 cg.body.writeOperand(Id, op_lhs.at(i));2376 cg.body.writeOperand(Id, op_lhs.at(i));
2478 cg.body.writeOperand(Id, op_rhs.at(i));2377 cg.body.writeOperand(Id, op_rhs.at(i));
...@@ -2591,7 +2490,7 @@ fn buildWideMul(...@@ -2591,7 +2490,7 @@ fn buildWideMul(
2591 const op_result = cg.module.allocId();2490 const op_result = cg.module.allocId();
25922491
2593 try cg.body.emitRaw(cg.module.gpa, opcode, 4);2492 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);
2595 cg.body.writeOperand(Id, op_result);2494 cg.body.writeOperand(Id, op_result);
2596 cg.body.writeOperand(Id, lhs_op.at(i));2495 cg.body.writeOperand(Id, lhs_op.at(i));
2597 cg.body.writeOperand(Id, rhs_op.at(i));2496 cg.body.writeOperand(Id, rhs_op.at(i));
...@@ -2664,30 +2563,27 @@ fn generateTestEntryPoint(...@@ -2664,30 +2563,27 @@ fn generateTestEntryPoint(
26642563
2665 const kernel_id = cg.module.declPtr(spv_decl_index).result_id;2564 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
2671 const section = &cg.module.sections.functions;2566 const section = &cg.module.sections.functions;
26722567
2673 const p_error_id = cg.module.allocId();2568 const p_error_id = cg.module.allocId();
2674 switch (target.os.tag) {2569 switch (target.os.tag) {
2675 .opencl, .amdhsa => {2570 .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, .{
2679 .id_result_type = try cg.resolveType(.void, .direct),2575 .id_result_type = try cg.resolveType(.void, .direct),
2680 .id_result = kernel_id,2576 .id_result = kernel_id,
2681 .function_control = .{},2577 .function_control = .{},
2682 .function_type = kernel_proto_ty_id,2578 .function_type = kernel_proto_ty_id,
2683 });2579 });
26842580
2685 try section.emit(cg.module.gpa, .OpFunctionParameter, .{2581 try section.emit(gpa, .OpFunctionParameter, .{
2686 .id_result_type = ptr_anyerror_ty_id,2582 .id_result_type = ptr_anyerror_ty_id,
2687 .id_result = p_error_id,2583 .id_result = p_error_id,
2688 });2584 });
26892585
2690 try section.emit(cg.module.gpa, .OpLabel, .{2586 try section.emit(gpa, .OpLabel, .{
2691 .id_result = cg.module.allocId(),2587 .id_result = cg.module.allocId(),
2692 });2588 });
2693 },2589 },
...@@ -2706,14 +2602,14 @@ fn generateTestEntryPoint(...@@ -2706,14 +2602,14 @@ fn generateTestEntryPoint(
2706 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });2602 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });
27072603
2708 const ptr_buffer_struct_ty_id = cg.module.allocId();2604 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, .{
2710 .id_result = ptr_buffer_struct_ty_id,2606 .id_result = ptr_buffer_struct_ty_id,
2711 .storage_class = cg.module.storageClass(.global),2607 .storage_class = cg.module.storageClass(.global),
2712 .type = buffer_struct_ty_id,2608 .type = buffer_struct_ty_id,
2713 });2609 });
27142610
2715 const buffer_struct_id = cg.module.declPtr(spv_err_decl_index).result_id;2611 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, .{
2717 .id_result_type = ptr_buffer_struct_ty_id,2613 .id_result_type = ptr_buffer_struct_ty_id,
2718 .id_result = buffer_struct_id,2614 .id_result = buffer_struct_id,
2719 .storage_class = cg.module.storageClass(.global),2615 .storage_class = cg.module.storageClass(.global),
...@@ -2724,7 +2620,7 @@ fn generateTestEntryPoint(...@@ -2724,7 +2620,7 @@ fn generateTestEntryPoint(
2724 cg.module.error_buffer = spv_err_decl_index;2620 cg.module.error_buffer = spv_err_decl_index;
2725 }2621 }
27262622
2727 try cg.module.sections.execution_modes.emit(cg.module.gpa, .OpExecutionMode, .{2623 try cg.module.sections.execution_modes.emit(gpa, .OpExecutionMode, .{
2728 .entry_point = kernel_id,2624 .entry_point = kernel_id,
2729 .mode = .{ .local_size = .{2625 .mode = .{ .local_size = .{
2730 .x_size = 1,2626 .x_size = 1,
...@@ -2733,23 +2629,24 @@ fn generateTestEntryPoint(...@@ -2733,23 +2629,24 @@ fn generateTestEntryPoint(
2733 } },2629 } },
2734 });2630 });
27352631
2736 const kernel_proto_ty_id = try cg.functionType(.void, &.{});2632 const void_ty_id = try cg.resolveType(.void, .direct);
2737 try section.emit(cg.module.gpa, .OpFunction, .{2633 const kernel_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});
2634 try section.emit(gpa, .OpFunction, .{
2738 .id_result_type = try cg.resolveType(.void, .direct),2635 .id_result_type = try cg.resolveType(.void, .direct),
2739 .id_result = kernel_id,2636 .id_result = kernel_id,
2740 .function_control = .{},2637 .function_control = .{},
2741 .function_type = kernel_proto_ty_id,2638 .function_type = kernel_proto_ty_id,
2742 });2639 });
2743 try section.emit(cg.module.gpa, .OpLabel, .{2640 try section.emit(gpa, .OpLabel, .{
2744 .id_result = cg.module.allocId(),2641 .id_result = cg.module.allocId(),
2745 });2642 });
27462643
2747 const spv_err_decl_index = cg.module.error_buffer.?;2644 const spv_err_decl_index = cg.module.error_buffer.?;
2748 const buffer_id = cg.module.declPtr(spv_err_decl_index).result_id;2645 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
2751 const zero_id = try cg.constInt(.u32, 0);2648 const zero_id = try cg.constInt(.u32, 0);
2752 try section.emit(cg.module.gpa, .OpInBoundsAccessChain, .{2649 try section.emit(gpa, .OpInBoundsAccessChain, .{
2753 .id_result_type = ptr_anyerror_ty_id,2650 .id_result_type = ptr_anyerror_ty_id,
2754 .id_result = p_error_id,2651 .id_result = p_error_id,
2755 .base = buffer_id,2652 .base = buffer_id,
...@@ -2760,25 +2657,25 @@ fn generateTestEntryPoint(...@@ -2760,25 +2657,25 @@ fn generateTestEntryPoint(
2760 }2657 }
27612658
2762 const error_id = cg.module.allocId();2659 const error_id = cg.module.allocId();
2763 try section.emit(cg.module.gpa, .OpFunctionCall, .{2660 try section.emit(gpa, .OpFunctionCall, .{
2764 .id_result_type = anyerror_ty_id,2661 .id_result_type = anyerror_ty_id,
2765 .id_result = error_id,2662 .id_result = error_id,
2766 .function = test_id,2663 .function = test_id,
2767 });2664 });
2768 // Note: Convert to direct not required.2665 // Note: Convert to direct not required.
2769 try section.emit(cg.module.gpa, .OpStore, .{2666 try section.emit(gpa, .OpStore, .{
2770 .pointer = p_error_id,2667 .pointer = p_error_id,
2771 .object = error_id,2668 .object = error_id,
2772 .memory_access = .{2669 .memory_access = .{
2773 .aligned = .{ .literal_integer = @intCast(Type.abiAlignment(.anyerror, zcu).toByteUnits().?) },2670 .aligned = .{ .literal_integer = @intCast(Type.abiAlignment(.anyerror, zcu).toByteUnits().?) },
2774 },2671 },
2775 });2672 });
2776 try section.emit(cg.module.gpa, .OpReturn, {});2673 try section.emit(gpa, .OpReturn, {});
2777 try section.emit(cg.module.gpa, .OpFunctionEnd, {});2674 try section.emit(gpa, .OpFunctionEnd, {});
27782675
2779 // Just generate a quick other name because the intel runtime crashes when the entry-2676 // Just generate a quick other name because the intel runtime crashes when the entry-
2780 // point name is the same as a different OpName.2677 // 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
2783 const execution_mode: spec.ExecutionModel = switch (target.os.tag) {2680 const execution_mode: spec.ExecutionModel = switch (target.os.tag) {
2784 .vulkan, .opengl => .gl_compute,2681 .vulkan, .opengl => .gl_compute,
...@@ -2786,7 +2683,6 @@ fn generateTestEntryPoint(...@@ -2786,7 +2683,6 @@ fn generateTestEntryPoint(
2786 else => unreachable,2683 else => unreachable,
2787 };2684 };
27882685
2789 try cg.module.declareDeclDeps(spv_decl_index, decl_deps.items);
2790 try cg.module.declareEntryPoint(spv_decl_index, test_name, execution_mode, null);2686 try cg.module.declareEntryPoint(spv_decl_index, test_name, execution_mode, null);
2791}2687}
27922688
...@@ -3760,10 +3656,10 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -3760,10 +3656,10 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3760 result_id = cg.module.allocId();3656 result_id = cg.module.allocId();
37613657
3762 try cg.body.emitRaw(cg.module.gpa, opcode, 4);3658 try cg.body.emitRaw(cg.module.gpa, opcode, 4);
3763 cg.body.writeOperand(spec.Id, scalar_ty_id);3659 cg.body.writeOperand(Id, scalar_ty_id);
3764 cg.body.writeOperand(spec.Id, result_id);3660 cg.body.writeOperand(Id, result_id);
3765 cg.body.writeOperand(spec.Id, lhs);3661 cg.body.writeOperand(Id, lhs);
3766 cg.body.writeOperand(spec.Id, rhs);3662 cg.body.writeOperand(Id, rhs);
3767 }3663 }
37683664
3769 return result_id;3665 return result_id;
...@@ -4189,7 +4085,7 @@ fn bitCast(...@@ -4189,7 +4085,7 @@ fn bitCast(
4189 break :blk result_id;4085 break :blk result_id;
4190 }4086 }
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
4194 const tmp_id = try cg.alloc(src_ty, .{ .storage_class = .function });4090 const tmp_id = try cg.alloc(src_ty, .{ .storage_class = .function });
4195 try cg.store(src_ty, tmp_id, src_id, .{});4091 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 {...@@ -4594,7 +4490,8 @@ fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
4594 const zcu = cg.module.zcu;4490 const zcu = cg.module.zcu;
4595 // Construct new pointer type for the resulting pointer4491 // Construct new pointer type for the resulting pointer
4596 const elem_ty = ptr_ty.elemType2(zcu); // use elemType() so that we get T for *[N]T.4492 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)));
4598 if (ptr_ty.isSinglePointer(zcu)) {4495 if (ptr_ty.isSinglePointer(zcu)) {
4599 // Pointer-to-array. In this case, the resulting pointer is not of the same type4496 // Pointer-to-array. In this case, the resulting pointer is not of the same type
4600 // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain.4497 // 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 {...@@ -4637,8 +4534,10 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4637 const is_vector = array_ty.isVector(zcu);4534 const is_vector = array_ty.isVector(zcu);
46384535
4639 const elem_repr: Repr = if (is_vector) .direct else .indirect;4536 const elem_repr: Repr = if (is_vector) .direct else .indirect;
4640 const ptr_array_ty_id = try cg.ptrType(array_ty, .function, .direct);4537 const array_ty_id = try cg.resolveType(array_ty, .direct);
4641 const ptr_elem_ty_id = try cg.ptrType(elem_ty, .function, elem_repr);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
4643 const tmp_id = cg.module.allocId();4542 const tmp_id = cg.module.allocId();
4644 try cg.prologue.emit(cg.module.gpa, .OpVariable, .{4543 try cg.prologue.emit(cg.module.gpa, .OpVariable, .{
...@@ -4692,8 +4591,9 @@ fn airVectorStoreElem(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -4692,8 +4591,9 @@ fn airVectorStoreElem(cg: *CodeGen, inst: Air.Inst.Index) !void {
4692 const vector_ty = vector_ptr_ty.childType(zcu);4591 const vector_ty = vector_ptr_ty.childType(zcu);
4693 const scalar_ty = vector_ty.scalarType(zcu);4592 const scalar_ty = vector_ty.scalarType(zcu);
46944593
4594 const scalar_ty_id = try cg.resolveType(scalar_ty, .indirect);
4695 const storage_class = cg.module.storageClass(vector_ptr_ty.ptrAddressSpace(zcu));4595 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
4698 const vector_ptr = try cg.resolve(data.vector_ptr);4598 const vector_ptr = try cg.resolve(data.vector_ptr);
4699 const index = try cg.resolve(extra.lhs);4599 const index = try cg.resolve(extra.lhs);
...@@ -4715,7 +4615,8 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -4715,7 +4615,8 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
4715 if (layout.tag_size == 0) return;4615 if (layout.tag_size == 0) return;
47164616
4717 const tag_ty = un_ty.unionTagTypeSafety(zcu).?;4617 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
4720 const union_ptr_id = try cg.resolve(bin_op.lhs);4621 const union_ptr_id = try cg.resolve(bin_op.lhs);
4721 const new_tag_id = try cg.resolve(bin_op.rhs);4622 const new_tag_id = try cg.resolve(bin_op.rhs);
...@@ -4802,17 +4703,20 @@ fn unionInit(...@@ -4802,17 +4703,20 @@ fn unionInit(
4802 const tmp_id = try cg.alloc(ty, .{ .storage_class = .function });4703 const tmp_id = try cg.alloc(ty, .{ .storage_class = .function });
48034704
4804 if (layout.tag_size != 0) {4705 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);
4806 const ptr_id = try cg.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});4708 const ptr_id = try cg.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});
4807 const tag_id = try cg.constInt(tag_ty, tag_int);4709 const tag_id = try cg.constInt(tag_ty, tag_int);
4808 try cg.store(tag_ty, ptr_id, tag_id, .{});4710 try cg.store(tag_ty, ptr_id, tag_id, .{});
4809 }4711 }
48104712
4811 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4713 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);
4813 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});4716 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
4814 const active_pl_ptr_id = if (!layout.payload_ty.eql(payload_ty, zcu)) blk: {4717 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);
4816 const active_pl_ptr_id = cg.module.allocId();4720 const active_pl_ptr_id = cg.module.allocId();
4817 try cg.body.emit(cg.module.gpa, .OpBitcast, .{4721 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
4818 .id_result_type = active_pl_ptr_ty_id,4722 .id_result_type = active_pl_ptr_ty_id,
...@@ -4876,7 +4780,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4876,7 +4780,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4876 const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1);4780 const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1);
4877 const masked = try cg.buildBinary(.bit_and, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } });4781 const masked = try cg.buildBinary(.bit_and, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } });
4878 const result_id = blk: {4782 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")
4880 break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg));4784 break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg));
4881 const trunc = try cg.buildConvert(field_int_ty, masked);4785 const trunc = try cg.buildConvert(field_int_ty, masked);
4882 break :blk try trunc.materialize(cg);4786 break :blk try trunc.materialize(cg);
...@@ -4900,7 +4804,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4900,7 +4804,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4900 .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } },4804 .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } },
4901 );4805 );
4902 const result_id = blk: {4806 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")
4904 break :blk try cg.bitCast(int_ty, backing_int_ty, try masked.materialize(cg));4808 break :blk try cg.bitCast(int_ty, backing_int_ty, try masked.materialize(cg));
4905 const trunc = try cg.buildConvert(int_ty, masked);4809 const trunc = try cg.buildConvert(int_ty, masked);
4906 break :blk try trunc.materialize(cg);4810 break :blk try trunc.materialize(cg);
...@@ -4917,10 +4821,12 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4917,10 +4821,12 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4917 const tmp_id = try cg.alloc(object_ty, .{ .storage_class = .function });4821 const tmp_id = try cg.alloc(object_ty, .{ .storage_class = .function });
4918 try cg.store(object_ty, tmp_id, object_id, .{});4822 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);
4921 const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});4826 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);
4924 const active_pl_ptr_id = cg.module.allocId();4830 const active_pl_ptr_id = cg.module.allocId();
4925 try cg.body.emit(cg.module.gpa, .OpBitcast, .{4831 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
4926 .id_result_type = active_pl_ptr_ty_id,4832 .id_result_type = active_pl_ptr_ty_id,
...@@ -4997,7 +4903,8 @@ fn structFieldPtr(...@@ -4997,7 +4903,8 @@ fn structFieldPtr(
4997 }4903 }
49984904
4999 const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu));4905 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);
5001 const pl_ptr_id = blk: {4908 const pl_ptr_id = blk: {
5002 if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;4909 if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;
5003 break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});4910 break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
...@@ -5041,7 +4948,8 @@ fn alloc(...@@ -5041,7 +4948,8 @@ fn alloc(
5041 options: AllocOptions,4948 options: AllocOptions,
5042) !Id {4949) !Id {
5043 const target = cg.module.zcu.getTarget();4950 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
5046 // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to4954 // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to
5047 // directly generate them into func.prologue instead of the body.4955 // directly generate them into func.prologue instead of the body.
...@@ -5060,7 +4968,7 @@ fn alloc(...@@ -5060,7 +4968,7 @@ fn alloc(
50604968
5061 switch (options.storage_class) {4969 switch (options.storage_class) {
5062 .generic => {4970 .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);
5064 // Convert to a generic pointer4972 // Convert to a generic pointer
5065 return cg.castToGeneric(ptr_gn_ty_id, var_id);4973 return cg.castToGeneric(ptr_gn_ty_id, var_id);
5066 },4974 },
...@@ -5093,8 +5001,8 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const ControlFlow.Structured.Bl...@@ -5093,8 +5001,8 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const ControlFlow.Structured.Bl
5093 const result_id = cg.module.allocId();5001 const result_id = cg.module.allocId();
5094 const block_id_ty_id = try cg.resolveType(.u32, .direct);5002 const block_id_ty_id = try cg.resolveType(.u32, .direct);
5095 try cg.body.emitRaw(cg.module.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent...5003 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);5004 cg.body.writeOperand(Id, block_id_ty_id);
5097 cg.body.writeOperand(spec.Id, result_id);5005 cg.body.writeOperand(Id, result_id);
50985006
5099 for (incoming) |incoming_block| {5007 for (incoming) |incoming_block| {
5100 cg.body.writeOperand(spec.PairIdRefIdRef, .{ incoming_block.next_block, incoming_block.src_label });5008 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)...@@ -5285,8 +5193,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
5285 // result type + result + variable/parent...5193 // result type + result + variable/parent...
5286 2 + @as(u16, @intCast(block.incoming_blocks.items.len * 2)),5194 2 + @as(u16, @intCast(block.incoming_blocks.items.len * 2)),
5287 );5195 );
5288 cg.body.writeOperand(spec.Id, result_type_id);5196 cg.body.writeOperand(Id, result_type_id);
5289 cg.body.writeOperand(spec.Id, result_id);5197 cg.body.writeOperand(Id, result_id);
52905198
5291 for (block.incoming_blocks.items) |incoming| {5199 for (block.incoming_blocks.items) |incoming| {
5292 cg.body.writeOperand(5200 cg.body.writeOperand(
...@@ -5793,7 +5701,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {...@@ -5793,7 +5701,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
5793 if (is_pointer) {5701 if (is_pointer) {
5794 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {5702 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
5795 const storage_class = cg.module.storageClass(operand_ty.ptrAddressSpace(zcu));5703 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);
5797 const tag_ptr_id = try cg.accessChain(bool_ptr_ty_id, operand_id, &.{1});5706 const tag_ptr_id = try cg.accessChain(bool_ptr_ty_id, operand_id, &.{1});
5798 break :blk try cg.load(.bool, tag_ptr_id, .{});5707 break :blk try cg.load(.bool, tag_ptr_id, .{});
5799 }5708 }
...@@ -5939,14 +5848,14 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5939,14 +5848,14 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
5939 .bool, .error_set => 1,5848 .bool, .error_set => 1,
5940 .int => blk: {5849 .int => blk: {
5941 const bits = cond_ty.intInfo(zcu).bits;5850 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);
5943 if (big_int) return cg.todo("implement composite int switch", .{});5852 if (big_int) return cg.todo("implement composite int switch", .{});
5944 break :blk if (backing_bits <= 32) 1 else 2;5853 break :blk if (backing_bits <= 32) 1 else 2;
5945 },5854 },
5946 .@"enum" => blk: {5855 .@"enum" => blk: {
5947 const int_ty = cond_ty.intTagType(zcu);5856 const int_ty = cond_ty.intTagType(zcu);
5948 const int_info = int_ty.intInfo(zcu);5857 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);
5950 if (big_int) return cg.todo("implement composite int switch", .{});5859 if (big_int) return cg.todo("implement composite int switch", .{});
5951 break :blk if (backing_bits <= 32) 1 else 2;5860 break :blk if (backing_bits <= 32) 1 else 2;
5952 },5861 },
...@@ -6298,7 +6207,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -6298,7 +6207,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
6298 const callee_id = try cg.resolve(pl_op.operand);6207 const callee_id = try cg.resolve(pl_op.operand);
62996208
6300 comptime assert(zig_call_abi_ver == 3);6209 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);
6302 defer gpa.free(params);6211 defer gpa.free(params);
6303 var n_params: usize = 0;6212 var n_params: usize = 0;
6304 for (args) |arg| {6213 for (args) |arg| {
...@@ -6327,50 +6236,49 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -6327,50 +6236,49 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
6327 return result_id;6236 return result_id;
6328}6237}
63296238
6330fn builtin3D(cg: *CodeGen, result_ty: Type, builtin: spec.BuiltIn, dimension: u32, out_of_range_value: anytype) !Id {6239fn builtin3D(
6331 if (dimension >= 3) {6240 cg: *CodeGen,
6332 return try cg.constInt(result_ty, out_of_range_value);6241 result_ty: Type,
6333 }6242 builtin: spec.BuiltIn,
6334 const vec_ty = try cg.pt.vectorType(.{6243 dimension: u32,
6335 .len = 3,6244 out_of_range_value: anytype,
6336 .child = result_ty.toIntern(),6245) !Id {
6337 });6246 if (dimension >= 3) return try cg.constInt(result_ty, out_of_range_value);
6338 const ptr_ty_id = try cg.ptrType(vec_ty, .input, .indirect);6247 const u32_ty_id = try cg.module.intType(.unsigned, 32);
6339 const spv_decl_index = try cg.module.builtin(ptr_ty_id, builtin);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);
6340 try cg.decl_deps.put(cg.module.gpa, spv_decl_index, {});6251 try cg.decl_deps.put(cg.module.gpa, spv_decl_index, {});
6341 const ptr = cg.module.declPtr(spv_decl_index).result_id;6252 const ptr_id = cg.module.declPtr(spv_decl_index).result_id;
6342 const vec = try cg.load(vec_ty, ptr, .{});6253 const vec_id = cg.module.allocId();
6343 return try cg.extractVectorComponent(result_ty, vec, dimension);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);
6344}6260}
63456261
6346fn airWorkItemId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6262fn airWorkItemId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6347 if (cg.liveness.isUnused(inst)) return null;6263 if (cg.liveness.isUnused(inst)) return null;
6348 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6264 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6349 const dimension = pl_op.payload;6265 const dimension = pl_op.payload;
6350 const result_id = try cg.builtin3D(.u32, .local_invocation_id, dimension, 0);6266 return 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);
6354}6267}
63556268
6269// TODO: this must be an OpConstant/OpSpec but even then the driver crashes.
6356fn airWorkGroupSize(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6270fn airWorkGroupSize(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6357 if (cg.liveness.isUnused(inst)) return null;6271 if (cg.liveness.isUnused(inst)) return null;
6358 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6272 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6359 const dimension = pl_op.payload;6273 const dimension = pl_op.payload;
6360 const result_id = try cg.builtin3D(.u32, .workgroup_size, dimension, 0);6274 return try cg.builtin3D(.u32, .workgroup_id, dimension, 0);
6361 const tmp: Temporary = .init(.u32, result_id);
6362 const result = try cg.buildConvert(.u32, tmp);
6363 return try result.materialize(cg);
6364}6275}
63656276
6366fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6277fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6367 if (cg.liveness.isUnused(inst)) return null;6278 if (cg.liveness.isUnused(inst)) return null;
6368 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6279 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6369 const dimension = pl_op.payload;6280 const dimension = pl_op.payload;
6370 const result_id = try cg.builtin3D(.u32, .workgroup_id, dimension, 0);6281 return 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);
6374}6282}
63756283
6376fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {6284fn 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,...@@ -35,10 +35,7 @@ entry_points: std.AutoArrayHashMapUnmanaged(Id, EntryPoint) = .empty,
35/// - It caches pointers by child-type. This is required because sometimes we rely on35/// - It caches pointers by child-type. This is required because sometimes we rely on
36/// ID-equality for pointers, and pointers constructed via `ptrType()` aren't interned36/// ID-equality for pointers, and pointers constructed via `ptrType()` aren't interned
37/// via the usual `intern_map` mechanism.37/// via the usual `intern_map` mechanism.
38ptr_types: std.AutoHashMapUnmanaged(38ptr_types: std.AutoHashMapUnmanaged(struct { Id, spec.StorageClass }, Id) = .{},
39 struct { Id, spec.StorageClass },
40 struct { ty_id: Id, fwd_emitted: bool },
41) = .{},
42/// For test declarations compiled for Vulkan target, we have to add a buffer.39/// For test declarations compiled for Vulkan target, we have to add a buffer.
43/// We only need to generate this once, this holds the link information related to that.40/// We only need to generate this once, this holds the link information related to that.
44error_buffer: ?Decl.Index = null,41error_buffer: ?Decl.Index = null,
...@@ -68,7 +65,7 @@ cache: struct {...@@ -68,7 +65,7 @@ cache: struct {
68 extensions: std.StringHashMapUnmanaged(void) = .empty,65 extensions: std.StringHashMapUnmanaged(void) = .empty,
69 extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, Id) = .empty,66 extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, Id) = .empty,
70 decorations: std.AutoHashMapUnmanaged(struct { Id, spec.Decoration }, void) = .empty,67 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,
72 strings: std.StringArrayHashMapUnmanaged(Id) = .empty,69 strings: std.StringArrayHashMapUnmanaged(Id) = .empty,
7370
74 bool_const: [2]?Id = .{ null, null },71 bool_const: [2]?Id = .{ null, null },
...@@ -88,6 +85,8 @@ sections: struct {...@@ -88,6 +85,8 @@ sections: struct {
88 functions: Section = .{},85 functions: Section = .{},
89} = .{},86} = .{},
9087
88pub const big_int_bits = 32;
89
91/// Data can be lowered into in two basic representations: indirect, which is when90/// Data can be lowered into in two basic representations: indirect, which is when
92/// a type is stored in memory, and direct, which is how a type is stored when its91/// a type is stored in memory, and direct, which is how a type is stored when its
93/// a direct SPIR-V value.92/// a direct SPIR-V value.
...@@ -241,10 +240,6 @@ pub fn deinit(module: *Module) void {...@@ -241,10 +240,6 @@ pub fn deinit(module: *Module) void {
241240
242 module.decls.deinit(module.gpa);241 module.decls.deinit(module.gpa);
243 module.decl_deps.deinit(module.gpa);242 module.decl_deps.deinit(module.gpa);
244
245 for (module.entry_points.values()) |ep| {
246 module.gpa.free(ep.name);
247 }
248 module.entry_points.deinit(module.gpa);243 module.entry_points.deinit(module.gpa);
249244
250 module.* = undefined;245 module.* = undefined;
...@@ -546,24 +541,68 @@ pub fn opaqueType(module: *Module, name: []const u8) !Id {...@@ -546,24 +541,68 @@ pub fn opaqueType(module: *Module, name: []const u8) !Id {
546 return result_id;541 return result_id;
547}542}
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
549pub fn intType(module: *Module, signedness: std.builtin.Signedness, bits: u16) !Id {572pub fn intType(module: *Module, signedness: std.builtin.Signedness, bits: u16) !Id {
550 assert(bits > 0);573 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 });
552 if (!entry.found_existing) {591 if (!entry.found_existing) {
553 const result_id = module.allocId();592 const result_id = module.allocId();
554 entry.value_ptr.* = result_id;593 entry.value_ptr.* = result_id;
555 try module.sections.globals.emit(module.gpa, .OpTypeInt, .{594 try module.sections.globals.emit(module.gpa, .OpTypeInt, .{
556 .id_result = result_id,595 .id_result = result_id,
557 .width = bits,596 .width = backing_bits,
558 .signedness = switch (signedness) {597 .signedness = switch (actual_signedness) {
559 .signed => 1,598 .signed => 1,
560 .unsigned => 0,599 .unsigned => 0,
561 },600 },
562 });601 });
563602
564 switch (signedness) {603 switch (actual_signedness) {
565 .signed => try module.debugNameFmt(result_id, "i{}", .{bits}),604 .signed => try module.debugNameFmt(result_id, "i{}", .{backing_bits}),
566 .unsigned => try module.debugNameFmt(result_id, "u{}", .{bits}),605 .unsigned => try module.debugNameFmt(result_id, "u{}", .{backing_bits}),
567 }606 }
568 }607 }
569 return entry.value_ptr.*;608 return entry.value_ptr.*;
...@@ -612,6 +651,21 @@ pub fn arrayType(module: *Module, len_id: Id, child_ty_id: Id) !Id {...@@ -612,6 +651,21 @@ pub fn arrayType(module: *Module, len_id: Id, child_ty_id: Id) !Id {
612 return entry.value_ptr.*;651 return entry.value_ptr.*;
613}652}
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
615pub fn structType(669pub fn structType(
616 module: *Module,670 module: *Module,
617 types: []const Id,671 types: []const Id,
...@@ -683,16 +737,16 @@ pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const I...@@ -683,16 +737,16 @@ pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const I
683}737}
684738
685pub fn constant(module: *Module, ty_id: Id, value: spec.LiteralContextDependentNumber) !Id {739pub 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 });740 const gop = try module.cache.constants.getOrPut(module.gpa, .{ .ty = ty_id, .value = value });
687 if (!entry.found_existing) {741 if (!gop.found_existing) {
688 entry.value_ptr.* = module.allocId();742 gop.value_ptr.* = module.allocId();
689 try module.sections.globals.emit(module.gpa, .OpConstant, .{743 try module.sections.globals.emit(module.gpa, .OpConstant, .{
690 .id_result_type = ty_id,744 .id_result_type = ty_id,
691 .id_result = entry.value_ptr.*,745 .id_result = gop.value_ptr.*,
692 .value = value,746 .value = value,
693 });747 });
694 }748 }
695 return entry.value_ptr.*;749 return gop.value_ptr.*;
696}750}
697751
698pub fn constBool(module: *Module, value: bool) !Id {752pub fn constBool(module: *Module, value: bool) !Id {
...@@ -716,23 +770,26 @@ pub fn constBool(module: *Module, value: bool) !Id {...@@ -716,23 +770,26 @@ pub fn constBool(module: *Module, value: bool) !Id {
716 return result_id;770 return result_id;
717}771}
718772
719/// Return a pointer to a builtin variable. `result_ty_id` must be a **pointer**773pub fn builtin(
720/// with storage class `.Input`.774 module: *Module,
721pub fn builtin(module: *Module, result_ty_id: Id, spirv_builtin: spec.BuiltIn) !Decl.Index {775 result_ty_id: Id,
722 const entry = try module.cache.builtins.getOrPut(module.gpa, .{ result_ty_id, spirv_builtin });776 spirv_builtin: spec.BuiltIn,
723 if (!entry.found_existing) {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) {
724 const decl_index = try module.allocDecl(.global);781 const decl_index = try module.allocDecl(.global);
725 const result_id = module.declPtr(decl_index).result_id;782 const result_id = module.declPtr(decl_index).result_id;
726 entry.value_ptr.* = decl_index;783 gop.value_ptr.* = decl_index;
727 try module.sections.globals.emit(module.gpa, .OpVariable, .{784 try module.sections.globals.emit(module.gpa, .OpVariable, .{
728 .id_result_type = result_ty_id,785 .id_result_type = result_ty_id,
729 .id_result = result_id,786 .id_result = result_id,
730 .storage_class = .input,787 .storage_class = storage_class,
731 });788 });
732 try module.decorate(result_id, .{ .built_in = .{ .built_in = spirv_builtin } });789 try module.decorate(result_id, .{ .built_in = .{ .built_in = spirv_builtin } });
733 try module.declareDeclDeps(decl_index, &.{});790 try module.declareDeclDeps(decl_index, &.{});
734 }791 }
735 return entry.value_ptr.*;792 return gop.value_ptr.*;
736}793}
737794
738pub fn constUndef(module: *Module, ty_id: Id) !Id {795pub fn constUndef(module: *Module, ty_id: Id) !Id {
...@@ -759,8 +816,8 @@ pub fn decorate(...@@ -759,8 +816,8 @@ pub fn decorate(
759 target: Id,816 target: Id,
760 decoration: spec.Decoration.Extended,817 decoration: spec.Decoration.Extended,
761) !void {818) !void {
762 const entry = try module.cache.decorations.getOrPut(module.gpa, .{ target, decoration });819 const gop = try module.cache.decorations.getOrPut(module.gpa, .{ target, decoration });
763 if (!entry.found_existing) {820 if (!gop.found_existing) {
764 try module.sections.annotations.emit(module.gpa, .OpDecorate, .{821 try module.sections.annotations.emit(module.gpa, .OpDecorate, .{
765 .target = target,822 .target = target,
766 .decoration = decoration,823 .decoration = decoration,