| ... | ... | @@ -40,7 +40,6 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | pub const zig_call_abi_ver = 3; |
| 43 | | pub const big_int_bits = 32; |
| 44 | 43 | |
| 45 | 44 | const ControlFlow = union(enum) { |
| 46 | 45 | const Structured = struct { |
| ... | ... | @@ -183,6 +182,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 183 | 182 | const gpa = cg.module.gpa; |
| 184 | 183 | const zcu = cg.module.zcu; |
| 185 | 184 | const ip = &zcu.intern_pool; |
| 185 | const target = zcu.getTarget(); |
| 186 | 186 | |
| 187 | 187 | const nav = ip.getNav(cg.owner_nav); |
| 188 | 188 | const val = zcu.navValue(cg.owner_nav); |
| ... | ... | @@ -251,19 +251,19 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 251 | 251 | // Append the actual code into the functions section. |
| 252 | 252 | try cg.module.sections.functions.append(cg.module.gpa, cg.prologue); |
| 253 | 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)); |
| 257 | 254 | |
| 258 | 255 | // Temporarily generate a test kernel declaration if this is a test function. |
| 259 | 256 | if (is_test) { |
| 260 | 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 | 263 | .global => { |
| 264 | 264 | const maybe_init_val: ?Value = switch (ip.indexToKey(val.toIntern())) { |
| 265 | 265 | .func => unreachable, |
| 266 | | .variable => |variable| Value.fromInterned(variable.init), |
| 266 | .variable => |variable| .fromInterned(variable.init), |
| 267 | 267 | .@"extern" => null, |
| 268 | 268 | else => val, |
| 269 | 269 | }; |
| ... | ... | @@ -272,7 +272,8 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 272 | 272 | const storage_class = cg.module.storageClass(nav.getAddrspace()); |
| 273 | 273 | assert(storage_class != .generic); // These should be instance globals |
| 274 | 274 | |
| 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); |
| 276 | 277 | |
| 277 | 278 | try cg.module.sections.globals.emit(cg.module.gpa, .OpVariable, .{ |
| 278 | 279 | .id_result_type = ptr_ty_id, |
| ... | ... | @@ -280,6 +281,27 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 280 | 281 | .storage_class = storage_class, |
| 281 | 282 | }); |
| 282 | 283 | |
| 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 | 305 | if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |builtin| { |
| 284 | 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 | 312 | .invocation_global => { |
| 291 | 313 | const maybe_init_val: ?Value = switch (ip.indexToKey(val.toIntern())) { |
| 292 | 314 | .func => unreachable, |
| 293 | | .variable => |variable| Value.fromInterned(variable.init), |
| 315 | .variable => |variable| .fromInterned(variable.init), |
| 294 | 316 | .@"extern" => null, |
| 295 | 317 | else => val, |
| 296 | 318 | }; |
| 297 | 319 | |
| 298 | 320 | try cg.module.declareDeclDeps(spv_decl_index, &.{}); |
| 299 | 321 | |
| 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); |
| 301 | 324 | |
| 302 | 325 | if (maybe_init_val) |init_val| { |
| 303 | 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, &.{}); |
| 305 | 329 | |
| 306 | 330 | const initializer_id = cg.module.allocId(); |
| 307 | 331 | try cg.prologue.emit(cg.module.gpa, .OpFunction, .{ |
| ... | ... | @@ -406,7 +430,8 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { |
| 406 | 430 | |
| 407 | 431 | const zcu = cg.module.zcu; |
| 408 | 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)); |
| 410 | 435 | |
| 411 | 436 | const spv_decl_index = blk: { |
| 412 | 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 | 479 | cg.decl_deps.deinit(gpa); |
| 455 | 480 | } |
| 456 | 481 | |
| 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, &.{}); |
| 458 | 484 | |
| 459 | 485 | const initializer_id = cg.module.allocId(); |
| 460 | 486 | try cg.prologue.emit(cg.module.gpa, .OpFunction, .{ |
| ... | ... | @@ -469,7 +495,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { |
| 469 | 495 | }); |
| 470 | 496 | cg.block_label = root_block_id; |
| 471 | 497 | |
| 472 | | const val_id = try cg.constant(ty, Value.fromInterned(val), .indirect); |
| 498 | const val_id = try cg.constant(ty, .fromInterned(val), .indirect); |
| 473 | 499 | try cg.body.emit(cg.module.gpa, .OpStore, .{ |
| 474 | 500 | .pointer = result_id, |
| 475 | 501 | .object = val_id, |
| ... | ... | @@ -484,7 +510,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { |
| 484 | 510 | |
| 485 | 511 | try cg.module.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)}); |
| 486 | 512 | |
| 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 | 514 | try cg.module.sections.globals.emit(cg.module.gpa, .OpExtInst, .{ |
| 489 | 515 | .id_result_type = fn_decl_ptr_ty_id, |
| 490 | 516 | .id_result = result_id, |
| ... | ... | @@ -533,44 +559,6 @@ fn beginSpvBlock(cg: *CodeGen, label: Id) !void { |
| 533 | 559 | cg.block_label = label; |
| 534 | 560 | } |
| 535 | 561 | |
| 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? |
| 544 | | fn 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 | 562 | /// Return the amount of bits in the largest supported integer type. This is either 32 (always supported), or 64 (if |
| 575 | 563 | /// the Int64 capability is enabled). |
| 576 | 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 | 620 | return switch (scalar_ty.zigTypeTag(zcu)) { |
| 633 | 621 | .bool => .{ |
| 634 | 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 | 624 | .vector_len = vector_len, |
| 637 | 625 | .signedness = .unsigned, // Technically, but doesn't matter for this class. |
| 638 | 626 | .class = .bool, |
| ... | ... | @@ -647,7 +635,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo { |
| 647 | 635 | .int => blk: { |
| 648 | 636 | const int_info = scalar_ty.intInfo(zcu); |
| 649 | 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 | 639 | break :blk .{ |
| 652 | 640 | .bits = int_info.bits, |
| 653 | 641 | .backing_bits = backing_bits, |
| ... | ... | @@ -711,7 +699,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { |
| 711 | 699 | const scalar_ty = ty.scalarType(zcu); |
| 712 | 700 | const int_info = scalar_ty.intInfo(zcu); |
| 713 | 701 | // 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 | 703 | assert(backing_bits != 0); // u0 is comptime |
| 716 | 704 | |
| 717 | 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 | 910 | }, |
| 923 | 911 | .ptr => return cg.constantPtr(val), |
| 924 | 912 | .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); |
| 927 | 915 | const comp_ty_id = try cg.resolveType(ty, .direct); |
| 928 | 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 | 965 | }, |
| 978 | 966 | .elems => |elems| { |
| 979 | 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 | 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 | } |
| 987 | 975 | |
| ... | ... | @@ -995,7 +983,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { |
| 995 | 983 | // TODO: composite int |
| 996 | 984 | // TODO: endianness |
| 997 | 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 | 987 | var limbs: [8]u8 = undefined; |
| 1000 | 988 | @memset(&limbs, 0); |
| 1001 | 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 | 1023 | if (un.tag == .none) { |
| 1036 | 1024 | assert(ty.containerLayout(zcu) == .@"packed"); // TODO |
| 1037 | 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 | 1029 | const union_obj = zcu.typeToUnion(ty).?; |
| 1042 | 1030 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[active_field]); |
| 1043 | 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 | 1033 | else |
| 1046 | 1034 | null; |
| 1047 | 1035 | return try cg.unionInit(ty, active_field, payload); |
| ... | ... | @@ -1084,10 +1072,11 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { |
| 1084 | 1072 | // that is not implemented by Mesa yet. Therefore, just generate it |
| 1085 | 1073 | // as a runtime operation. |
| 1086 | 1074 | const result_ptr_id = cg.module.allocId(); |
| 1075 | const value_id = try cg.constInt(.usize, int.addr); |
| 1087 | 1076 | try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{ |
| 1088 | 1077 | .id_result_type = result_ty_id, |
| 1089 | 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 | 1081 | return result_ptr_id; |
| 1093 | 1082 | }, |
| ... | ... | @@ -1174,7 +1163,8 @@ fn constantUavRef( |
| 1174 | 1163 | |
| 1175 | 1164 | // Uav refs are always generic. |
| 1176 | 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 | 1168 | const ptr_id = try cg.resolveUav(uav.val); |
| 1179 | 1169 | |
| 1180 | 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 | 1218 | const storage_class = cg.module.storageClass(nav.getAddrspace()); |
| 1229 | 1219 | try cg.addFunctionDep(spv_decl_index, storage_class); |
| 1230 | 1220 | |
| 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); |
| 1232 | 1223 | |
| 1233 | 1224 | const ptr_id = switch (storage_class) { |
| 1234 | 1225 | .generic => try cg.castToGeneric(decl_ptr_ty_id, decl_id), |
| ... | ... | @@ -1260,104 +1251,6 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 { |
| 1260 | 1251 | return try aw.toOwnedSlice(); |
| 1261 | 1252 | } |
| 1262 | 1253 | |
| 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. |
| 1267 | | fn 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 | | |
| 1286 | | fn 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 | | |
| 1291 | | fn 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 | | |
| 1348 | | fn 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 | 1254 | /// Generate a union type. Union types are always generated with the |
| 1362 | 1255 | /// most aligned field active. If the tag alignment is greater |
| 1363 | 1256 | /// 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 | 1276 | const union_obj = zcu.typeToUnion(ty).?; |
| 1384 | 1277 | |
| 1385 | 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 | } |
| 1388 | 1281 | |
| 1389 | 1282 | const layout = cg.unionLayout(ty); |
| ... | ... | @@ -1410,13 +1303,15 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id { |
| 1410 | 1303 | } |
| 1411 | 1304 | |
| 1412 | 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 | 1308 | member_types[layout.payload_padding_index] = payload_padding_ty_id; |
| 1415 | 1309 | member_names[layout.payload_padding_index] = "(payload padding)"; |
| 1416 | 1310 | } |
| 1417 | 1311 | |
| 1418 | 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 | 1315 | member_types[layout.padding_index] = padding_ty_id; |
| 1421 | 1316 | member_names[layout.padding_index] = "(padding)"; |
| 1422 | 1317 | } |
| ... | ... | @@ -1479,7 +1374,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1479 | 1374 | assert(repr == .indirect); |
| 1480 | 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 | 1379 | .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr), |
| 1485 | 1380 | .float => { |
| ... | ... | @@ -1519,9 +1414,11 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1519 | 1414 | // In this case, we have an array of a non-zero sized type. In this case, |
| 1520 | 1415 | // generate an array of 1 element instead, so that ptr_elem_ptr instructions |
| 1521 | 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 | 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 | 1422 | switch (target.os.tag) { |
| 1526 | 1423 | .vulkan, .opengl => { |
| 1527 | 1424 | try cg.module.decorate(result_id, .{ |
| ... | ... | @@ -1540,7 +1437,8 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1540 | 1437 | const elem_ty_id = try cg.resolveType(elem_ty, repr); |
| 1541 | 1438 | const len = ty.vectorLen(zcu); |
| 1542 | 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 | 1443 | .@"fn" => switch (repr) { |
| 1546 | 1444 | .direct => { |
| ... | ... | @@ -1582,8 +1480,9 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1582 | 1480 | const ptr_info = ty.ptrInfo(zcu); |
| 1583 | 1481 | |
| 1584 | 1482 | const child_ty: Type = .fromInterned(ptr_info.child); |
| 1483 | const child_ty_id = try cg.resolveType(child_ty, .indirect); |
| 1585 | 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); |
| 1587 | 1486 | |
| 1588 | 1487 | if (ptr_info.flags.size != .slice) { |
| 1589 | 1488 | return ptr_ty_id; |
| ... | ... | @@ -2142,7 +2041,7 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary { |
| 2142 | 2041 | |
| 2143 | 2042 | for (0..ops) |i| { |
| 2144 | 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 | 2045 | cg.body.writeOperand(Id, results.at(i)); |
| 2147 | 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 | 2176 | |
| 2278 | 2177 | for (0..ops) |i| { |
| 2279 | 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 | 2180 | cg.body.writeOperand(Id, results.at(i)); |
| 2282 | 2181 | cg.body.writeOperand(Id, op_lhs.at(i)); |
| 2283 | 2182 | cg.body.writeOperand(Id, op_rhs.at(i)); |
| ... | ... | @@ -2331,7 +2230,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary { |
| 2331 | 2230 | }) |opcode| { |
| 2332 | 2231 | for (0..ops) |i| { |
| 2333 | 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 | 2234 | cg.body.writeOperand(Id, results.at(i)); |
| 2336 | 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 | 2371 | }) |opcode| { |
| 2473 | 2372 | for (0..ops) |i| { |
| 2474 | 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 | 2375 | cg.body.writeOperand(Id, results.at(i)); |
| 2477 | 2376 | cg.body.writeOperand(Id, op_lhs.at(i)); |
| 2478 | 2377 | cg.body.writeOperand(Id, op_rhs.at(i)); |
| ... | ... | @@ -2591,7 +2490,7 @@ fn buildWideMul( |
| 2591 | 2490 | const op_result = cg.module.allocId(); |
| 2592 | 2491 | |
| 2593 | 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 | 2494 | cg.body.writeOperand(Id, op_result); |
| 2596 | 2495 | cg.body.writeOperand(Id, lhs_op.at(i)); |
| 2597 | 2496 | cg.body.writeOperand(Id, rhs_op.at(i)); |
| ... | ... | @@ -2664,30 +2563,27 @@ fn generateTestEntryPoint( |
| 2664 | 2563 | |
| 2665 | 2564 | const kernel_id = cg.module.declPtr(spv_decl_index).result_id; |
| 2666 | 2565 | |
| 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 | 2566 | const section = &cg.module.sections.functions; |
| 2672 | 2567 | |
| 2673 | 2568 | const p_error_id = cg.module.allocId(); |
| 2674 | 2569 | switch (target.os.tag) { |
| 2675 | 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}); |
| 2677 | 2573 | |
| 2678 | | try section.emit(cg.module.gpa, .OpFunction, .{ |
| 2574 | try section.emit(gpa, .OpFunction, .{ |
| 2679 | 2575 | .id_result_type = try cg.resolveType(.void, .direct), |
| 2680 | 2576 | .id_result = kernel_id, |
| 2681 | 2577 | .function_control = .{}, |
| 2682 | 2578 | .function_type = kernel_proto_ty_id, |
| 2683 | 2579 | }); |
| 2684 | 2580 | |
| 2685 | | try section.emit(cg.module.gpa, .OpFunctionParameter, .{ |
| 2581 | try section.emit(gpa, .OpFunctionParameter, .{ |
| 2686 | 2582 | .id_result_type = ptr_anyerror_ty_id, |
| 2687 | 2583 | .id_result = p_error_id, |
| 2688 | 2584 | }); |
| 2689 | 2585 | |
| 2690 | | try section.emit(cg.module.gpa, .OpLabel, .{ |
| 2586 | try section.emit(gpa, .OpLabel, .{ |
| 2691 | 2587 | .id_result = cg.module.allocId(), |
| 2692 | 2588 | }); |
| 2693 | 2589 | }, |
| ... | ... | @@ -2706,14 +2602,14 @@ fn generateTestEntryPoint( |
| 2706 | 2602 | try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } }); |
| 2707 | 2603 | |
| 2708 | 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 | 2606 | .id_result = ptr_buffer_struct_ty_id, |
| 2711 | 2607 | .storage_class = cg.module.storageClass(.global), |
| 2712 | 2608 | .type = buffer_struct_ty_id, |
| 2713 | 2609 | }); |
| 2714 | 2610 | |
| 2715 | 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 | 2613 | .id_result_type = ptr_buffer_struct_ty_id, |
| 2718 | 2614 | .id_result = buffer_struct_id, |
| 2719 | 2615 | .storage_class = cg.module.storageClass(.global), |
| ... | ... | @@ -2724,7 +2620,7 @@ fn generateTestEntryPoint( |
| 2724 | 2620 | cg.module.error_buffer = spv_err_decl_index; |
| 2725 | 2621 | } |
| 2726 | 2622 | |
| 2727 | | try cg.module.sections.execution_modes.emit(cg.module.gpa, .OpExecutionMode, .{ |
| 2623 | try cg.module.sections.execution_modes.emit(gpa, .OpExecutionMode, .{ |
| 2728 | 2624 | .entry_point = kernel_id, |
| 2729 | 2625 | .mode = .{ .local_size = .{ |
| 2730 | 2626 | .x_size = 1, |
| ... | ... | @@ -2733,23 +2629,24 @@ fn generateTestEntryPoint( |
| 2733 | 2629 | } }, |
| 2734 | 2630 | }); |
| 2735 | 2631 | |
| 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, .{ |
| 2738 | 2635 | .id_result_type = try cg.resolveType(.void, .direct), |
| 2739 | 2636 | .id_result = kernel_id, |
| 2740 | 2637 | .function_control = .{}, |
| 2741 | 2638 | .function_type = kernel_proto_ty_id, |
| 2742 | 2639 | }); |
| 2743 | | try section.emit(cg.module.gpa, .OpLabel, .{ |
| 2640 | try section.emit(gpa, .OpLabel, .{ |
| 2744 | 2641 | .id_result = cg.module.allocId(), |
| 2745 | 2642 | }); |
| 2746 | 2643 | |
| 2747 | 2644 | const spv_err_decl_index = cg.module.error_buffer.?; |
| 2748 | 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, {}); |
| 2750 | 2647 | |
| 2751 | 2648 | const zero_id = try cg.constInt(.u32, 0); |
| 2752 | | try section.emit(cg.module.gpa, .OpInBoundsAccessChain, .{ |
| 2649 | try section.emit(gpa, .OpInBoundsAccessChain, .{ |
| 2753 | 2650 | .id_result_type = ptr_anyerror_ty_id, |
| 2754 | 2651 | .id_result = p_error_id, |
| 2755 | 2652 | .base = buffer_id, |
| ... | ... | @@ -2760,25 +2657,25 @@ fn generateTestEntryPoint( |
| 2760 | 2657 | } |
| 2761 | 2658 | |
| 2762 | 2659 | const error_id = cg.module.allocId(); |
| 2763 | | try section.emit(cg.module.gpa, .OpFunctionCall, .{ |
| 2660 | try section.emit(gpa, .OpFunctionCall, .{ |
| 2764 | 2661 | .id_result_type = anyerror_ty_id, |
| 2765 | 2662 | .id_result = error_id, |
| 2766 | 2663 | .function = test_id, |
| 2767 | 2664 | }); |
| 2768 | 2665 | // Note: Convert to direct not required. |
| 2769 | | try section.emit(cg.module.gpa, .OpStore, .{ |
| 2666 | try section.emit(gpa, .OpStore, .{ |
| 2770 | 2667 | .pointer = p_error_id, |
| 2771 | 2668 | .object = error_id, |
| 2772 | 2669 | .memory_access = .{ |
| 2773 | 2670 | .aligned = .{ .literal_integer = @intCast(Type.abiAlignment(.anyerror, zcu).toByteUnits().?) }, |
| 2774 | 2671 | }, |
| 2775 | 2672 | }); |
| 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, {}); |
| 2778 | 2675 | |
| 2779 | 2676 | // Just generate a quick other name because the intel runtime crashes when the entry- |
| 2780 | 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}); |
| 2782 | 2679 | |
| 2783 | 2680 | const execution_mode: spec.ExecutionModel = switch (target.os.tag) { |
| 2784 | 2681 | .vulkan, .opengl => .gl_compute, |
| ... | ... | @@ -2786,7 +2683,6 @@ fn generateTestEntryPoint( |
| 2786 | 2683 | else => unreachable, |
| 2787 | 2684 | }; |
| 2788 | 2685 | |
| 2789 | | try cg.module.declareDeclDeps(spv_decl_index, decl_deps.items); |
| 2790 | 2686 | try cg.module.declareEntryPoint(spv_decl_index, test_name, execution_mode, null); |
| 2791 | 2687 | } |
| 2792 | 2688 | |
| ... | ... | @@ -3760,10 +3656,10 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3760 | 3656 | result_id = cg.module.allocId(); |
| 3761 | 3657 | |
| 3762 | 3658 | 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); |
| 3767 | 3663 | } |
| 3768 | 3664 | |
| 3769 | 3665 | return result_id; |
| ... | ... | @@ -4189,7 +4085,7 @@ fn bitCast( |
| 4189 | 4085 | break :blk result_id; |
| 4190 | 4086 | } |
| 4191 | 4087 | |
| 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); |
| 4193 | 4089 | |
| 4194 | 4090 | const tmp_id = try cg.alloc(src_ty, .{ .storage_class = .function }); |
| 4195 | 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 | 4490 | const zcu = cg.module.zcu; |
| 4595 | 4491 | // Construct new pointer type for the resulting pointer |
| 4596 | 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 | 4495 | if (ptr_ty.isSinglePointer(zcu)) { |
| 4599 | 4496 | // Pointer-to-array. In this case, the resulting pointer is not of the same type |
| 4600 | 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 | 4534 | const is_vector = array_ty.isVector(zcu); |
| 4638 | 4535 | |
| 4639 | 4536 | 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); |
| 4642 | 4541 | |
| 4643 | 4542 | const tmp_id = cg.module.allocId(); |
| 4644 | 4543 | try cg.prologue.emit(cg.module.gpa, .OpVariable, .{ |
| ... | ... | @@ -4692,8 +4591,9 @@ fn airVectorStoreElem(cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 4692 | 4591 | const vector_ty = vector_ptr_ty.childType(zcu); |
| 4693 | 4592 | const scalar_ty = vector_ty.scalarType(zcu); |
| 4694 | 4593 | |
| 4594 | const scalar_ty_id = try cg.resolveType(scalar_ty, .indirect); |
| 4695 | 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); |
| 4697 | 4597 | |
| 4698 | 4598 | const vector_ptr = try cg.resolve(data.vector_ptr); |
| 4699 | 4599 | const index = try cg.resolve(extra.lhs); |
| ... | ... | @@ -4715,7 +4615,8 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 4715 | 4615 | if (layout.tag_size == 0) return; |
| 4716 | 4616 | |
| 4717 | 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))); |
| 4719 | 4620 | |
| 4720 | 4621 | const union_ptr_id = try cg.resolve(bin_op.lhs); |
| 4721 | 4622 | const new_tag_id = try cg.resolve(bin_op.rhs); |
| ... | ... | @@ -4802,17 +4703,20 @@ fn unionInit( |
| 4802 | 4703 | const tmp_id = try cg.alloc(ty, .{ .storage_class = .function }); |
| 4803 | 4704 | |
| 4804 | 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 | 4708 | const ptr_id = try cg.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))}); |
| 4807 | 4709 | const tag_id = try cg.constInt(tag_ty, tag_int); |
| 4808 | 4710 | try cg.store(tag_ty, ptr_id, tag_id, .{}); |
| 4809 | 4711 | } |
| 4810 | 4712 | |
| 4811 | 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 | 4716 | const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index}); |
| 4814 | 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 | 4720 | const active_pl_ptr_id = cg.module.allocId(); |
| 4817 | 4721 | try cg.body.emit(cg.module.gpa, .OpBitcast, .{ |
| 4818 | 4722 | .id_result_type = active_pl_ptr_ty_id, |
| ... | ... | @@ -4876,7 +4780,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4876 | 4780 | const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1); |
| 4877 | 4781 | const masked = try cg.buildBinary(.bit_and, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } }); |
| 4878 | 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 | 4784 | break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg)); |
| 4881 | 4785 | const trunc = try cg.buildConvert(field_int_ty, masked); |
| 4882 | 4786 | break :blk try trunc.materialize(cg); |
| ... | ... | @@ -4900,7 +4804,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4900 | 4804 | .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } }, |
| 4901 | 4805 | ); |
| 4902 | 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 | 4808 | break :blk try cg.bitCast(int_ty, backing_int_ty, try masked.materialize(cg)); |
| 4905 | 4809 | const trunc = try cg.buildConvert(int_ty, masked); |
| 4906 | 4810 | break :blk try trunc.materialize(cg); |
| ... | ... | @@ -4917,10 +4821,12 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4917 | 4821 | const tmp_id = try cg.alloc(object_ty, .{ .storage_class = .function }); |
| 4918 | 4822 | try cg.store(object_ty, tmp_id, object_id, .{}); |
| 4919 | 4823 | |
| 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 | 4826 | const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index}); |
| 4922 | 4827 | |
| 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 | 4830 | const active_pl_ptr_id = cg.module.allocId(); |
| 4925 | 4831 | try cg.body.emit(cg.module.gpa, .OpBitcast, .{ |
| 4926 | 4832 | .id_result_type = active_pl_ptr_ty_id, |
| ... | ... | @@ -4997,7 +4903,8 @@ fn structFieldPtr( |
| 4997 | 4903 | } |
| 4998 | 4904 | |
| 4999 | 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 | 4908 | const pl_ptr_id = blk: { |
| 5002 | 4909 | if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr; |
| 5003 | 4910 | break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index}); |
| ... | ... | @@ -5041,7 +4948,8 @@ fn alloc( |
| 5041 | 4948 | options: AllocOptions, |
| 5042 | 4949 | ) !Id { |
| 5043 | 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); |
| 5045 | 4953 | |
| 5046 | 4954 | // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to |
| 5047 | 4955 | // directly generate them into func.prologue instead of the body. |
| ... | ... | @@ -5060,7 +4968,7 @@ fn alloc( |
| 5060 | 4968 | |
| 5061 | 4969 | switch (options.storage_class) { |
| 5062 | 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 | 4972 | // Convert to a generic pointer |
| 5065 | 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 | 5001 | const result_id = cg.module.allocId(); |
| 5094 | 5002 | const block_id_ty_id = try cg.resolveType(.u32, .direct); |
| 5095 | 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); |
| 5097 | | cg.body.writeOperand(spec.Id, result_id); |
| 5004 | cg.body.writeOperand(Id, block_id_ty_id); |
| 5005 | cg.body.writeOperand(Id, result_id); |
| 5098 | 5006 | |
| 5099 | 5007 | for (incoming) |incoming_block| { |
| 5100 | 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 | 5193 | // result type + result + variable/parent... |
| 5286 | 5194 | 2 + @as(u16, @intCast(block.incoming_blocks.items.len * 2)), |
| 5287 | 5195 | ); |
| 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); |
| 5290 | 5198 | |
| 5291 | 5199 | for (block.incoming_blocks.items) |incoming| { |
| 5292 | 5200 | cg.body.writeOperand( |
| ... | ... | @@ -5793,7 +5701,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { |
| 5793 | 5701 | if (is_pointer) { |
| 5794 | 5702 | if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 5795 | 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 | 5706 | const tag_ptr_id = try cg.accessChain(bool_ptr_ty_id, operand_id, &.{1}); |
| 5798 | 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 | 5848 | .bool, .error_set => 1, |
| 5940 | 5849 | .int => blk: { |
| 5941 | 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 | 5852 | if (big_int) return cg.todo("implement composite int switch", .{}); |
| 5944 | 5853 | break :blk if (backing_bits <= 32) 1 else 2; |
| 5945 | 5854 | }, |
| 5946 | 5855 | .@"enum" => blk: { |
| 5947 | 5856 | const int_ty = cond_ty.intTagType(zcu); |
| 5948 | 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 | 5859 | if (big_int) return cg.todo("implement composite int switch", .{}); |
| 5951 | 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 | 6207 | const callee_id = try cg.resolve(pl_op.operand); |
| 6299 | 6208 | |
| 6300 | 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 | 6211 | defer gpa.free(params); |
| 6303 | 6212 | var n_params: usize = 0; |
| 6304 | 6213 | for (args) |arg| { |
| ... | ... | @@ -6327,50 +6236,49 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie |
| 6327 | 6236 | return result_id; |
| 6328 | 6237 | } |
| 6329 | 6238 | |
| 6330 | | fn 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); |
| 6239 | fn 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); |
| 6340 | 6251 | 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); |
| 6344 | 6260 | } |
| 6345 | 6261 | |
| 6346 | 6262 | fn airWorkItemId(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6347 | 6263 | if (cg.liveness.isUnused(inst)) return null; |
| 6348 | 6264 | const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 6349 | 6265 | 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); |
| 6354 | 6267 | } |
| 6355 | 6268 | |
| 6269 | // TODO: this must be an OpConstant/OpSpec but even then the driver crashes. |
| 6356 | 6270 | fn airWorkGroupSize(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6357 | 6271 | if (cg.liveness.isUnused(inst)) return null; |
| 6358 | 6272 | const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 6359 | 6273 | 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); |
| 6364 | 6275 | } |
| 6365 | 6276 | |
| 6366 | 6277 | fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6367 | 6278 | if (cg.liveness.isUnused(inst)) return null; |
| 6368 | 6279 | const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 6369 | 6280 | 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); |
| 6374 | 6282 | } |
| 6375 | 6283 | |
| 6376 | 6284 | fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type { |