| ... | ... | @@ -37,6 +37,10 @@ prologue: Section = .{}, |
| 37 | 37 | body: Section = .{}, |
| 38 | 38 | args: std.ArrayList(Id) = .empty, |
| 39 | 39 | next_arg_index: u32 = 0, |
| 40 | /// Caches the limb extractions for composite integer values so repeated |
| 41 | /// arithmetic on the same operand doesn't re-emit `OpCompositeExtract` per |
| 42 | /// limb per use. Slices are owned by `cg.arena`. |
| 43 | composite_limbs: std.AutoHashMapUnmanaged(Id, []const Id) = .empty, |
| 40 | 44 | block_stack: std.ArrayList(*Block) = .empty, |
| 41 | 45 | block_label: Id = .none, |
| 42 | 46 | /// Whether the current block has been terminated by a terminator |
| ... | ... | @@ -49,7 +53,21 @@ tracked_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty, |
| 49 | 53 | loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, LoopSwitch) = .empty, |
| 50 | 54 | id_scratch: std.ArrayList(Id) = .empty, |
| 51 | 55 | |
| 52 | | const big_int_bits = @bitSizeOf(u32); |
| 56 | fn hasInt64(target: *const std.Target) bool { |
| 57 | return target.cpu.arch == .spirv64 or target.cpu.has(.spirv, .int64); |
| 58 | } |
| 59 | |
| 60 | fn bigIntBits(cg: *const CodeGen) u16 { |
| 61 | return if (hasInt64(cg.zcu.getTarget())) 64 else 32; |
| 62 | } |
| 63 | |
| 64 | fn limbType(cg: *const CodeGen) Type { |
| 65 | return if (cg.bigIntBits() == 64) .u64 else .u32; |
| 66 | } |
| 67 | |
| 68 | fn limbTypeId(cg: *CodeGen) !Id { |
| 69 | return cg.resolveType(cg.limbType(), .direct); |
| 70 | } |
| 53 | 71 | |
| 54 | 72 | /// Data can be lowered into in two basic representations: indirect, which is when |
| 55 | 73 | /// a type is stored in memory, and direct, which is how a type is stored when its |
| ... | ... | @@ -163,6 +181,7 @@ pub fn deinit(cg: *CodeGen) void { |
| 163 | 181 | cg.block_stack.deinit(gpa); |
| 164 | 182 | cg.block_results.deinit(gpa); |
| 165 | 183 | cg.args.deinit(gpa); |
| 184 | cg.composite_limbs.deinit(gpa); |
| 166 | 185 | cg.tracked_allocas.deinit(gpa); |
| 167 | 186 | cg.inst_results.deinit(gpa); |
| 168 | 187 | cg.loop_switches.deinit(gpa); |
| ... | ... | @@ -407,7 +426,7 @@ pub fn addEntryPointDeps( |
| 407 | 426 | cg: *CodeGen, |
| 408 | 427 | decl_index: Decl.Index, |
| 409 | 428 | seen: *std.bit_set.Dynamic, |
| 410 | | interface: *std.array_list.Managed(Id), |
| 429 | interface: *std.ArrayList(Id), |
| 411 | 430 | ) !void { |
| 412 | 431 | const decl = cg.declPtr(decl_index); |
| 413 | 432 | const deps = cg.decl_deps.items[decl.begin_dep..decl.end_dep]; |
| ... | ... | @@ -419,7 +438,7 @@ pub fn addEntryPointDeps( |
| 419 | 438 | seen.set(@intFromEnum(decl_index)); |
| 420 | 439 | |
| 421 | 440 | if (decl.kind == .global) { |
| 422 | | try interface.append(decl.result_id); |
| 441 | try interface.append(cg.gpa, decl.result_id); |
| 423 | 442 | } |
| 424 | 443 | |
| 425 | 444 | for (deps) |dep| { |
| ... | ... | @@ -471,14 +490,14 @@ pub fn backingIntBits(cg: *const CodeGen, bits: u16) struct { u16, bool } { |
| 471 | 490 | .{ .bits = 8, .enabled = target.cpu.has(.spirv, .int8) }, |
| 472 | 491 | .{ .bits = 16, .enabled = target.cpu.has(.spirv, .int16) }, |
| 473 | 492 | .{ .bits = 32, .enabled = true }, |
| 474 | | .{ .bits = 64, .enabled = target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64 }, |
| 493 | .{ .bits = 64, .enabled = hasInt64(target) }, |
| 475 | 494 | }; |
| 476 | 495 | |
| 477 | 496 | for (ints) |int| { |
| 478 | 497 | if (bits <= int.bits and int.enabled) return .{ int.bits, false }; |
| 479 | 498 | } |
| 480 | 499 | |
| 481 | | return .{ std.mem.alignForward(u16, bits, big_int_bits), true }; |
| 500 | return .{ std.mem.alignForward(u16, bits, cg.bigIntBits()), true }; |
| 482 | 501 | } |
| 483 | 502 | |
| 484 | 503 | pub fn intType(cg: *CodeGen, signedness: std.lang.Signedness, bits: u16) !Id { |
| ... | ... | @@ -492,14 +511,16 @@ pub fn intType(cg: *CodeGen, signedness: std.lang.Signedness, bits: u16) !Id { |
| 492 | 511 | }; |
| 493 | 512 | const backing_bits, const big_int = cg.backingIntBits(bits); |
| 494 | 513 | if (big_int) { |
| 495 | | const u32_ty = try cg.intType(.unsigned, 32); |
| 514 | const limb_bits = cg.bigIntBits(); |
| 515 | const limb_ty = try cg.intType(.unsigned, limb_bits); |
| 516 | const len_ty = try cg.intType(.unsigned, 32); |
| 496 | 517 | const len_id = cg.allocId(); |
| 497 | 518 | try cg.sections.globals.emit(cg.gpa, .OpConstant, .{ |
| 498 | | .id_result_type = u32_ty, |
| 519 | .id_result_type = len_ty, |
| 499 | 520 | .id_result = len_id, |
| 500 | | .value = .{ .uint32 = backing_bits / big_int_bits }, |
| 521 | .value = .{ .uint32 = backing_bits / limb_bits }, |
| 501 | 522 | }); |
| 502 | | return cg.arrayType(len_id, u32_ty); |
| 523 | return cg.arrayType(len_id, limb_ty); |
| 503 | 524 | } |
| 504 | 525 | |
| 505 | 526 | const result_id = cg.allocId(); |
| ... | ... | @@ -1443,7 +1464,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { |
| 1443 | 1464 | .signed => @bitCast(@as(i64, @intCast(value))), |
| 1444 | 1465 | .unsigned => @as(u64, @intCast(value)), |
| 1445 | 1466 | }; |
| 1446 | | const n_limbs = backing_bits / big_int_bits; |
| 1467 | const n_limbs = backing_bits / cg.bigIntBits(); |
| 1447 | 1468 | const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0; |
| 1448 | 1469 | const scratch_top = cg.id_scratch.items.len; |
| 1449 | 1470 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| ... | ... | @@ -1616,21 +1637,33 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { |
| 1616 | 1637 | const int_info = ty.intInfo(zcu); |
| 1617 | 1638 | const backing_bits, const is_big_int = cg.backingIntBits(int_info.bits); |
| 1618 | 1639 | if (is_big_int) { |
| 1619 | | const n_limbs = backing_bits / big_int_bits; |
| 1640 | const limb_bits = cg.bigIntBits(); |
| 1641 | const n_limbs = backing_bits / limb_bits; |
| 1620 | 1642 | const big_result_ty_id = try cg.resolveType(ty, .indirect); |
| 1621 | 1643 | var bigint_space: Value.BigIntSpace = undefined; |
| 1622 | 1644 | const bigint = val.toBigInt(&bigint_space, zcu); |
| 1623 | | const limb_values = try gpa.alloc(u32, n_limbs); |
| 1624 | | defer gpa.free(limb_values); |
| 1625 | | bigint.writeTwosComplement(std.mem.sliceAsBytes(limb_values), .little); |
| 1626 | | if (builtin.cpu.arch.endian() == .big) { |
| 1627 | | for (limb_values) |*limb| limb.* = @byteSwap(limb.*); |
| 1628 | | } |
| 1645 | const limb_bytes = try gpa.alloc(u8, backing_bits / 8); |
| 1646 | defer gpa.free(limb_bytes); |
| 1647 | bigint.writeTwosComplement(limb_bytes, .little); |
| 1629 | 1648 | const scratch_top = cg.id_scratch.items.len; |
| 1630 | 1649 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| 1631 | 1650 | const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs); |
| 1632 | | for (constituents, 0..) |*c, i| { |
| 1633 | | c.* = try cg.constInt(.u32, limb_values[i]); |
| 1651 | switch (limb_bits) { |
| 1652 | 32 => { |
| 1653 | const limbs_u32: []u32 = @ptrCast(@alignCast(limb_bytes)); |
| 1654 | for (constituents, limbs_u32) |*c, v| { |
| 1655 | const host_v = if (builtin.cpu.arch.endian() == .big) @byteSwap(v) else v; |
| 1656 | c.* = try cg.constInt(.u32, host_v); |
| 1657 | } |
| 1658 | }, |
| 1659 | 64 => { |
| 1660 | const limbs_u64: []u64 = @ptrCast(@alignCast(limb_bytes)); |
| 1661 | for (constituents, limbs_u64) |*c, v| { |
| 1662 | const host_v = if (builtin.cpu.arch.endian() == .big) @byteSwap(v) else v; |
| 1663 | c.* = try cg.constInt(.u64, host_v); |
| 1664 | } |
| 1665 | }, |
| 1666 | else => unreachable, |
| 1634 | 1667 | } |
| 1635 | 1668 | break :cache try cg.constructComposite(big_result_ty_id, constituents); |
| 1636 | 1669 | } |
| ... | ... | @@ -1776,11 +1809,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { |
| 1776 | 1809 | const struct_type = zcu.typeToStruct(ty).?; |
| 1777 | 1810 | assert(struct_type.layout != .@"packed"); // packed structs use `bitpack` |
| 1778 | 1811 | |
| 1779 | | var types = std.array_list.Managed(Type).init(gpa); |
| 1780 | | defer types.deinit(); |
| 1812 | var types: std.ArrayList(Type) = .empty; |
| 1813 | defer types.deinit(gpa); |
| 1781 | 1814 | |
| 1782 | | var constituents = std.array_list.Managed(Id).init(gpa); |
| 1783 | | defer constituents.deinit(); |
| 1815 | var constituents: std.ArrayList(Id) = .empty; |
| 1816 | defer constituents.deinit(gpa); |
| 1784 | 1817 | |
| 1785 | 1818 | var it = struct_type.iterateRuntimeOrder(ip); |
| 1786 | 1819 | while (it.next()) |field_index| { |
| ... | ... | @@ -1794,8 +1827,8 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { |
| 1794 | 1827 | const field_val = try val.fieldValue(pt, field_index); |
| 1795 | 1828 | const field_id = try cg.constant(field_ty, field_val, .indirect); |
| 1796 | 1829 | |
| 1797 | | try types.append(field_ty); |
| 1798 | | try constituents.append(field_id); |
| 1830 | try types.append(gpa, field_ty); |
| 1831 | try constituents.append(gpa, field_id); |
| 1799 | 1832 | } |
| 1800 | 1833 | |
| 1801 | 1834 | const comp_ty_id = try cg.resolveType(ty, .direct); |
| ... | ... | @@ -2189,14 +2222,10 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 2189 | 2222 | 64 => target.cpu.has(.spirv, .float64), |
| 2190 | 2223 | else => false, |
| 2191 | 2224 | }; |
| 2192 | | |
| 2193 | | if (!supported) { |
| 2194 | | return cg.fail( |
| 2195 | | "floating point width of {} bits is not supported for the current SPIR-V feature set", |
| 2196 | | .{bits}, |
| 2197 | | ); |
| 2198 | | } |
| 2199 | | |
| 2225 | if (!supported) return cg.fail( |
| 2226 | "'{f}' is not supported on the current SPIR-V feature set", |
| 2227 | .{ty.fmt(cg.pt)}, |
| 2228 | ); |
| 2200 | 2229 | return try cg.floatType(bits); |
| 2201 | 2230 | }, |
| 2202 | 2231 | .array => { |
| ... | ... | @@ -2288,7 +2317,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 2288 | 2317 | }), |
| 2289 | 2318 | }, |
| 2290 | 2319 | }; |
| 2291 | | const child_ty_id = try cg.resolveType(child_ty, .indirect); |
| 2320 | const child_ty_id = try cg.pointeeType(ptr_info.flags.address_space, child_ty, false); |
| 2292 | 2321 | const storage_class = cg.storageClass(ptr_info.flags.address_space); |
| 2293 | 2322 | const ptr_ty_id = try cg.ptrType(child_ty_id, storage_class); |
| 2294 | 2323 | |
| ... | ... | @@ -2336,11 +2365,11 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 2336 | 2365 | return try cg.resolveType(.fromInterned(struct_type.packed_backing_int_type), .direct); |
| 2337 | 2366 | } |
| 2338 | 2367 | |
| 2339 | | var member_types = std.array_list.Managed(Id).init(gpa); |
| 2340 | | defer member_types.deinit(); |
| 2368 | var member_types: std.ArrayList(Id) = .empty; |
| 2369 | defer member_types.deinit(gpa); |
| 2341 | 2370 | |
| 2342 | | var member_names = std.array_list.Managed([]const u8).init(gpa); |
| 2343 | | defer member_names.deinit(); |
| 2371 | var member_names: std.ArrayList([]const u8) = .empty; |
| 2372 | defer member_names.deinit(gpa); |
| 2344 | 2373 | |
| 2345 | 2374 | var it = struct_type.iterateRuntimeOrder(ip); |
| 2346 | 2375 | while (it.next()) |field_index| { |
| ... | ... | @@ -2348,8 +2377,8 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 2348 | 2377 | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 2349 | 2378 | |
| 2350 | 2379 | const field_name = struct_type.field_names.get(ip)[field_index]; |
| 2351 | | try member_types.append(try cg.resolveType(field_ty, .indirect)); |
| 2352 | | try member_names.append(field_name.toSlice(ip)); |
| 2380 | try member_types.append(gpa, try cg.resolveType(field_ty, .indirect)); |
| 2381 | try member_names.append(gpa, field_name.toSlice(ip)); |
| 2353 | 2382 | } |
| 2354 | 2383 | |
| 2355 | 2384 | const result_id = try cg.structType( |
| ... | ... | @@ -2766,20 +2795,28 @@ const CompositeInt = struct { |
| 2766 | 2795 | info: ArithmeticTypeInfo, |
| 2767 | 2796 | |
| 2768 | 2797 | fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt { |
| 2769 | | const n_limbs: u16 = info.backing_bits / big_int_bits; |
| 2798 | const n_limbs: u16 = info.backing_bits / cg.bigIntBits(); |
| 2770 | 2799 | const gpa = cg.gpa; |
| 2771 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 2800 | if (cg.composite_limbs.get(composite_id)) |cached| { |
| 2801 | assert(cached.len == n_limbs); |
| 2802 | const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs); |
| 2803 | @memcpy(limbs, cached); |
| 2804 | return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info }; |
| 2805 | } |
| 2806 | const limb_ty_id = try cg.limbTypeId(); |
| 2772 | 2807 | const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs); |
| 2773 | 2808 | for (limbs, 0..) |*limb, i| { |
| 2774 | 2809 | const result_id = cg.allocId(); |
| 2775 | 2810 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 2776 | | .id_result_type = u32_ty_id, |
| 2811 | .id_result_type = limb_ty_id, |
| 2777 | 2812 | .id_result = result_id, |
| 2778 | 2813 | .composite = composite_id, |
| 2779 | 2814 | .indexes = &.{@as(u32, @intCast(i))}, |
| 2780 | 2815 | }); |
| 2781 | 2816 | limb.* = result_id; |
| 2782 | 2817 | } |
| 2818 | const cached = try cg.arena.dupe(Id, limbs); |
| 2819 | try cg.composite_limbs.put(gpa, composite_id, cached); |
| 2783 | 2820 | return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info }; |
| 2784 | 2821 | } |
| 2785 | 2822 | |
| ... | ... | @@ -2793,9 +2830,9 @@ const CompositeInt = struct { |
| 2793 | 2830 | } |
| 2794 | 2831 | |
| 2795 | 2832 | fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt { |
| 2796 | | const n_limbs: u16 = info.backing_bits / big_int_bits; |
| 2833 | const n_limbs: u16 = info.backing_bits / cg.bigIntBits(); |
| 2797 | 2834 | const limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, n_limbs); |
| 2798 | | const zero_id = try cg.constInt(.u32, @as(u32, 0)); |
| 2835 | const zero_id = try cg.constInt(cg.limbType(), @as(u64, 0)); |
| 2799 | 2836 | for (limbs) |*limb| limb.* = zero_id; |
| 2800 | 2837 | return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info }; |
| 2801 | 2838 | } |
| ... | ... | @@ -2808,10 +2845,10 @@ const CompositeInt = struct { |
| 2808 | 2845 | fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id { |
| 2809 | 2846 | const cg = ci.cg; |
| 2810 | 2847 | const gpa = cg.gpa; |
| 2811 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 2848 | const limb_ty_id = try cg.limbTypeId(); |
| 2812 | 2849 | const result_id = cg.allocId(); |
| 2813 | 2850 | try cg.body.emitRaw(gpa, opcode, 4); |
| 2814 | | cg.body.writeOperand(Id, u32_ty_id); |
| 2851 | cg.body.writeOperand(Id, limb_ty_id); |
| 2815 | 2852 | cg.body.writeOperand(Id, result_id); |
| 2816 | 2853 | cg.body.writeOperand(Id, lhs); |
| 2817 | 2854 | cg.body.writeOperand(Id, rhs); |
| ... | ... | @@ -2821,10 +2858,10 @@ const CompositeInt = struct { |
| 2821 | 2858 | fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id { |
| 2822 | 2859 | const cg = ci.cg; |
| 2823 | 2860 | const gpa = cg.gpa; |
| 2824 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 2861 | const limb_ty_id = try cg.limbTypeId(); |
| 2825 | 2862 | const result_id = cg.allocId(); |
| 2826 | 2863 | try cg.body.emitRaw(gpa, opcode, 3); |
| 2827 | | cg.body.writeOperand(Id, u32_ty_id); |
| 2864 | cg.body.writeOperand(Id, limb_ty_id); |
| 2828 | 2865 | cg.body.writeOperand(Id, result_id); |
| 2829 | 2866 | cg.body.writeOperand(Id, operand); |
| 2830 | 2867 | return result_id; |
| ... | ... | @@ -2916,16 +2953,17 @@ const CompositeInt = struct { |
| 2916 | 2953 | var cmp_l = l; |
| 2917 | 2954 | var cmp_r = r; |
| 2918 | 2955 | if (use_signed) { |
| 2919 | | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| 2956 | const signed_limb_ty: Type = if (cg.bigIntBits() == 64) .i64 else .i32; |
| 2957 | const signed_limb_ty_id = try cg.resolveType(signed_limb_ty, .direct); |
| 2920 | 2958 | const sl = cg.allocId(); |
| 2921 | 2959 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 2922 | | .id_result_type = i32_ty_id, |
| 2960 | .id_result_type = signed_limb_ty_id, |
| 2923 | 2961 | .id_result = sl, |
| 2924 | 2962 | .operand = l, |
| 2925 | 2963 | }); |
| 2926 | 2964 | const sr = cg.allocId(); |
| 2927 | 2965 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 2928 | | .id_result_type = i32_ty_id, |
| 2966 | .id_result_type = signed_limb_ty_id, |
| 2929 | 2967 | .id_result = sr, |
| 2930 | 2968 | .operand = r, |
| 2931 | 2969 | }); |
| ... | ... | @@ -2969,16 +3007,17 @@ const CompositeInt = struct { |
| 2969 | 3007 | const comp = zcu.comp; |
| 2970 | 3008 | const io = comp.io; |
| 2971 | 3009 | |
| 2972 | | const u32_zig = try pt.intType(.unsigned, 32); |
| 2973 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 3010 | const limb_bits = cg.bigIntBits(); |
| 3011 | const limb_zig = try pt.intType(.unsigned, limb_bits); |
| 3012 | const limb_ty_id = try cg.limbTypeId(); |
| 2974 | 3013 | const carry_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{ |
| 2975 | | .types = &.{ u32_zig.toIntern(), u32_zig.toIntern() }, |
| 3014 | .types = &.{ limb_zig.toIntern(), limb_zig.toIntern() }, |
| 2976 | 3015 | .values = &.{ .none, .none }, |
| 2977 | 3016 | })); |
| 2978 | 3017 | const carry_struct_ty_id = try cg.resolveType(carry_struct_ty, .direct); |
| 2979 | 3018 | |
| 2980 | 3019 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| 2981 | | var carry_id = try cg.constInt(.u32, @as(u32, 0)); |
| 3020 | var carry_id = try cg.constInt(cg.limbType(), @as(u64, 0)); |
| 2982 | 3021 | |
| 2983 | 3022 | const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow; |
| 2984 | 3023 | |
| ... | ... | @@ -2992,14 +3031,14 @@ const CompositeInt = struct { |
| 2992 | 3031 | |
| 2993 | 3032 | const sum1 = cg.allocId(); |
| 2994 | 3033 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 2995 | | .id_result_type = u32_ty_id, |
| 3034 | .id_result_type = limb_ty_id, |
| 2996 | 3035 | .id_result = sum1, |
| 2997 | 3036 | .composite = op1, |
| 2998 | 3037 | .indexes = &.{0}, |
| 2999 | 3038 | }); |
| 3000 | 3039 | const carry1 = cg.allocId(); |
| 3001 | 3040 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3002 | | .id_result_type = u32_ty_id, |
| 3041 | .id_result_type = limb_ty_id, |
| 3003 | 3042 | .id_result = carry1, |
| 3004 | 3043 | .composite = op1, |
| 3005 | 3044 | .indexes = &.{1}, |
| ... | ... | @@ -3014,14 +3053,14 @@ const CompositeInt = struct { |
| 3014 | 3053 | |
| 3015 | 3054 | result_limbs[i] = cg.allocId(); |
| 3016 | 3055 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3017 | | .id_result_type = u32_ty_id, |
| 3056 | .id_result_type = limb_ty_id, |
| 3018 | 3057 | .id_result = result_limbs[i], |
| 3019 | 3058 | .composite = op2, |
| 3020 | 3059 | .indexes = &.{0}, |
| 3021 | 3060 | }); |
| 3022 | 3061 | const carry2 = cg.allocId(); |
| 3023 | 3062 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3024 | | .id_result_type = u32_ty_id, |
| 3063 | .id_result_type = limb_ty_id, |
| 3025 | 3064 | .id_result = carry2, |
| 3026 | 3065 | .composite = op2, |
| 3027 | 3066 | .indexes = &.{1}, |
| ... | ... | @@ -3036,16 +3075,18 @@ const CompositeInt = struct { |
| 3036 | 3075 | fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt { |
| 3037 | 3076 | const cg = ci.cg; |
| 3038 | 3077 | const gpa = cg.gpa; |
| 3039 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 3078 | const limb_bits = cg.bigIntBits(); |
| 3079 | const limb_ty = cg.limbType(); |
| 3080 | const limb_ty_id = try cg.limbTypeId(); |
| 3040 | 3081 | const bool_ty_id = try cg.resolveType(.bool, .direct); |
| 3041 | | const zero_id = try cg.constInt(.u32, @as(u32, 0)); |
| 3042 | | const five_id = try cg.constInt(.u32, @as(u32, 5)); |
| 3043 | | const thirty_one_id = try cg.constInt(.u32, @as(u32, 31)); |
| 3044 | | const thirty_two_id = try cg.constInt(.u32, @as(u32, 32)); |
| 3045 | | |
| 3046 | | const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, five_id); |
| 3047 | | const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id); |
| 3048 | | const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac); |
| 3082 | const zero_id = try cg.constInt(limb_ty, @as(u64, 0)); |
| 3083 | const log2_bits_id = try cg.constInt(limb_ty, @as(u64, std.math.log2_int(u16, limb_bits))); |
| 3084 | const bits_minus_1_id = try cg.constInt(limb_ty, @as(u64, limb_bits - 1)); |
| 3085 | const bits_id = try cg.constInt(limb_ty, @as(u64, limb_bits)); |
| 3086 | |
| 3087 | const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, log2_bits_id); |
| 3088 | const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, bits_minus_1_id); |
| 3089 | const comp_frac = try ci.limbBinOp(.OpISub, bits_id, frac); |
| 3049 | 3090 | const frac_is_zero = blk: { |
| 3050 | 3091 | const r = cg.allocId(); |
| 3051 | 3092 | try cg.body.emit(gpa, .OpIEqual, .{ |
| ... | ... | @@ -3060,12 +3101,12 @@ const CompositeInt = struct { |
| 3060 | 3101 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| 3061 | 3102 | |
| 3062 | 3103 | for (0..ci.n_limbs) |i| { |
| 3063 | | const i_id = try cg.constInt(.u32, @as(u32, @intCast(i))); |
| 3104 | const i_id = try cg.constInt(limb_ty, @as(u64, @intCast(i))); |
| 3064 | 3105 | var main_val = zero_id; |
| 3065 | 3106 | var carry_val = zero_id; |
| 3066 | 3107 | |
| 3067 | 3108 | for (0..ci.n_limbs) |j| { |
| 3068 | | const j_id = try cg.constInt(.u32, @as(u32, @intCast(j))); |
| 3109 | const j_id = try cg.constInt(limb_ty, @as(u64, @intCast(j))); |
| 3069 | 3110 | const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole); |
| 3070 | 3111 | |
| 3071 | 3112 | const is_main = blk: { |
| ... | ... | @@ -3082,7 +3123,7 @@ const CompositeInt = struct { |
| 3082 | 3123 | main_val = blk: { |
| 3083 | 3124 | const r = cg.allocId(); |
| 3084 | 3125 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3085 | | .id_result_type = u32_ty_id, |
| 3126 | .id_result_type = limb_ty_id, |
| 3086 | 3127 | .id_result = r, |
| 3087 | 3128 | .condition = is_main, |
| 3088 | 3129 | .object_1 = shifted, |
| ... | ... | @@ -3091,7 +3132,7 @@ const CompositeInt = struct { |
| 3091 | 3132 | break :blk r; |
| 3092 | 3133 | }; |
| 3093 | 3134 | |
| 3094 | | const one_id = try cg.constInt(.u32, @as(u32, 1)); |
| 3135 | const one_id = try cg.constInt(limb_ty, @as(u64, 1)); |
| 3095 | 3136 | const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id); |
| 3096 | 3137 | const is_carry = blk: { |
| 3097 | 3138 | const r = cg.allocId(); |
| ... | ... | @@ -3107,7 +3148,7 @@ const CompositeInt = struct { |
| 3107 | 3148 | const guarded_carry = blk: { |
| 3108 | 3149 | const r = cg.allocId(); |
| 3109 | 3150 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3110 | | .id_result_type = u32_ty_id, |
| 3151 | .id_result_type = limb_ty_id, |
| 3111 | 3152 | .id_result = r, |
| 3112 | 3153 | .condition = frac_is_zero, |
| 3113 | 3154 | .object_1 = zero_id, |
| ... | ... | @@ -3118,7 +3159,7 @@ const CompositeInt = struct { |
| 3118 | 3159 | carry_val = blk: { |
| 3119 | 3160 | const r = cg.allocId(); |
| 3120 | 3161 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3121 | | .id_result_type = u32_ty_id, |
| 3162 | .id_result_type = limb_ty_id, |
| 3122 | 3163 | .id_result = r, |
| 3123 | 3164 | .condition = is_carry, |
| 3124 | 3165 | .object_1 = guarded_carry, |
| ... | ... | @@ -3137,16 +3178,18 @@ const CompositeInt = struct { |
| 3137 | 3178 | fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt { |
| 3138 | 3179 | const cg = ci.cg; |
| 3139 | 3180 | const gpa = cg.gpa; |
| 3140 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 3181 | const limb_bits = cg.bigIntBits(); |
| 3182 | const limb_ty = cg.limbType(); |
| 3183 | const limb_ty_id = try cg.limbTypeId(); |
| 3141 | 3184 | const bool_ty_id = try cg.resolveType(.bool, .direct); |
| 3142 | | const zero_id = try cg.constInt(.u32, @as(u32, 0)); |
| 3143 | | const five_id = try cg.constInt(.u32, @as(u32, 5)); |
| 3144 | | const thirty_one_id = try cg.constInt(.u32, @as(u32, 31)); |
| 3145 | | const thirty_two_id = try cg.constInt(.u32, @as(u32, 32)); |
| 3146 | | |
| 3147 | | const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, five_id); |
| 3148 | | const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id); |
| 3149 | | const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac); |
| 3185 | const zero_id = try cg.constInt(limb_ty, @as(u64, 0)); |
| 3186 | const log2_bits_id = try cg.constInt(limb_ty, @as(u64, std.math.log2_int(u16, limb_bits))); |
| 3187 | const bits_minus_1_id = try cg.constInt(limb_ty, @as(u64, limb_bits - 1)); |
| 3188 | const bits_id = try cg.constInt(limb_ty, @as(u64, limb_bits)); |
| 3189 | |
| 3190 | const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, log2_bits_id); |
| 3191 | const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, bits_minus_1_id); |
| 3192 | const comp_frac = try ci.limbBinOp(.OpISub, bits_id, frac); |
| 3150 | 3193 | const frac_is_zero = blk: { |
| 3151 | 3194 | const r = cg.allocId(); |
| 3152 | 3195 | try cg.body.emit(gpa, .OpIEqual, .{ |
| ... | ... | @@ -3159,24 +3202,25 @@ const CompositeInt = struct { |
| 3159 | 3202 | }; |
| 3160 | 3203 | |
| 3161 | 3204 | const fill_id = if (is_arithmetic) blk: { |
| 3162 | | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| 3205 | const signed_limb_ty: Type = if (limb_bits == 64) .i64 else .i32; |
| 3206 | const signed_limb_ty_id = try cg.resolveType(signed_limb_ty, .direct); |
| 3163 | 3207 | const msb_signed = cg.allocId(); |
| 3164 | 3208 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 3165 | | .id_result_type = i32_ty_id, |
| 3209 | .id_result_type = signed_limb_ty_id, |
| 3166 | 3210 | .id_result = msb_signed, |
| 3167 | 3211 | .operand = ci.limbs[ci.n_limbs - 1], |
| 3168 | 3212 | }); |
| 3169 | | const shift31 = try cg.constInt(.i32, @as(i32, 31)); |
| 3213 | const shift_amt = try cg.constInt(signed_limb_ty, @as(u64, limb_bits - 1)); |
| 3170 | 3214 | const sign_ext = cg.allocId(); |
| 3171 | 3215 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 3172 | | .id_result_type = i32_ty_id, |
| 3216 | .id_result_type = signed_limb_ty_id, |
| 3173 | 3217 | .id_result = sign_ext, |
| 3174 | 3218 | .base = msb_signed, |
| 3175 | | .shift = shift31, |
| 3219 | .shift = shift_amt, |
| 3176 | 3220 | }); |
| 3177 | 3221 | const back = cg.allocId(); |
| 3178 | 3222 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 3179 | | .id_result_type = u32_ty_id, |
| 3223 | .id_result_type = limb_ty_id, |
| 3180 | 3224 | .id_result = back, |
| 3181 | 3225 | .operand = sign_ext, |
| 3182 | 3226 | }); |
| ... | ... | @@ -3189,7 +3233,7 @@ const CompositeInt = struct { |
| 3189 | 3233 | const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac); |
| 3190 | 3234 | const guarded = cg.allocId(); |
| 3191 | 3235 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3192 | | .id_result_type = u32_ty_id, |
| 3236 | .id_result_type = limb_ty_id, |
| 3193 | 3237 | .id_result = guarded, |
| 3194 | 3238 | .condition = frac_is_zero, |
| 3195 | 3239 | .object_1 = zero_id, |
| ... | ... | @@ -3199,12 +3243,12 @@ const CompositeInt = struct { |
| 3199 | 3243 | } else zero_id; |
| 3200 | 3244 | |
| 3201 | 3245 | for (0..ci.n_limbs) |i| { |
| 3202 | | const i_id = try cg.constInt(.u32, @as(u32, @intCast(i))); |
| 3246 | const i_id = try cg.constInt(limb_ty, @as(u64, @intCast(i))); |
| 3203 | 3247 | var main_val = fill_id; |
| 3204 | 3248 | var carry_val = arith_carry_init; |
| 3205 | 3249 | |
| 3206 | 3250 | for (0..ci.n_limbs) |j| { |
| 3207 | | const j_id = try cg.constInt(.u32, @as(u32, @intCast(j))); |
| 3251 | const j_id = try cg.constInt(limb_ty, @as(u64, @intCast(j))); |
| 3208 | 3252 | const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole); |
| 3209 | 3253 | const is_main = blk: { |
| 3210 | 3254 | const r = cg.allocId(); |
| ... | ... | @@ -3220,7 +3264,7 @@ const CompositeInt = struct { |
| 3220 | 3264 | main_val = blk: { |
| 3221 | 3265 | const r = cg.allocId(); |
| 3222 | 3266 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3223 | | .id_result_type = u32_ty_id, |
| 3267 | .id_result_type = limb_ty_id, |
| 3224 | 3268 | .id_result = r, |
| 3225 | 3269 | .condition = is_main, |
| 3226 | 3270 | .object_1 = shifted, |
| ... | ... | @@ -3229,7 +3273,7 @@ const CompositeInt = struct { |
| 3229 | 3273 | break :blk r; |
| 3230 | 3274 | }; |
| 3231 | 3275 | |
| 3232 | | const one_id = try cg.constInt(.u32, @as(u32, 1)); |
| 3276 | const one_id = try cg.constInt(limb_ty, @as(u64, 1)); |
| 3233 | 3277 | const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id); |
| 3234 | 3278 | const is_carry = blk: { |
| 3235 | 3279 | const r = cg.allocId(); |
| ... | ... | @@ -3245,7 +3289,7 @@ const CompositeInt = struct { |
| 3245 | 3289 | const guarded_carry = blk: { |
| 3246 | 3290 | const r = cg.allocId(); |
| 3247 | 3291 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3248 | | .id_result_type = u32_ty_id, |
| 3292 | .id_result_type = limb_ty_id, |
| 3249 | 3293 | .id_result = r, |
| 3250 | 3294 | .condition = frac_is_zero, |
| 3251 | 3295 | .object_1 = zero_id, |
| ... | ... | @@ -3256,7 +3300,7 @@ const CompositeInt = struct { |
| 3256 | 3300 | carry_val = blk: { |
| 3257 | 3301 | const r = cg.allocId(); |
| 3258 | 3302 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3259 | | .id_result_type = u32_ty_id, |
| 3303 | .id_result_type = limb_ty_id, |
| 3260 | 3304 | .id_result = r, |
| 3261 | 3305 | .condition = is_carry, |
| 3262 | 3306 | .object_1 = guarded_carry, |
| ... | ... | @@ -3284,17 +3328,18 @@ const CompositeInt = struct { |
| 3284 | 3328 | |
| 3285 | 3329 | const n: usize = ci.n_limbs; |
| 3286 | 3330 | const total: usize = if (wide) 2 * n else n; |
| 3287 | | const u32_zig = try pt.intType(.unsigned, 32); |
| 3288 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 3331 | const limb_bits = cg.bigIntBits(); |
| 3332 | const limb_zig = try pt.intType(.unsigned, limb_bits); |
| 3333 | const limb_ty_id = try cg.limbTypeId(); |
| 3289 | 3334 | |
| 3290 | 3335 | const pair_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{ |
| 3291 | | .types = &.{ u32_zig.toIntern(), u32_zig.toIntern() }, |
| 3336 | .types = &.{ limb_zig.toIntern(), limb_zig.toIntern() }, |
| 3292 | 3337 | .values = &.{ .none, .none }, |
| 3293 | 3338 | })); |
| 3294 | 3339 | const pair_struct_ty_id = try cg.resolveType(pair_struct_ty, .direct); |
| 3295 | 3340 | |
| 3296 | 3341 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, total); |
| 3297 | | const zero_id = try cg.constInt(.u32, @as(u32, 0)); |
| 3342 | const zero_id = try cg.constInt(cg.limbType(), @as(u64, 0)); |
| 3298 | 3343 | for (result_limbs) |*r| r.* = zero_id; |
| 3299 | 3344 | |
| 3300 | 3345 | for (0..n) |i| { |
| ... | ... | @@ -3309,7 +3354,7 @@ const CompositeInt = struct { |
| 3309 | 3354 | .opencl => { |
| 3310 | 3355 | lo = cg.allocId(); |
| 3311 | 3356 | try cg.body.emit(gpa, .OpIMul, .{ |
| 3312 | | .id_result_type = u32_ty_id, |
| 3357 | .id_result_type = limb_ty_id, |
| 3313 | 3358 | .id_result = lo, |
| 3314 | 3359 | .operand_1 = ci.limbs[i], |
| 3315 | 3360 | .operand_2 = other.limbs[j], |
| ... | ... | @@ -3318,7 +3363,7 @@ const CompositeInt = struct { |
| 3318 | 3363 | const set = try cg.importExtendedSet(); |
| 3319 | 3364 | hi = cg.allocId(); |
| 3320 | 3365 | try cg.body.emit(gpa, .OpExtInst, .{ |
| 3321 | | .id_result_type = u32_ty_id, |
| 3366 | .id_result_type = limb_ty_id, |
| 3322 | 3367 | .id_result = hi, |
| 3323 | 3368 | .set = set, |
| 3324 | 3369 | .instruction = .{ .inst = @intFromEnum(spec.OpenClOpcode.u_mul_hi) }, |
| ... | ... | @@ -3336,14 +3381,14 @@ const CompositeInt = struct { |
| 3336 | 3381 | |
| 3337 | 3382 | lo = cg.allocId(); |
| 3338 | 3383 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3339 | | .id_result_type = u32_ty_id, |
| 3384 | .id_result_type = limb_ty_id, |
| 3340 | 3385 | .id_result = lo, |
| 3341 | 3386 | .composite = mul_result, |
| 3342 | 3387 | .indexes = &.{0}, |
| 3343 | 3388 | }); |
| 3344 | 3389 | hi = cg.allocId(); |
| 3345 | 3390 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3346 | | .id_result_type = u32_ty_id, |
| 3391 | .id_result_type = limb_ty_id, |
| 3347 | 3392 | .id_result = hi, |
| 3348 | 3393 | .composite = mul_result, |
| 3349 | 3394 | .indexes = &.{1}, |
| ... | ... | @@ -3361,14 +3406,14 @@ const CompositeInt = struct { |
| 3361 | 3406 | |
| 3362 | 3407 | const sum1 = cg.allocId(); |
| 3363 | 3408 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3364 | | .id_result_type = u32_ty_id, |
| 3409 | .id_result_type = limb_ty_id, |
| 3365 | 3410 | .id_result = sum1, |
| 3366 | 3411 | .composite = add1, |
| 3367 | 3412 | .indexes = &.{0}, |
| 3368 | 3413 | }); |
| 3369 | 3414 | const c1 = cg.allocId(); |
| 3370 | 3415 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3371 | | .id_result_type = u32_ty_id, |
| 3416 | .id_result_type = limb_ty_id, |
| 3372 | 3417 | .id_result = c1, |
| 3373 | 3418 | .composite = add1, |
| 3374 | 3419 | .indexes = &.{1}, |
| ... | ... | @@ -3384,14 +3429,14 @@ const CompositeInt = struct { |
| 3384 | 3429 | |
| 3385 | 3430 | result_limbs[k] = cg.allocId(); |
| 3386 | 3431 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3387 | | .id_result_type = u32_ty_id, |
| 3432 | .id_result_type = limb_ty_id, |
| 3388 | 3433 | .id_result = result_limbs[k], |
| 3389 | 3434 | .composite = add2, |
| 3390 | 3435 | .indexes = &.{0}, |
| 3391 | 3436 | }); |
| 3392 | 3437 | const c2 = cg.allocId(); |
| 3393 | 3438 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3394 | | .id_result_type = u32_ty_id, |
| 3439 | .id_result_type = limb_ty_id, |
| 3395 | 3440 | .id_result = c2, |
| 3396 | 3441 | .composite = add2, |
| 3397 | 3442 | .indexes = &.{1}, |
| ... | ... | @@ -3412,7 +3457,8 @@ const CompositeInt = struct { |
| 3412 | 3457 | if (ci.info.bits == ci.info.backing_bits) return ci; |
| 3413 | 3458 | const cg = ci.cg; |
| 3414 | 3459 | const gpa = cg.gpa; |
| 3415 | | const top_bits: u16 = ci.info.bits % big_int_bits; |
| 3460 | const limb_bits = cg.bigIntBits(); |
| 3461 | const top_bits: u16 = ci.info.bits % limb_bits; |
| 3416 | 3462 | assert(top_bits != 0); |
| 3417 | 3463 | |
| 3418 | 3464 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| ... | ... | @@ -3421,41 +3467,43 @@ const CompositeInt = struct { |
| 3421 | 3467 | } |
| 3422 | 3468 | |
| 3423 | 3469 | const top_limb = ci.limbs[ci.n_limbs - 1]; |
| 3470 | const limb_ty = cg.limbType(); |
| 3471 | const limb_signed_ty: Type = if (limb_bits == 64) .i64 else .i32; |
| 3424 | 3472 | switch (ci.info.signedness) { |
| 3425 | 3473 | .unsigned => { |
| 3426 | | const mask_val: u32 = (@as(u32, 1) << @as(u5, @intCast(top_bits))) - 1; |
| 3427 | | const mask_id = try cg.constInt(.u32, mask_val); |
| 3474 | const mask_val: u64 = (@as(u64, 1) << @as(u6, @intCast(top_bits))) - 1; |
| 3475 | const mask_id = try cg.constInt(limb_ty, mask_val); |
| 3428 | 3476 | result_limbs[ci.n_limbs - 1] = try ci.limbBinOp(.OpBitwiseAnd, top_limb, mask_id); |
| 3429 | 3477 | }, |
| 3430 | 3478 | .signed => { |
| 3431 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 3432 | | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| 3433 | | const shift_amt: u32 = 32 - top_bits; |
| 3434 | | const shift_id = try cg.constInt(.u32, shift_amt); |
| 3479 | const limb_ty_id = try cg.limbTypeId(); |
| 3480 | const signed_ty_id = try cg.resolveType(limb_signed_ty, .direct); |
| 3481 | const shift_amt: u32 = @intCast(limb_bits - top_bits); |
| 3482 | const shift_id = try cg.constInt(limb_ty, shift_amt); |
| 3435 | 3483 | |
| 3436 | 3484 | const as_signed = cg.allocId(); |
| 3437 | 3485 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 3438 | | .id_result_type = i32_ty_id, |
| 3486 | .id_result_type = signed_ty_id, |
| 3439 | 3487 | .id_result = as_signed, |
| 3440 | 3488 | .operand = top_limb, |
| 3441 | 3489 | }); |
| 3442 | 3490 | const shifted_left = cg.allocId(); |
| 3443 | 3491 | try cg.body.emit(gpa, .OpShiftLeftLogical, .{ |
| 3444 | | .id_result_type = i32_ty_id, |
| 3492 | .id_result_type = signed_ty_id, |
| 3445 | 3493 | .id_result = shifted_left, |
| 3446 | 3494 | .base = as_signed, |
| 3447 | 3495 | .shift = shift_id, |
| 3448 | 3496 | }); |
| 3449 | 3497 | const shifted_right = cg.allocId(); |
| 3450 | 3498 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 3451 | | .id_result_type = i32_ty_id, |
| 3499 | .id_result_type = signed_ty_id, |
| 3452 | 3500 | .id_result = shifted_right, |
| 3453 | 3501 | .base = shifted_left, |
| 3454 | 3502 | .shift = shift_id, |
| 3455 | 3503 | }); |
| 3456 | 3504 | const back = cg.allocId(); |
| 3457 | 3505 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 3458 | | .id_result_type = u32_ty_id, |
| 3506 | .id_result_type = limb_ty_id, |
| 3459 | 3507 | .id_result = back, |
| 3460 | 3508 | .operand = shifted_right, |
| 3461 | 3509 | }); |
| ... | ... | @@ -4218,13 +4266,16 @@ const MemoryOptions = struct { |
| 4218 | 4266 | fn needsLayout(cg: *CodeGen, as: std.lang.AddressSpace, pointee_ty: Type) bool { |
| 4219 | 4267 | const target = cg.zcu.getTarget(); |
| 4220 | 4268 | if (target.os.tag != .vulkan and target.os.tag != .opengl) return false; |
| 4221 | | switch (as) { |
| 4222 | | .uniform, .push_constant, .storage_buffer => {}, |
| 4223 | | else => return false, |
| 4224 | | } |
| 4225 | | return switch (pointee_ty.zigTypeTag(cg.zcu)) { |
| 4226 | | .@"struct", .@"union", .array => true, |
| 4227 | | .spirv => pointee_ty.isSpirvRuntimeArray(cg.zcu), |
| 4269 | return switch (as) { |
| 4270 | .uniform, |
| 4271 | .push_constant, |
| 4272 | .storage_buffer, |
| 4273 | .physical_storage_buffer, |
| 4274 | => switch (pointee_ty.zigTypeTag(cg.zcu)) { |
| 4275 | .@"struct", .@"union", .array => true, |
| 4276 | .spirv => pointee_ty.isSpirvRuntimeArray(cg.zcu), |
| 4277 | else => false, |
| 4278 | }, |
| 4228 | 4279 | else => false, |
| 4229 | 4280 | }; |
| 4230 | 4281 | } |
| ... | ... | @@ -4537,10 +4588,6 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode |
| 4537 | 4588 | const zcu = cg.zcu; |
| 4538 | 4589 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 4539 | 4590 | |
| 4540 | | if (cg.typeOf(bin_op.lhs).isVector(zcu) and !cg.typeOf(bin_op.rhs).isVector(zcu)) { |
| 4541 | | return cg.fail("vector shift with scalar rhs", .{}); |
| 4542 | | } |
| 4543 | | |
| 4544 | 4591 | const base = try cg.temporary(bin_op.lhs); |
| 4545 | 4592 | const shift = try cg.temporary(bin_op.rhs); |
| 4546 | 4593 | |
| ... | ... | @@ -4550,13 +4597,14 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode |
| 4550 | 4597 | switch (info.class) { |
| 4551 | 4598 | .composite_integer => { |
| 4552 | 4599 | const shift_info = cg.arithmeticTypeInfo(shift.ty); |
| 4600 | const limb_ty = cg.limbType(); |
| 4553 | 4601 | const shift_amt_id = switch (shift_info.class) { |
| 4554 | 4602 | .composite_integer => blk: { |
| 4555 | 4603 | const shift_id = try shift.materialize(cg); |
| 4556 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 4604 | const limb_ty_id = try cg.limbTypeId(); |
| 4557 | 4605 | const result_id = cg.allocId(); |
| 4558 | 4606 | try cg.body.emit(cg.gpa, .OpCompositeExtract, .{ |
| 4559 | | .id_result_type = u32_ty_id, |
| 4607 | .id_result_type = limb_ty_id, |
| 4560 | 4608 | .id_result = result_id, |
| 4561 | 4609 | .composite = shift_id, |
| 4562 | 4610 | .indexes = &.{@as(u32, 0)}, |
| ... | ... | @@ -4564,7 +4612,7 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode |
| 4564 | 4612 | break :blk result_id; |
| 4565 | 4613 | }, |
| 4566 | 4614 | else => blk: { |
| 4567 | | const converted = try cg.buildConvert(.u32, shift); |
| 4615 | const converted = try cg.buildConvert(limb_ty, shift); |
| 4568 | 4616 | break :blk try converted.materialize(cg); |
| 4569 | 4617 | }, |
| 4570 | 4618 | }; |
| ... | ... | @@ -4885,12 +4933,12 @@ fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4885 | 4933 | const is_neg = try ci.cmp(ci_z, .lt); |
| 4886 | 4934 | const ci_neg = try ci_z.addSub(ci, false); |
| 4887 | 4935 | const result_info = cg.arithmeticTypeInfo(result_ty); |
| 4888 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 4936 | const limb_ty_id = try cg.limbTypeId(); |
| 4889 | 4937 | const result_limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, ci.n_limbs); |
| 4890 | 4938 | for (0..ci.n_limbs) |i| { |
| 4891 | 4939 | result_limbs[i] = cg.allocId(); |
| 4892 | 4940 | try cg.body.emit(cg.gpa, .OpSelect, .{ |
| 4893 | | .id_result_type = u32_ty_id, |
| 4941 | .id_result_type = limb_ty_id, |
| 4894 | 4942 | .id_result = result_limbs[i], |
| 4895 | 4943 | .condition = is_neg, |
| 4896 | 4944 | .object_1 = ci_neg.limbs[i], |
| ... | ... | @@ -5064,12 +5112,13 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5064 | 5112 | const high_limbs = wide_limbs[ci_lhs2.n_limbs..]; |
| 5065 | 5113 | |
| 5066 | 5114 | const bool_ty_id = try cg.resolveType(.bool, .direct); |
| 5067 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 5068 | | const n: usize = info.backing_bits / big_int_bits; |
| 5115 | const limb_ty_id = try cg.limbTypeId(); |
| 5116 | const limb_ty = cg.limbType(); |
| 5117 | const n: usize = info.backing_bits / cg.bigIntBits(); |
| 5069 | 5118 | |
| 5070 | 5119 | const ov_bool = switch (info.signedness) { |
| 5071 | 5120 | .unsigned => blk: { |
| 5072 | | const zero_id = try cg.constInt(.u32, @as(u32, 0)); |
| 5121 | const zero_id = try cg.constInt(limb_ty, @as(u64, 0)); |
| 5073 | 5122 | var any_nonzero = cg.allocId(); |
| 5074 | 5123 | try cg.body.emit(gpa, .OpINotEqual, .{ |
| 5075 | 5124 | .id_result_type = bool_ty_id, |
| ... | ... | @@ -5102,32 +5151,33 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5102 | 5151 | .signed => blk: { |
| 5103 | 5152 | const ci_res = try CompositeInt.init(cg, result_val_id, info); |
| 5104 | 5153 | const top_limb = ci_res.limbs[n - 1]; |
| 5105 | | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| 5154 | const signed_limb_ty: Type = if (cg.bigIntBits() == 64) .i64 else .i32; |
| 5155 | const signed_limb_ty_id = try cg.resolveType(signed_limb_ty, .direct); |
| 5106 | 5156 | |
| 5107 | | const top_bits: u16 = if (info.bits % big_int_bits == 0) |
| 5108 | | big_int_bits |
| 5157 | const top_bits: u16 = if (info.bits % cg.bigIntBits() == 0) |
| 5158 | cg.bigIntBits() |
| 5109 | 5159 | else |
| 5110 | | info.bits % big_int_bits; |
| 5160 | info.bits % cg.bigIntBits(); |
| 5111 | 5161 | |
| 5112 | | const shift_amt: u32 = top_bits - 1; |
| 5113 | | const shift_id = try cg.constInt(.u32, shift_amt); |
| 5162 | const shift_amt: u64 = top_bits - 1; |
| 5163 | const shift_id = try cg.constInt(limb_ty, shift_amt); |
| 5114 | 5164 | |
| 5115 | 5165 | const as_signed = cg.allocId(); |
| 5116 | 5166 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 5117 | | .id_result_type = i32_ty_id, |
| 5167 | .id_result_type = signed_limb_ty_id, |
| 5118 | 5168 | .id_result = as_signed, |
| 5119 | 5169 | .operand = top_limb, |
| 5120 | 5170 | }); |
| 5121 | 5171 | const sign_ext = cg.allocId(); |
| 5122 | 5172 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 5123 | | .id_result_type = i32_ty_id, |
| 5173 | .id_result_type = signed_limb_ty_id, |
| 5124 | 5174 | .id_result = sign_ext, |
| 5125 | 5175 | .base = as_signed, |
| 5126 | 5176 | .shift = shift_id, |
| 5127 | 5177 | }); |
| 5128 | 5178 | const expected = cg.allocId(); |
| 5129 | 5179 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 5130 | | .id_result_type = u32_ty_id, |
| 5180 | .id_result_type = limb_ty_id, |
| 5131 | 5181 | .id_result = expected, |
| 5132 | 5182 | .operand = sign_ext, |
| 5133 | 5183 | }); |
| ... | ... | @@ -5160,25 +5210,25 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5160 | 5210 | } |
| 5161 | 5211 | |
| 5162 | 5212 | if (info.bits != info.backing_bits) { |
| 5163 | | const top_bits_s: u16 = info.bits % big_int_bits; |
| 5164 | | const s_shift_id = try cg.constInt(.u32, top_bits_s - 1); |
| 5213 | const top_bits_s: u16 = info.bits % cg.bigIntBits(); |
| 5214 | const s_shift_id = try cg.constInt(limb_ty, @as(u64, top_bits_s - 1)); |
| 5165 | 5215 | |
| 5166 | 5216 | const top_as_signed = cg.allocId(); |
| 5167 | 5217 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 5168 | | .id_result_type = i32_ty_id, |
| 5218 | .id_result_type = signed_limb_ty_id, |
| 5169 | 5219 | .id_result = top_as_signed, |
| 5170 | 5220 | .operand = top_limb, |
| 5171 | 5221 | }); |
| 5172 | 5222 | const top_sign_ext = cg.allocId(); |
| 5173 | 5223 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 5174 | | .id_result_type = i32_ty_id, |
| 5224 | .id_result_type = signed_limb_ty_id, |
| 5175 | 5225 | .id_result = top_sign_ext, |
| 5176 | 5226 | .base = top_as_signed, |
| 5177 | 5227 | .shift = s_shift_id, |
| 5178 | 5228 | }); |
| 5179 | 5229 | const top_expected = cg.allocId(); |
| 5180 | 5230 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 5181 | | .id_result_type = u32_ty_id, |
| 5231 | .id_result_type = limb_ty_id, |
| 5182 | 5232 | .id_result = top_expected, |
| 5183 | 5233 | .operand = top_sign_ext, |
| 5184 | 5234 | }); |
| ... | ... | @@ -5219,7 +5269,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5219 | 5269 | // of the result too. |
| 5220 | 5270 | |
| 5221 | 5271 | const target = cg.zcu.getTarget(); |
| 5222 | | const largest_int_bits: u16 = if (target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64) 64 else 32; |
| 5272 | const largest_int_bits: u16 = if (hasInt64(target)) 64 else 32; |
| 5223 | 5273 | // If non-null, the number of bits that the multiplication should be performed in. If |
| 5224 | 5274 | // null, we have to use wide multiplication. |
| 5225 | 5275 | const maybe_op_ty_bits: ?u16 = switch (info.bits) { |
| ... | ... | @@ -5368,10 +5418,6 @@ fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5368 | 5418 | const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 5369 | 5419 | const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data; |
| 5370 | 5420 | |
| 5371 | | if (cg.typeOf(extra.lhs).isVector(zcu) and !cg.typeOf(extra.rhs).isVector(zcu)) { |
| 5372 | | return cg.fail("vector shift with scalar rhs", .{}); |
| 5373 | | } |
| 5374 | | |
| 5375 | 5421 | const base = try cg.temporary(extra.lhs); |
| 5376 | 5422 | const shift = try cg.temporary(extra.rhs); |
| 5377 | 5423 | |
| ... | ... | @@ -5964,7 +6010,27 @@ fn bitCast( |
| 5964 | 6010 | |
| 5965 | 6011 | if (src_ty.toIntern() == dst_ty.toIntern()) return src_id; |
| 5966 | 6012 | if (src_ty.isPtrAtRuntime(zcu) and dst_ty.isPtrAtRuntime(zcu)) switch (target.os.tag) { |
| 5967 | | .vulkan, .opengl => if (src_ty.ptrAddressSpace(zcu) != .physical_storage_buffer) return src_id, |
| 6013 | .vulkan, .opengl => if (src_ty.ptrAddressSpace(zcu) != .physical_storage_buffer) { |
| 6014 | const src_child = src_ty.childType(zcu); |
| 6015 | const dst_child = dst_ty.childType(zcu); |
| 6016 | if (!dst_child.hasRuntimeBits(zcu)) return src_id; |
| 6017 | if (src_child.toIntern() == dst_child.toIntern()) return src_id; |
| 6018 | if (src_ty.ptrInfo(zcu).packed_offset.host_size != 0 or |
| 6019 | dst_ty.ptrInfo(zcu).packed_offset.host_size != 0) return src_id; |
| 6020 | |
| 6021 | var indices: std.ArrayList(u32) = .empty; |
| 6022 | defer indices.deinit(gpa); |
| 6023 | var cur = src_child; |
| 6024 | while (cur.toIntern() != dst_child.toIntern()) : (try indices.append(gpa, 0)) { |
| 6025 | cur = switch (cur.zigTypeTag(zcu)) { |
| 6026 | .array, .vector => cur.childType(zcu), |
| 6027 | .@"struct" => cur.fieldType(0, zcu), |
| 6028 | else => unreachable, |
| 6029 | }; |
| 6030 | } |
| 6031 | const dst_ty_id = try cg.resolveType(dst_ty, .direct); |
| 6032 | return try cg.accessChain(dst_ty_id, src_id, indices.items); |
| 6033 | }, |
| 5968 | 6034 | else => {}, |
| 5969 | 6035 | }; |
| 5970 | 6036 | |
| ... | ... | @@ -6095,15 +6161,17 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6095 | 6161 | |
| 6096 | 6162 | if (src_composite and dst_composite) { |
| 6097 | 6163 | const src_id = try src.materialize(cg); |
| 6098 | | const src_n: u16 = src_info.backing_bits / big_int_bits; |
| 6099 | | const dst_n: u16 = dst_info.backing_bits / big_int_bits; |
| 6164 | const limb_bits = cg.bigIntBits(); |
| 6165 | const limb_ty = cg.limbType(); |
| 6166 | const limb_ty_id = try cg.limbTypeId(); |
| 6167 | const src_n: u16 = src_info.backing_bits / limb_bits; |
| 6168 | const dst_n: u16 = dst_info.backing_bits / limb_bits; |
| 6100 | 6169 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n); |
| 6101 | 6170 | const min_n = @min(src_n, dst_n); |
| 6102 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 6103 | 6171 | for (0..min_n) |i| { |
| 6104 | 6172 | result_limbs[i] = cg.allocId(); |
| 6105 | 6173 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 6106 | | .id_result_type = u32_ty_id, |
| 6174 | .id_result_type = limb_ty_id, |
| 6107 | 6175 | .id_result = result_limbs[i], |
| 6108 | 6176 | .composite = src_id, |
| 6109 | 6177 | .indexes = &.{@as(u32, @intCast(i))}, |
| ... | ... | @@ -6111,30 +6179,31 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6111 | 6179 | } |
| 6112 | 6180 | if (dst_n > src_n) { |
| 6113 | 6181 | const fill = if (src_info.signedness == .signed) blk: { |
| 6114 | | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| 6182 | const signed_limb_ty: Type = if (limb_bits == 64) .i64 else .i32; |
| 6183 | const signed_limb_ty_id = try cg.resolveType(signed_limb_ty, .direct); |
| 6115 | 6184 | const msb = result_limbs[src_n - 1]; |
| 6116 | 6185 | const msb_signed = cg.allocId(); |
| 6117 | 6186 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 6118 | | .id_result_type = i32_ty_id, |
| 6187 | .id_result_type = signed_limb_ty_id, |
| 6119 | 6188 | .id_result = msb_signed, |
| 6120 | 6189 | .operand = msb, |
| 6121 | 6190 | }); |
| 6122 | | const shift31 = try cg.constInt(.i32, @as(i32, 31)); |
| 6191 | const shift_amt = try cg.constInt(signed_limb_ty, @as(u64, limb_bits - 1)); |
| 6123 | 6192 | const sign_ext = cg.allocId(); |
| 6124 | 6193 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 6125 | | .id_result_type = i32_ty_id, |
| 6194 | .id_result_type = signed_limb_ty_id, |
| 6126 | 6195 | .id_result = sign_ext, |
| 6127 | 6196 | .base = msb_signed, |
| 6128 | | .shift = shift31, |
| 6197 | .shift = shift_amt, |
| 6129 | 6198 | }); |
| 6130 | 6199 | const back = cg.allocId(); |
| 6131 | 6200 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 6132 | | .id_result_type = u32_ty_id, |
| 6201 | .id_result_type = limb_ty_id, |
| 6133 | 6202 | .id_result = back, |
| 6134 | 6203 | .operand = sign_ext, |
| 6135 | 6204 | }); |
| 6136 | 6205 | break :blk back; |
| 6137 | | } else try cg.constInt(.u32, @as(u32, 0)); |
| 6206 | } else try cg.constInt(limb_ty, @as(u64, 0)); |
| 6138 | 6207 | for (min_n..dst_n) |i| { |
| 6139 | 6208 | result_limbs[i] = fill; |
| 6140 | 6209 | } |
| ... | ... | @@ -6144,16 +6213,18 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6144 | 6213 | return try normalized.materialize(dst_ty); |
| 6145 | 6214 | } else if (src_composite and !dst_composite) { |
| 6146 | 6215 | const src_id = try src.materialize(cg); |
| 6147 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 6148 | | if (dst_info.backing_bits <= 32) { |
| 6216 | const limb_bits = cg.bigIntBits(); |
| 6217 | const limb_ty = cg.limbType(); |
| 6218 | const limb_ty_id = try cg.limbTypeId(); |
| 6219 | if (dst_info.backing_bits <= limb_bits) { |
| 6149 | 6220 | const limb0 = cg.allocId(); |
| 6150 | 6221 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 6151 | | .id_result_type = u32_ty_id, |
| 6222 | .id_result_type = limb_ty_id, |
| 6152 | 6223 | .id_result = limb0, |
| 6153 | 6224 | .composite = src_id, |
| 6154 | 6225 | .indexes = &.{@as(u32, 0)}, |
| 6155 | 6226 | }); |
| 6156 | | const tmp: Temporary = .init(.u32, limb0); |
| 6227 | const tmp: Temporary = .init(limb_ty, limb0); |
| 6157 | 6228 | const converted = try cg.buildConvert(dst_ty, tmp); |
| 6158 | 6229 | const result = if (dst_info.bits < src_info.bits) |
| 6159 | 6230 | try cg.normalize(converted, dst_info) |
| ... | ... | @@ -6161,16 +6232,17 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6161 | 6232 | converted; |
| 6162 | 6233 | return try result.materialize(cg); |
| 6163 | 6234 | } else { |
| 6235 | assert(limb_bits == 32); // dst > 64 while limbs are 64 shouldn't happen — dst fits in one 64-bit limb. |
| 6164 | 6236 | const limb0 = cg.allocId(); |
| 6165 | 6237 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 6166 | | .id_result_type = u32_ty_id, |
| 6238 | .id_result_type = limb_ty_id, |
| 6167 | 6239 | .id_result = limb0, |
| 6168 | 6240 | .composite = src_id, |
| 6169 | 6241 | .indexes = &.{@as(u32, 0)}, |
| 6170 | 6242 | }); |
| 6171 | 6243 | const limb1 = cg.allocId(); |
| 6172 | 6244 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 6173 | | .id_result_type = u32_ty_id, |
| 6245 | .id_result_type = limb_ty_id, |
| 6174 | 6246 | .id_result = limb1, |
| 6175 | 6247 | .composite = src_id, |
| 6176 | 6248 | .indexes = &.{@as(u32, 1)}, |
| ... | ... | @@ -6212,19 +6284,21 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6212 | 6284 | return try result.materialize(cg); |
| 6213 | 6285 | } |
| 6214 | 6286 | } else { |
| 6215 | | const dst_n: u16 = dst_info.backing_bits / big_int_bits; |
| 6287 | const limb_bits = cg.bigIntBits(); |
| 6288 | const limb_ty = cg.limbType(); |
| 6289 | const limb_ty_id = try cg.limbTypeId(); |
| 6290 | const dst_n: u16 = dst_info.backing_bits / limb_bits; |
| 6216 | 6291 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n); |
| 6217 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 6218 | 6292 | |
| 6219 | | if (src_info.backing_bits <= 32) { |
| 6220 | | const converted = try cg.buildConvert(.u32, src); |
| 6293 | if (src_info.backing_bits <= limb_bits) { |
| 6294 | const converted = try cg.buildConvert(limb_ty, src); |
| 6221 | 6295 | result_limbs[0] = try converted.materialize(cg); |
| 6222 | 6296 | } else { |
| 6223 | 6297 | const src_as_u64 = try cg.buildConvert(.u64, src); |
| 6224 | 6298 | const src_id = try src_as_u64.materialize(cg); |
| 6225 | 6299 | result_limbs[0] = cg.allocId(); |
| 6226 | 6300 | try cg.body.emit(gpa, .OpUConvert, .{ |
| 6227 | | .id_result_type = u32_ty_id, |
| 6301 | .id_result_type = limb_ty_id, |
| 6228 | 6302 | .id_result = result_limbs[0], |
| 6229 | 6303 | .unsigned_value = src_id, |
| 6230 | 6304 | }); |
| ... | ... | @@ -6239,38 +6313,39 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6239 | 6313 | }); |
| 6240 | 6314 | result_limbs[1] = cg.allocId(); |
| 6241 | 6315 | try cg.body.emit(gpa, .OpUConvert, .{ |
| 6242 | | .id_result_type = u32_ty_id, |
| 6316 | .id_result_type = limb_ty_id, |
| 6243 | 6317 | .id_result = result_limbs[1], |
| 6244 | 6318 | .unsigned_value = hi, |
| 6245 | 6319 | }); |
| 6246 | 6320 | } |
| 6247 | 6321 | // Sign/zero-extend remaining limbs. |
| 6248 | | const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2; |
| 6322 | const fill_start: u16 = if (src_info.backing_bits <= limb_bits) 1 else 2; |
| 6249 | 6323 | const fill = if (src_info.signedness == .signed) blk: { |
| 6250 | | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| 6324 | const signed_limb_ty: Type = if (limb_bits == 64) .i64 else .i32; |
| 6325 | const signed_limb_ty_id = try cg.resolveType(signed_limb_ty, .direct); |
| 6251 | 6326 | const msb = result_limbs[fill_start - 1]; |
| 6252 | 6327 | const msb_signed = cg.allocId(); |
| 6253 | 6328 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 6254 | | .id_result_type = i32_ty_id, |
| 6329 | .id_result_type = signed_limb_ty_id, |
| 6255 | 6330 | .id_result = msb_signed, |
| 6256 | 6331 | .operand = msb, |
| 6257 | 6332 | }); |
| 6258 | | const shift31 = try cg.constInt(.i32, @as(i32, 31)); |
| 6333 | const shift_amt = try cg.constInt(signed_limb_ty, @as(u64, limb_bits - 1)); |
| 6259 | 6334 | const sign_ext = cg.allocId(); |
| 6260 | 6335 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 6261 | | .id_result_type = i32_ty_id, |
| 6336 | .id_result_type = signed_limb_ty_id, |
| 6262 | 6337 | .id_result = sign_ext, |
| 6263 | 6338 | .base = msb_signed, |
| 6264 | | .shift = shift31, |
| 6339 | .shift = shift_amt, |
| 6265 | 6340 | }); |
| 6266 | 6341 | const back = cg.allocId(); |
| 6267 | 6342 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 6268 | | .id_result_type = u32_ty_id, |
| 6343 | .id_result_type = limb_ty_id, |
| 6269 | 6344 | .id_result = back, |
| 6270 | 6345 | .operand = sign_ext, |
| 6271 | 6346 | }); |
| 6272 | 6347 | break :blk back; |
| 6273 | | } else try cg.constInt(.u32, @as(u32, 0)); |
| 6348 | } else try cg.constInt(limb_ty, @as(u64, 0)); |
| 6274 | 6349 | for (fill_start..dst_n) |i| { |
| 6275 | 6350 | result_limbs[i] = fill; |
| 6276 | 6351 | } |
| ... | ... | @@ -8632,37 +8707,68 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 8632 | 8707 | const input_ty = cg.typeOf(in.operand); |
| 8633 | 8708 | |
| 8634 | 8709 | if (std.mem.eql(u8, in.constraint, "c")) { |
| 8635 | | // constant |
| 8636 | | const val: Value = .fromInterned(in.operand.toInterned() orelse { |
| 8637 | | return cg.fail("assembly inputs with 'c' constraint have to be compile-time known", .{}); |
| 8638 | | }); |
| 8639 | | |
| 8710 | const val: Value = .fromInterned(in.operand.toInterned().?); |
| 8640 | 8711 | const ip = &zcu.intern_pool; |
| 8641 | | switch (ip.indexToKey(val.toIntern())) { |
| 8642 | | .int_type, |
| 8643 | | .ptr_type, |
| 8644 | | .array_type, |
| 8645 | | .vector_type, |
| 8646 | | .opt_type, |
| 8647 | | .anyframe_type, |
| 8648 | | .error_union_type, |
| 8649 | | .simple_type, |
| 8650 | | .struct_type, |
| 8651 | | .union_type, |
| 8652 | | .opaque_type, |
| 8653 | | .spirv_type, |
| 8654 | | .enum_type, |
| 8655 | | .func_type, |
| 8656 | | .error_set_type, |
| 8657 | | .inferred_error_set_type, |
| 8658 | | => unreachable, // types, not values |
| 8659 | | |
| 8660 | | .undef => return cg.fail("assembly input with 'c' constraint cannot be undefined", .{}), |
| 8661 | | |
| 8662 | | .int => try ass.value_map.put(gpa, in.name, .{ .constant = @intCast(val.toUnsignedInt(zcu)) }), |
| 8663 | | .enum_literal => |str| try ass.value_map.put(gpa, in.name, .{ .string = str.toSlice(ip) }), |
| 8664 | | |
| 8665 | | else => unreachable, // TODO |
| 8712 | const target = cg.pt.zcu.getTarget(); |
| 8713 | switch (input_ty.zigTypeTag(zcu)) { |
| 8714 | .int => { |
| 8715 | const bits: u64 = switch (input_ty.intInfo(zcu).signedness) { |
| 8716 | .unsigned => val.toUnsignedInt(zcu), |
| 8717 | .signed => @bitCast(val.toSignedInt(zcu)), |
| 8718 | }; |
| 8719 | try ass.value_map.put(gpa, in.name, .{ .constant = bits }); |
| 8720 | }, |
| 8721 | .float => { |
| 8722 | const bits: u64 = switch (input_ty.floatBits(target)) { |
| 8723 | 16 => @as(u16, @bitCast(val.toFloat(f16, zcu))), |
| 8724 | 32 => @as(u32, @bitCast(val.toFloat(f32, zcu))), |
| 8725 | 64 => @bitCast(val.toFloat(f64, zcu)), |
| 8726 | else => unreachable, // Sema rejects unsupported float widths. |
| 8727 | }; |
| 8728 | try ass.value_map.put(gpa, in.name, .{ .constant = bits }); |
| 8729 | }, |
| 8730 | .vector => { |
| 8731 | const child_ty = input_ty.childType(zcu); |
| 8732 | const child_kind = child_ty.zigTypeTag(zcu); |
| 8733 | const child_bit_width: u16 = switch (child_kind) { |
| 8734 | .bool => 0, |
| 8735 | .int => @intCast(child_ty.intInfo(zcu).bits), |
| 8736 | .float => child_ty.floatBits(target), |
| 8737 | else => unreachable, // Sema rejects unsupported vector element types. |
| 8738 | }; |
| 8739 | const vec_len: usize = @intCast(input_ty.vectorLen(zcu)); |
| 8740 | const values = try gpa.alloc(u64, vec_len); |
| 8741 | errdefer gpa.free(values); |
| 8742 | for (values, 0..) |*out, i| { |
| 8743 | const elem: Value = try val.elemValue(cg.pt, i); |
| 8744 | out.* = switch (child_kind) { |
| 8745 | .bool => @intFromBool(elem.toBool()), |
| 8746 | .int => switch (child_ty.intInfo(zcu).signedness) { |
| 8747 | .unsigned => elem.toUnsignedInt(zcu), |
| 8748 | .signed => @bitCast(elem.toSignedInt(zcu)), |
| 8749 | }, |
| 8750 | .float => switch (child_bit_width) { |
| 8751 | 16 => @as(u16, @bitCast(elem.toFloat(f16, zcu))), |
| 8752 | 32 => @as(u32, @bitCast(elem.toFloat(f32, zcu))), |
| 8753 | 64 => @bitCast(elem.toFloat(f64, zcu)), |
| 8754 | else => unreachable, |
| 8755 | }, |
| 8756 | else => unreachable, |
| 8757 | }; |
| 8758 | } |
| 8759 | const child_ty_id = try cg.resolveType(child_ty, .direct); |
| 8760 | try ass.value_map.put(gpa, in.name, .{ .constant_composite = .{ |
| 8761 | .child = child_ty_id, |
| 8762 | .child_kind = child_kind, |
| 8763 | .child_bit_width = child_bit_width, |
| 8764 | .values = values, |
| 8765 | } }); |
| 8766 | }, |
| 8767 | .@"enum" => switch (ip.indexToKey(val.toIntern())) { |
| 8768 | .enum_literal => |str| try ass.value_map.put(gpa, in.name, .{ .string = str.toSlice(ip) }), |
| 8769 | else => unreachable, |
| 8770 | }, |
| 8771 | else => unreachable, // Sema rejects unsupported types. |
| 8666 | 8772 | } |
| 8667 | 8773 | } else if (std.mem.eql(u8, in.constraint, "t")) { |
| 8668 | 8774 | // type |
| ... | ... | @@ -8729,7 +8835,7 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 8729 | 8835 | .just_declared, .unresolved_forward_reference => unreachable, |
| 8730 | 8836 | .ty => return cg.fail("cannot return spir-v type as value from assembly", .{}), |
| 8731 | 8837 | .value => |ref| return ref, |
| 8732 | | .constant, .string => return cg.fail("cannot return constant from assembly", .{}), |
| 8838 | .constant, .constant_composite, .string => return cg.fail("cannot return constant from assembly", .{}), |
| 8733 | 8839 | } |
| 8734 | 8840 | // TODO: Multiple results |
| 8735 | 8841 | // TODO: Check that the output type from assembly is the same as the type actually expected by Zig. |
| ... | ... | @@ -8749,8 +8855,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 8749 | 8855 | const callee_ty = cg.typeOf(air_call.callee); |
| 8750 | 8856 | const zig_fn_ty = switch (callee_ty.zigTypeTag(zcu)) { |
| 8751 | 8857 | .@"fn" => callee_ty, |
| 8752 | | .pointer => return cg.fail("cannot call function pointers", .{}), |
| 8753 | | else => unreachable, |
| 8858 | else => unreachable, // rejected by Sema for SPIR-V |
| 8754 | 8859 | }; |
| 8755 | 8860 | const fn_info = zcu.typeToFunc(zig_fn_ty).?; |
| 8756 | 8861 | const return_type = fn_info.return_type; |