authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-07-08 10:31:16+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-07-10 11:39:54+03:30
log332c73ccd2246af417afaa42597055c9ba6255c1
tree03a89089e04301768ea3ccc111b4d20c654fdb58
parentf02d21c8c888b07ead4034562beb1872faee11d6

spirv: cache composite integer limbs and use 64bit ints when possible


1 files changed, 210 insertions(+), 149 deletions(-)

src/codegen/spirv/CodeGen.zig+210-149
...@@ -37,6 +37,10 @@ prologue: Section = .{},...@@ -37,6 +37,10 @@ prologue: Section = .{},
37body: Section = .{},37body: Section = .{},
38args: std.ArrayList(Id) = .empty,38args: std.ArrayList(Id) = .empty,
39next_arg_index: u32 = 0,39next_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`.
43composite_limbs: std.AutoHashMapUnmanaged(Id, []const Id) = .empty,
40block_stack: std.ArrayList(*Block) = .empty,44block_stack: std.ArrayList(*Block) = .empty,
41block_label: Id = .none,45block_label: Id = .none,
42/// Whether the current block has been terminated by a terminator46/// Whether the current block has been terminated by a terminator
...@@ -49,7 +53,18 @@ tracked_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty,...@@ -49,7 +53,18 @@ tracked_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty,
49loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, LoopSwitch) = .empty,53loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, LoopSwitch) = .empty,
50id_scratch: std.ArrayList(Id) = .empty,54id_scratch: std.ArrayList(Id) = .empty,
5155
52const big_int_bits = @bitSizeOf(u32);56fn bigIntBits(cg: *const CodeGen) u16 {
57 const target = cg.zcu.getTarget();
58 return if (target.cpu.has(.spirv, .int64)) 64 else 32;
59}
60
61fn limbType(cg: *const CodeGen) Type {
62 return if (cg.bigIntBits() == 64) .u64 else .u32;
63}
64
65fn limbTypeId(cg: *CodeGen) !Id {
66 return cg.resolveType(cg.limbType(), .direct);
67}
5368
54/// Data can be lowered into in two basic representations: indirect, which is when69/// Data can be lowered into in two basic representations: indirect, which is when
55/// a type is stored in memory, and direct, which is how a type is stored when its70/// a type is stored in memory, and direct, which is how a type is stored when its
...@@ -163,6 +178,7 @@ pub fn deinit(cg: *CodeGen) void {...@@ -163,6 +178,7 @@ pub fn deinit(cg: *CodeGen) void {
163 cg.block_stack.deinit(gpa);178 cg.block_stack.deinit(gpa);
164 cg.block_results.deinit(gpa);179 cg.block_results.deinit(gpa);
165 cg.args.deinit(gpa);180 cg.args.deinit(gpa);
181 cg.composite_limbs.deinit(gpa);
166 cg.tracked_allocas.deinit(gpa);182 cg.tracked_allocas.deinit(gpa);
167 cg.inst_results.deinit(gpa);183 cg.inst_results.deinit(gpa);
168 cg.loop_switches.deinit(gpa);184 cg.loop_switches.deinit(gpa);
...@@ -478,7 +494,7 @@ pub fn backingIntBits(cg: *const CodeGen, bits: u16) struct { u16, bool } {...@@ -478,7 +494,7 @@ pub fn backingIntBits(cg: *const CodeGen, bits: u16) struct { u16, bool } {
478 if (bits <= int.bits and int.enabled) return .{ int.bits, false };494 if (bits <= int.bits and int.enabled) return .{ int.bits, false };
479 }495 }
480496
481 return .{ std.mem.alignForward(u16, bits, big_int_bits), true };497 return .{ std.mem.alignForward(u16, bits, cg.bigIntBits()), true };
482}498}
483499
484pub fn intType(cg: *CodeGen, signedness: std.lang.Signedness, bits: u16) !Id {500pub fn intType(cg: *CodeGen, signedness: std.lang.Signedness, bits: u16) !Id {
...@@ -492,14 +508,16 @@ pub fn intType(cg: *CodeGen, signedness: std.lang.Signedness, bits: u16) !Id {...@@ -492,14 +508,16 @@ pub fn intType(cg: *CodeGen, signedness: std.lang.Signedness, bits: u16) !Id {
492 };508 };
493 const backing_bits, const big_int = cg.backingIntBits(bits);509 const backing_bits, const big_int = cg.backingIntBits(bits);
494 if (big_int) {510 if (big_int) {
495 const u32_ty = try cg.intType(.unsigned, 32);511 const limb_bits = cg.bigIntBits();
512 const limb_ty = try cg.intType(.unsigned, limb_bits);
513 const len_ty = try cg.intType(.unsigned, 32);
496 const len_id = cg.allocId();514 const len_id = cg.allocId();
497 try cg.sections.globals.emit(cg.gpa, .OpConstant, .{515 try cg.sections.globals.emit(cg.gpa, .OpConstant, .{
498 .id_result_type = u32_ty,516 .id_result_type = len_ty,
499 .id_result = len_id,517 .id_result = len_id,
500 .value = .{ .uint32 = backing_bits / big_int_bits },518 .value = .{ .uint32 = backing_bits / limb_bits },
501 });519 });
502 return cg.arrayType(len_id, u32_ty);520 return cg.arrayType(len_id, limb_ty);
503 }521 }
504522
505 const result_id = cg.allocId();523 const result_id = cg.allocId();
...@@ -1443,7 +1461,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {...@@ -1443,7 +1461,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
1443 .signed => @bitCast(@as(i64, @intCast(value))),1461 .signed => @bitCast(@as(i64, @intCast(value))),
1444 .unsigned => @as(u64, @intCast(value)),1462 .unsigned => @as(u64, @intCast(value)),
1445 };1463 };
1446 const n_limbs = backing_bits / big_int_bits;1464 const n_limbs = backing_bits / cg.bigIntBits();
1447 const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0;1465 const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0;
1448 const scratch_top = cg.id_scratch.items.len;1466 const scratch_top = cg.id_scratch.items.len;
1449 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);1467 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
...@@ -1616,21 +1634,33 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1616,21 +1634,33 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1616 const int_info = ty.intInfo(zcu);1634 const int_info = ty.intInfo(zcu);
1617 const backing_bits, const is_big_int = cg.backingIntBits(int_info.bits);1635 const backing_bits, const is_big_int = cg.backingIntBits(int_info.bits);
1618 if (is_big_int) {1636 if (is_big_int) {
1619 const n_limbs = backing_bits / big_int_bits;1637 const limb_bits = cg.bigIntBits();
1638 const n_limbs = backing_bits / limb_bits;
1620 const big_result_ty_id = try cg.resolveType(ty, .indirect);1639 const big_result_ty_id = try cg.resolveType(ty, .indirect);
1621 var bigint_space: Value.BigIntSpace = undefined;1640 var bigint_space: Value.BigIntSpace = undefined;
1622 const bigint = val.toBigInt(&bigint_space, zcu);1641 const bigint = val.toBigInt(&bigint_space, zcu);
1623 const limb_values = try gpa.alloc(u32, n_limbs);1642 const limb_bytes = try gpa.alloc(u8, backing_bits / 8);
1624 defer gpa.free(limb_values);1643 defer gpa.free(limb_bytes);
1625 bigint.writeTwosComplement(std.mem.sliceAsBytes(limb_values), .little);1644 bigint.writeTwosComplement(limb_bytes, .little);
1626 if (builtin.cpu.arch.endian() == .big) {
1627 for (limb_values) |*limb| limb.* = @byteSwap(limb.*);
1628 }
1629 const scratch_top = cg.id_scratch.items.len;1645 const scratch_top = cg.id_scratch.items.len;
1630 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);1646 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
1631 const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);1647 const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
1632 for (constituents, 0..) |*c, i| {1648 switch (limb_bits) {
1633 c.* = try cg.constInt(.u32, limb_values[i]);1649 32 => {
1650 const limbs_u32: []u32 = @ptrCast(@alignCast(limb_bytes));
1651 for (constituents, limbs_u32) |*c, v| {
1652 const host_v = if (builtin.cpu.arch.endian() == .big) @byteSwap(v) else v;
1653 c.* = try cg.constInt(.u32, host_v);
1654 }
1655 },
1656 64 => {
1657 const limbs_u64: []u64 = @ptrCast(@alignCast(limb_bytes));
1658 for (constituents, limbs_u64) |*c, v| {
1659 const host_v = if (builtin.cpu.arch.endian() == .big) @byteSwap(v) else v;
1660 c.* = try cg.constInt(.u64, host_v);
1661 }
1662 },
1663 else => unreachable,
1634 }1664 }
1635 break :cache try cg.constructComposite(big_result_ty_id, constituents);1665 break :cache try cg.constructComposite(big_result_ty_id, constituents);
1636 }1666 }
...@@ -2766,20 +2796,28 @@ const CompositeInt = struct {...@@ -2766,20 +2796,28 @@ const CompositeInt = struct {
2766 info: ArithmeticTypeInfo,2796 info: ArithmeticTypeInfo,
27672797
2768 fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt {2798 fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt {
2769 const n_limbs: u16 = info.backing_bits / big_int_bits;2799 const n_limbs: u16 = info.backing_bits / cg.bigIntBits();
2770 const gpa = cg.gpa;2800 const gpa = cg.gpa;
2771 const u32_ty_id = try cg.resolveType(.u32, .direct);2801 if (cg.composite_limbs.get(composite_id)) |cached| {
2802 assert(cached.len == n_limbs);
2803 const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
2804 @memcpy(limbs, cached);
2805 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };
2806 }
2807 const limb_ty_id = try cg.limbTypeId();
2772 const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);2808 const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
2773 for (limbs, 0..) |*limb, i| {2809 for (limbs, 0..) |*limb, i| {
2774 const result_id = cg.allocId();2810 const result_id = cg.allocId();
2775 try cg.body.emit(gpa, .OpCompositeExtract, .{2811 try cg.body.emit(gpa, .OpCompositeExtract, .{
2776 .id_result_type = u32_ty_id,2812 .id_result_type = limb_ty_id,
2777 .id_result = result_id,2813 .id_result = result_id,
2778 .composite = composite_id,2814 .composite = composite_id,
2779 .indexes = &.{@as(u32, @intCast(i))},2815 .indexes = &.{@as(u32, @intCast(i))},
2780 });2816 });
2781 limb.* = result_id;2817 limb.* = result_id;
2782 }2818 }
2819 const cached = try cg.arena.dupe(Id, limbs);
2820 try cg.composite_limbs.put(gpa, composite_id, cached);
2783 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };2821 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };
2784 }2822 }
27852823
...@@ -2793,9 +2831,9 @@ const CompositeInt = struct {...@@ -2793,9 +2831,9 @@ const CompositeInt = struct {
2793 }2831 }
27942832
2795 fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt {2833 fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt {
2796 const n_limbs: u16 = info.backing_bits / big_int_bits;2834 const n_limbs: u16 = info.backing_bits / cg.bigIntBits();
2797 const limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, n_limbs);2835 const limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, n_limbs);
2798 const zero_id = try cg.constInt(.u32, @as(u32, 0));2836 const zero_id = try cg.constInt(cg.limbType(), @as(u64, 0));
2799 for (limbs) |*limb| limb.* = zero_id;2837 for (limbs) |*limb| limb.* = zero_id;
2800 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };2838 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };
2801 }2839 }
...@@ -2808,10 +2846,10 @@ const CompositeInt = struct {...@@ -2808,10 +2846,10 @@ const CompositeInt = struct {
2808 fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id {2846 fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id {
2809 const cg = ci.cg;2847 const cg = ci.cg;
2810 const gpa = cg.gpa;2848 const gpa = cg.gpa;
2811 const u32_ty_id = try cg.resolveType(.u32, .direct);2849 const limb_ty_id = try cg.limbTypeId();
2812 const result_id = cg.allocId();2850 const result_id = cg.allocId();
2813 try cg.body.emitRaw(gpa, opcode, 4);2851 try cg.body.emitRaw(gpa, opcode, 4);
2814 cg.body.writeOperand(Id, u32_ty_id);2852 cg.body.writeOperand(Id, limb_ty_id);
2815 cg.body.writeOperand(Id, result_id);2853 cg.body.writeOperand(Id, result_id);
2816 cg.body.writeOperand(Id, lhs);2854 cg.body.writeOperand(Id, lhs);
2817 cg.body.writeOperand(Id, rhs);2855 cg.body.writeOperand(Id, rhs);
...@@ -2821,10 +2859,10 @@ const CompositeInt = struct {...@@ -2821,10 +2859,10 @@ const CompositeInt = struct {
2821 fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id {2859 fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id {
2822 const cg = ci.cg;2860 const cg = ci.cg;
2823 const gpa = cg.gpa;2861 const gpa = cg.gpa;
2824 const u32_ty_id = try cg.resolveType(.u32, .direct);2862 const limb_ty_id = try cg.limbTypeId();
2825 const result_id = cg.allocId();2863 const result_id = cg.allocId();
2826 try cg.body.emitRaw(gpa, opcode, 3);2864 try cg.body.emitRaw(gpa, opcode, 3);
2827 cg.body.writeOperand(Id, u32_ty_id);2865 cg.body.writeOperand(Id, limb_ty_id);
2828 cg.body.writeOperand(Id, result_id);2866 cg.body.writeOperand(Id, result_id);
2829 cg.body.writeOperand(Id, operand);2867 cg.body.writeOperand(Id, operand);
2830 return result_id;2868 return result_id;
...@@ -2916,16 +2954,17 @@ const CompositeInt = struct {...@@ -2916,16 +2954,17 @@ const CompositeInt = struct {
2916 var cmp_l = l;2954 var cmp_l = l;
2917 var cmp_r = r;2955 var cmp_r = r;
2918 if (use_signed) {2956 if (use_signed) {
2919 const i32_ty_id = try cg.resolveType(.i32, .direct);2957 const signed_limb_ty: Type = if (cg.bigIntBits() == 64) .i64 else .i32;
2958 const signed_limb_ty_id = try cg.resolveType(signed_limb_ty, .direct);
2920 const sl = cg.allocId();2959 const sl = cg.allocId();
2921 try cg.body.emit(gpa, .OpBitcast, .{2960 try cg.body.emit(gpa, .OpBitcast, .{
2922 .id_result_type = i32_ty_id,2961 .id_result_type = signed_limb_ty_id,
2923 .id_result = sl,2962 .id_result = sl,
2924 .operand = l,2963 .operand = l,
2925 });2964 });
2926 const sr = cg.allocId();2965 const sr = cg.allocId();
2927 try cg.body.emit(gpa, .OpBitcast, .{2966 try cg.body.emit(gpa, .OpBitcast, .{
2928 .id_result_type = i32_ty_id,2967 .id_result_type = signed_limb_ty_id,
2929 .id_result = sr,2968 .id_result = sr,
2930 .operand = r,2969 .operand = r,
2931 });2970 });
...@@ -2969,16 +3008,17 @@ const CompositeInt = struct {...@@ -2969,16 +3008,17 @@ const CompositeInt = struct {
2969 const comp = zcu.comp;3008 const comp = zcu.comp;
2970 const io = comp.io;3009 const io = comp.io;
29713010
2972 const u32_zig = try pt.intType(.unsigned, 32);3011 const limb_bits = cg.bigIntBits();
2973 const u32_ty_id = try cg.resolveType(.u32, .direct);3012 const limb_zig = try pt.intType(.unsigned, limb_bits);
3013 const limb_ty_id = try cg.limbTypeId();
2974 const carry_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{3014 const carry_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{
2975 .types = &.{ u32_zig.toIntern(), u32_zig.toIntern() },3015 .types = &.{ limb_zig.toIntern(), limb_zig.toIntern() },
2976 .values = &.{ .none, .none },3016 .values = &.{ .none, .none },
2977 }));3017 }));
2978 const carry_struct_ty_id = try cg.resolveType(carry_struct_ty, .direct);3018 const carry_struct_ty_id = try cg.resolveType(carry_struct_ty, .direct);
29793019
2980 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);3020 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2981 var carry_id = try cg.constInt(.u32, @as(u32, 0));3021 var carry_id = try cg.constInt(cg.limbType(), @as(u64, 0));
29823022
2983 const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow;3023 const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow;
29843024
...@@ -2992,14 +3032,14 @@ const CompositeInt = struct {...@@ -2992,14 +3032,14 @@ const CompositeInt = struct {
29923032
2993 const sum1 = cg.allocId();3033 const sum1 = cg.allocId();
2994 try cg.body.emit(gpa, .OpCompositeExtract, .{3034 try cg.body.emit(gpa, .OpCompositeExtract, .{
2995 .id_result_type = u32_ty_id,3035 .id_result_type = limb_ty_id,
2996 .id_result = sum1,3036 .id_result = sum1,
2997 .composite = op1,3037 .composite = op1,
2998 .indexes = &.{0},3038 .indexes = &.{0},
2999 });3039 });
3000 const carry1 = cg.allocId();3040 const carry1 = cg.allocId();
3001 try cg.body.emit(gpa, .OpCompositeExtract, .{3041 try cg.body.emit(gpa, .OpCompositeExtract, .{
3002 .id_result_type = u32_ty_id,3042 .id_result_type = limb_ty_id,
3003 .id_result = carry1,3043 .id_result = carry1,
3004 .composite = op1,3044 .composite = op1,
3005 .indexes = &.{1},3045 .indexes = &.{1},
...@@ -3014,14 +3054,14 @@ const CompositeInt = struct {...@@ -3014,14 +3054,14 @@ const CompositeInt = struct {
30143054
3015 result_limbs[i] = cg.allocId();3055 result_limbs[i] = cg.allocId();
3016 try cg.body.emit(gpa, .OpCompositeExtract, .{3056 try cg.body.emit(gpa, .OpCompositeExtract, .{
3017 .id_result_type = u32_ty_id,3057 .id_result_type = limb_ty_id,
3018 .id_result = result_limbs[i],3058 .id_result = result_limbs[i],
3019 .composite = op2,3059 .composite = op2,
3020 .indexes = &.{0},3060 .indexes = &.{0},
3021 });3061 });
3022 const carry2 = cg.allocId();3062 const carry2 = cg.allocId();
3023 try cg.body.emit(gpa, .OpCompositeExtract, .{3063 try cg.body.emit(gpa, .OpCompositeExtract, .{
3024 .id_result_type = u32_ty_id,3064 .id_result_type = limb_ty_id,
3025 .id_result = carry2,3065 .id_result = carry2,
3026 .composite = op2,3066 .composite = op2,
3027 .indexes = &.{1},3067 .indexes = &.{1},
...@@ -3036,16 +3076,18 @@ const CompositeInt = struct {...@@ -3036,16 +3076,18 @@ const CompositeInt = struct {
3036 fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt {3076 fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt {
3037 const cg = ci.cg;3077 const cg = ci.cg;
3038 const gpa = cg.gpa;3078 const gpa = cg.gpa;
3039 const u32_ty_id = try cg.resolveType(.u32, .direct);3079 const limb_bits = cg.bigIntBits();
3080 const limb_ty = cg.limbType();
3081 const limb_ty_id = try cg.limbTypeId();
3040 const bool_ty_id = try cg.resolveType(.bool, .direct);3082 const bool_ty_id = try cg.resolveType(.bool, .direct);
3041 const zero_id = try cg.constInt(.u32, @as(u32, 0));3083 const zero_id = try cg.constInt(limb_ty, @as(u64, 0));
3042 const five_id = try cg.constInt(.u32, @as(u32, 5));3084 const log2_bits_id = try cg.constInt(limb_ty, @as(u64, std.math.log2_int(u16, limb_bits)));
3043 const thirty_one_id = try cg.constInt(.u32, @as(u32, 31));3085 const bits_minus_1_id = try cg.constInt(limb_ty, @as(u64, limb_bits - 1));
3044 const thirty_two_id = try cg.constInt(.u32, @as(u32, 32));3086 const bits_id = try cg.constInt(limb_ty, @as(u64, limb_bits));
30453087
3046 const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, five_id);3088 const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, log2_bits_id);
3047 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);3089 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, bits_minus_1_id);
3048 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);3090 const comp_frac = try ci.limbBinOp(.OpISub, bits_id, frac);
3049 const frac_is_zero = blk: {3091 const frac_is_zero = blk: {
3050 const r = cg.allocId();3092 const r = cg.allocId();
3051 try cg.body.emit(gpa, .OpIEqual, .{3093 try cg.body.emit(gpa, .OpIEqual, .{
...@@ -3060,12 +3102,12 @@ const CompositeInt = struct {...@@ -3060,12 +3102,12 @@ const CompositeInt = struct {
3060 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);3102 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
30613103
3062 for (0..ci.n_limbs) |i| {3104 for (0..ci.n_limbs) |i| {
3063 const i_id = try cg.constInt(.u32, @as(u32, @intCast(i)));3105 const i_id = try cg.constInt(limb_ty, @as(u64, @intCast(i)));
3064 var main_val = zero_id;3106 var main_val = zero_id;
3065 var carry_val = zero_id;3107 var carry_val = zero_id;
30663108
3067 for (0..ci.n_limbs) |j| {3109 for (0..ci.n_limbs) |j| {
3068 const j_id = try cg.constInt(.u32, @as(u32, @intCast(j)));3110 const j_id = try cg.constInt(limb_ty, @as(u64, @intCast(j)));
3069 const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole);3111 const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole);
30703112
3071 const is_main = blk: {3113 const is_main = blk: {
...@@ -3082,7 +3124,7 @@ const CompositeInt = struct {...@@ -3082,7 +3124,7 @@ const CompositeInt = struct {
3082 main_val = blk: {3124 main_val = blk: {
3083 const r = cg.allocId();3125 const r = cg.allocId();
3084 try cg.body.emit(gpa, .OpSelect, .{3126 try cg.body.emit(gpa, .OpSelect, .{
3085 .id_result_type = u32_ty_id,3127 .id_result_type = limb_ty_id,
3086 .id_result = r,3128 .id_result = r,
3087 .condition = is_main,3129 .condition = is_main,
3088 .object_1 = shifted,3130 .object_1 = shifted,
...@@ -3091,7 +3133,7 @@ const CompositeInt = struct {...@@ -3091,7 +3133,7 @@ const CompositeInt = struct {
3091 break :blk r;3133 break :blk r;
3092 };3134 };
30933135
3094 const one_id = try cg.constInt(.u32, @as(u32, 1));3136 const one_id = try cg.constInt(limb_ty, @as(u64, 1));
3095 const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id);3137 const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id);
3096 const is_carry = blk: {3138 const is_carry = blk: {
3097 const r = cg.allocId();3139 const r = cg.allocId();
...@@ -3107,7 +3149,7 @@ const CompositeInt = struct {...@@ -3107,7 +3149,7 @@ const CompositeInt = struct {
3107 const guarded_carry = blk: {3149 const guarded_carry = blk: {
3108 const r = cg.allocId();3150 const r = cg.allocId();
3109 try cg.body.emit(gpa, .OpSelect, .{3151 try cg.body.emit(gpa, .OpSelect, .{
3110 .id_result_type = u32_ty_id,3152 .id_result_type = limb_ty_id,
3111 .id_result = r,3153 .id_result = r,
3112 .condition = frac_is_zero,3154 .condition = frac_is_zero,
3113 .object_1 = zero_id,3155 .object_1 = zero_id,
...@@ -3118,7 +3160,7 @@ const CompositeInt = struct {...@@ -3118,7 +3160,7 @@ const CompositeInt = struct {
3118 carry_val = blk: {3160 carry_val = blk: {
3119 const r = cg.allocId();3161 const r = cg.allocId();
3120 try cg.body.emit(gpa, .OpSelect, .{3162 try cg.body.emit(gpa, .OpSelect, .{
3121 .id_result_type = u32_ty_id,3163 .id_result_type = limb_ty_id,
3122 .id_result = r,3164 .id_result = r,
3123 .condition = is_carry,3165 .condition = is_carry,
3124 .object_1 = guarded_carry,3166 .object_1 = guarded_carry,
...@@ -3137,16 +3179,18 @@ const CompositeInt = struct {...@@ -3137,16 +3179,18 @@ const CompositeInt = struct {
3137 fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt {3179 fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt {
3138 const cg = ci.cg;3180 const cg = ci.cg;
3139 const gpa = cg.gpa;3181 const gpa = cg.gpa;
3140 const u32_ty_id = try cg.resolveType(.u32, .direct);3182 const limb_bits = cg.bigIntBits();
3183 const limb_ty = cg.limbType();
3184 const limb_ty_id = try cg.limbTypeId();
3141 const bool_ty_id = try cg.resolveType(.bool, .direct);3185 const bool_ty_id = try cg.resolveType(.bool, .direct);
3142 const zero_id = try cg.constInt(.u32, @as(u32, 0));3186 const zero_id = try cg.constInt(limb_ty, @as(u64, 0));
3143 const five_id = try cg.constInt(.u32, @as(u32, 5));3187 const log2_bits_id = try cg.constInt(limb_ty, @as(u64, std.math.log2_int(u16, limb_bits)));
3144 const thirty_one_id = try cg.constInt(.u32, @as(u32, 31));3188 const bits_minus_1_id = try cg.constInt(limb_ty, @as(u64, limb_bits - 1));
3145 const thirty_two_id = try cg.constInt(.u32, @as(u32, 32));3189 const bits_id = try cg.constInt(limb_ty, @as(u64, limb_bits));
31463190
3147 const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, five_id);3191 const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, log2_bits_id);
3148 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);3192 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, bits_minus_1_id);
3149 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);3193 const comp_frac = try ci.limbBinOp(.OpISub, bits_id, frac);
3150 const frac_is_zero = blk: {3194 const frac_is_zero = blk: {
3151 const r = cg.allocId();3195 const r = cg.allocId();
3152 try cg.body.emit(gpa, .OpIEqual, .{3196 try cg.body.emit(gpa, .OpIEqual, .{
...@@ -3159,24 +3203,25 @@ const CompositeInt = struct {...@@ -3159,24 +3203,25 @@ const CompositeInt = struct {
3159 };3203 };
31603204
3161 const fill_id = if (is_arithmetic) blk: {3205 const fill_id = if (is_arithmetic) blk: {
3162 const i32_ty_id = try cg.resolveType(.i32, .direct);3206 const signed_limb_ty: Type = if (limb_bits == 64) .i64 else .i32;
3207 const signed_limb_ty_id = try cg.resolveType(signed_limb_ty, .direct);
3163 const msb_signed = cg.allocId();3208 const msb_signed = cg.allocId();
3164 try cg.body.emit(gpa, .OpBitcast, .{3209 try cg.body.emit(gpa, .OpBitcast, .{
3165 .id_result_type = i32_ty_id,3210 .id_result_type = signed_limb_ty_id,
3166 .id_result = msb_signed,3211 .id_result = msb_signed,
3167 .operand = ci.limbs[ci.n_limbs - 1],3212 .operand = ci.limbs[ci.n_limbs - 1],
3168 });3213 });
3169 const shift31 = try cg.constInt(.i32, @as(i32, 31));3214 const shift_amt = try cg.constInt(signed_limb_ty, @as(u64, limb_bits - 1));
3170 const sign_ext = cg.allocId();3215 const sign_ext = cg.allocId();
3171 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{3216 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
3172 .id_result_type = i32_ty_id,3217 .id_result_type = signed_limb_ty_id,
3173 .id_result = sign_ext,3218 .id_result = sign_ext,
3174 .base = msb_signed,3219 .base = msb_signed,
3175 .shift = shift31,3220 .shift = shift_amt,
3176 });3221 });
3177 const back = cg.allocId();3222 const back = cg.allocId();
3178 try cg.body.emit(gpa, .OpBitcast, .{3223 try cg.body.emit(gpa, .OpBitcast, .{
3179 .id_result_type = u32_ty_id,3224 .id_result_type = limb_ty_id,
3180 .id_result = back,3225 .id_result = back,
3181 .operand = sign_ext,3226 .operand = sign_ext,
3182 });3227 });
...@@ -3189,7 +3234,7 @@ const CompositeInt = struct {...@@ -3189,7 +3234,7 @@ const CompositeInt = struct {
3189 const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac);3234 const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac);
3190 const guarded = cg.allocId();3235 const guarded = cg.allocId();
3191 try cg.body.emit(gpa, .OpSelect, .{3236 try cg.body.emit(gpa, .OpSelect, .{
3192 .id_result_type = u32_ty_id,3237 .id_result_type = limb_ty_id,
3193 .id_result = guarded,3238 .id_result = guarded,
3194 .condition = frac_is_zero,3239 .condition = frac_is_zero,
3195 .object_1 = zero_id,3240 .object_1 = zero_id,
...@@ -3199,12 +3244,12 @@ const CompositeInt = struct {...@@ -3199,12 +3244,12 @@ const CompositeInt = struct {
3199 } else zero_id;3244 } else zero_id;
32003245
3201 for (0..ci.n_limbs) |i| {3246 for (0..ci.n_limbs) |i| {
3202 const i_id = try cg.constInt(.u32, @as(u32, @intCast(i)));3247 const i_id = try cg.constInt(limb_ty, @as(u64, @intCast(i)));
3203 var main_val = fill_id;3248 var main_val = fill_id;
3204 var carry_val = arith_carry_init;3249 var carry_val = arith_carry_init;
32053250
3206 for (0..ci.n_limbs) |j| {3251 for (0..ci.n_limbs) |j| {
3207 const j_id = try cg.constInt(.u32, @as(u32, @intCast(j)));3252 const j_id = try cg.constInt(limb_ty, @as(u64, @intCast(j)));
3208 const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole);3253 const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole);
3209 const is_main = blk: {3254 const is_main = blk: {
3210 const r = cg.allocId();3255 const r = cg.allocId();
...@@ -3220,7 +3265,7 @@ const CompositeInt = struct {...@@ -3220,7 +3265,7 @@ const CompositeInt = struct {
3220 main_val = blk: {3265 main_val = blk: {
3221 const r = cg.allocId();3266 const r = cg.allocId();
3222 try cg.body.emit(gpa, .OpSelect, .{3267 try cg.body.emit(gpa, .OpSelect, .{
3223 .id_result_type = u32_ty_id,3268 .id_result_type = limb_ty_id,
3224 .id_result = r,3269 .id_result = r,
3225 .condition = is_main,3270 .condition = is_main,
3226 .object_1 = shifted,3271 .object_1 = shifted,
...@@ -3229,7 +3274,7 @@ const CompositeInt = struct {...@@ -3229,7 +3274,7 @@ const CompositeInt = struct {
3229 break :blk r;3274 break :blk r;
3230 };3275 };
32313276
3232 const one_id = try cg.constInt(.u32, @as(u32, 1));3277 const one_id = try cg.constInt(limb_ty, @as(u64, 1));
3233 const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id);3278 const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id);
3234 const is_carry = blk: {3279 const is_carry = blk: {
3235 const r = cg.allocId();3280 const r = cg.allocId();
...@@ -3245,7 +3290,7 @@ const CompositeInt = struct {...@@ -3245,7 +3290,7 @@ const CompositeInt = struct {
3245 const guarded_carry = blk: {3290 const guarded_carry = blk: {
3246 const r = cg.allocId();3291 const r = cg.allocId();
3247 try cg.body.emit(gpa, .OpSelect, .{3292 try cg.body.emit(gpa, .OpSelect, .{
3248 .id_result_type = u32_ty_id,3293 .id_result_type = limb_ty_id,
3249 .id_result = r,3294 .id_result = r,
3250 .condition = frac_is_zero,3295 .condition = frac_is_zero,
3251 .object_1 = zero_id,3296 .object_1 = zero_id,
...@@ -3256,7 +3301,7 @@ const CompositeInt = struct {...@@ -3256,7 +3301,7 @@ const CompositeInt = struct {
3256 carry_val = blk: {3301 carry_val = blk: {
3257 const r = cg.allocId();3302 const r = cg.allocId();
3258 try cg.body.emit(gpa, .OpSelect, .{3303 try cg.body.emit(gpa, .OpSelect, .{
3259 .id_result_type = u32_ty_id,3304 .id_result_type = limb_ty_id,
3260 .id_result = r,3305 .id_result = r,
3261 .condition = is_carry,3306 .condition = is_carry,
3262 .object_1 = guarded_carry,3307 .object_1 = guarded_carry,
...@@ -3284,17 +3329,18 @@ const CompositeInt = struct {...@@ -3284,17 +3329,18 @@ const CompositeInt = struct {
32843329
3285 const n: usize = ci.n_limbs;3330 const n: usize = ci.n_limbs;
3286 const total: usize = if (wide) 2 * n else n;3331 const total: usize = if (wide) 2 * n else n;
3287 const u32_zig = try pt.intType(.unsigned, 32);3332 const limb_bits = cg.bigIntBits();
3288 const u32_ty_id = try cg.resolveType(.u32, .direct);3333 const limb_zig = try pt.intType(.unsigned, limb_bits);
3334 const limb_ty_id = try cg.limbTypeId();
32893335
3290 const pair_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{3336 const pair_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{
3291 .types = &.{ u32_zig.toIntern(), u32_zig.toIntern() },3337 .types = &.{ limb_zig.toIntern(), limb_zig.toIntern() },
3292 .values = &.{ .none, .none },3338 .values = &.{ .none, .none },
3293 }));3339 }));
3294 const pair_struct_ty_id = try cg.resolveType(pair_struct_ty, .direct);3340 const pair_struct_ty_id = try cg.resolveType(pair_struct_ty, .direct);
32953341
3296 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, total);3342 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, total);
3297 const zero_id = try cg.constInt(.u32, @as(u32, 0));3343 const zero_id = try cg.constInt(cg.limbType(), @as(u64, 0));
3298 for (result_limbs) |*r| r.* = zero_id;3344 for (result_limbs) |*r| r.* = zero_id;
32993345
3300 for (0..n) |i| {3346 for (0..n) |i| {
...@@ -3309,7 +3355,7 @@ const CompositeInt = struct {...@@ -3309,7 +3355,7 @@ const CompositeInt = struct {
3309 .opencl => {3355 .opencl => {
3310 lo = cg.allocId();3356 lo = cg.allocId();
3311 try cg.body.emit(gpa, .OpIMul, .{3357 try cg.body.emit(gpa, .OpIMul, .{
3312 .id_result_type = u32_ty_id,3358 .id_result_type = limb_ty_id,
3313 .id_result = lo,3359 .id_result = lo,
3314 .operand_1 = ci.limbs[i],3360 .operand_1 = ci.limbs[i],
3315 .operand_2 = other.limbs[j],3361 .operand_2 = other.limbs[j],
...@@ -3318,7 +3364,7 @@ const CompositeInt = struct {...@@ -3318,7 +3364,7 @@ const CompositeInt = struct {
3318 const set = try cg.importExtendedSet();3364 const set = try cg.importExtendedSet();
3319 hi = cg.allocId();3365 hi = cg.allocId();
3320 try cg.body.emit(gpa, .OpExtInst, .{3366 try cg.body.emit(gpa, .OpExtInst, .{
3321 .id_result_type = u32_ty_id,3367 .id_result_type = limb_ty_id,
3322 .id_result = hi,3368 .id_result = hi,
3323 .set = set,3369 .set = set,
3324 .instruction = .{ .inst = @intFromEnum(spec.OpenClOpcode.u_mul_hi) },3370 .instruction = .{ .inst = @intFromEnum(spec.OpenClOpcode.u_mul_hi) },
...@@ -3336,14 +3382,14 @@ const CompositeInt = struct {...@@ -3336,14 +3382,14 @@ const CompositeInt = struct {
33363382
3337 lo = cg.allocId();3383 lo = cg.allocId();
3338 try cg.body.emit(gpa, .OpCompositeExtract, .{3384 try cg.body.emit(gpa, .OpCompositeExtract, .{
3339 .id_result_type = u32_ty_id,3385 .id_result_type = limb_ty_id,
3340 .id_result = lo,3386 .id_result = lo,
3341 .composite = mul_result,3387 .composite = mul_result,
3342 .indexes = &.{0},3388 .indexes = &.{0},
3343 });3389 });
3344 hi = cg.allocId();3390 hi = cg.allocId();
3345 try cg.body.emit(gpa, .OpCompositeExtract, .{3391 try cg.body.emit(gpa, .OpCompositeExtract, .{
3346 .id_result_type = u32_ty_id,3392 .id_result_type = limb_ty_id,
3347 .id_result = hi,3393 .id_result = hi,
3348 .composite = mul_result,3394 .composite = mul_result,
3349 .indexes = &.{1},3395 .indexes = &.{1},
...@@ -3361,14 +3407,14 @@ const CompositeInt = struct {...@@ -3361,14 +3407,14 @@ const CompositeInt = struct {
33613407
3362 const sum1 = cg.allocId();3408 const sum1 = cg.allocId();
3363 try cg.body.emit(gpa, .OpCompositeExtract, .{3409 try cg.body.emit(gpa, .OpCompositeExtract, .{
3364 .id_result_type = u32_ty_id,3410 .id_result_type = limb_ty_id,
3365 .id_result = sum1,3411 .id_result = sum1,
3366 .composite = add1,3412 .composite = add1,
3367 .indexes = &.{0},3413 .indexes = &.{0},
3368 });3414 });
3369 const c1 = cg.allocId();3415 const c1 = cg.allocId();
3370 try cg.body.emit(gpa, .OpCompositeExtract, .{3416 try cg.body.emit(gpa, .OpCompositeExtract, .{
3371 .id_result_type = u32_ty_id,3417 .id_result_type = limb_ty_id,
3372 .id_result = c1,3418 .id_result = c1,
3373 .composite = add1,3419 .composite = add1,
3374 .indexes = &.{1},3420 .indexes = &.{1},
...@@ -3384,14 +3430,14 @@ const CompositeInt = struct {...@@ -3384,14 +3430,14 @@ const CompositeInt = struct {
33843430
3385 result_limbs[k] = cg.allocId();3431 result_limbs[k] = cg.allocId();
3386 try cg.body.emit(gpa, .OpCompositeExtract, .{3432 try cg.body.emit(gpa, .OpCompositeExtract, .{
3387 .id_result_type = u32_ty_id,3433 .id_result_type = limb_ty_id,
3388 .id_result = result_limbs[k],3434 .id_result = result_limbs[k],
3389 .composite = add2,3435 .composite = add2,
3390 .indexes = &.{0},3436 .indexes = &.{0},
3391 });3437 });
3392 const c2 = cg.allocId();3438 const c2 = cg.allocId();
3393 try cg.body.emit(gpa, .OpCompositeExtract, .{3439 try cg.body.emit(gpa, .OpCompositeExtract, .{
3394 .id_result_type = u32_ty_id,3440 .id_result_type = limb_ty_id,
3395 .id_result = c2,3441 .id_result = c2,
3396 .composite = add2,3442 .composite = add2,
3397 .indexes = &.{1},3443 .indexes = &.{1},
...@@ -3412,7 +3458,8 @@ const CompositeInt = struct {...@@ -3412,7 +3458,8 @@ const CompositeInt = struct {
3412 if (ci.info.bits == ci.info.backing_bits) return ci;3458 if (ci.info.bits == ci.info.backing_bits) return ci;
3413 const cg = ci.cg;3459 const cg = ci.cg;
3414 const gpa = cg.gpa;3460 const gpa = cg.gpa;
3415 const top_bits: u16 = ci.info.bits % big_int_bits;3461 const limb_bits = cg.bigIntBits();
3462 const top_bits: u16 = ci.info.bits % limb_bits;
3416 assert(top_bits != 0);3463 assert(top_bits != 0);
34173464
3418 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);3465 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
...@@ -3421,41 +3468,43 @@ const CompositeInt = struct {...@@ -3421,41 +3468,43 @@ const CompositeInt = struct {
3421 }3468 }
34223469
3423 const top_limb = ci.limbs[ci.n_limbs - 1];3470 const top_limb = ci.limbs[ci.n_limbs - 1];
3471 const limb_ty = cg.limbType();
3472 const limb_signed_ty: Type = if (limb_bits == 64) .i64 else .i32;
3424 switch (ci.info.signedness) {3473 switch (ci.info.signedness) {
3425 .unsigned => {3474 .unsigned => {
3426 const mask_val: u32 = (@as(u32, 1) << @as(u5, @intCast(top_bits))) - 1;3475 const mask_val: u64 = (@as(u64, 1) << @as(u6, @intCast(top_bits))) - 1;
3427 const mask_id = try cg.constInt(.u32, mask_val);3476 const mask_id = try cg.constInt(limb_ty, mask_val);
3428 result_limbs[ci.n_limbs - 1] = try ci.limbBinOp(.OpBitwiseAnd, top_limb, mask_id);3477 result_limbs[ci.n_limbs - 1] = try ci.limbBinOp(.OpBitwiseAnd, top_limb, mask_id);
3429 },3478 },
3430 .signed => {3479 .signed => {
3431 const u32_ty_id = try cg.resolveType(.u32, .direct);3480 const limb_ty_id = try cg.limbTypeId();
3432 const i32_ty_id = try cg.resolveType(.i32, .direct);3481 const signed_ty_id = try cg.resolveType(limb_signed_ty, .direct);
3433 const shift_amt: u32 = 32 - top_bits;3482 const shift_amt: u32 = @intCast(limb_bits - top_bits);
3434 const shift_id = try cg.constInt(.u32, shift_amt);3483 const shift_id = try cg.constInt(limb_ty, shift_amt);
34353484
3436 const as_signed = cg.allocId();3485 const as_signed = cg.allocId();
3437 try cg.body.emit(gpa, .OpBitcast, .{3486 try cg.body.emit(gpa, .OpBitcast, .{
3438 .id_result_type = i32_ty_id,3487 .id_result_type = signed_ty_id,
3439 .id_result = as_signed,3488 .id_result = as_signed,
3440 .operand = top_limb,3489 .operand = top_limb,
3441 });3490 });
3442 const shifted_left = cg.allocId();3491 const shifted_left = cg.allocId();
3443 try cg.body.emit(gpa, .OpShiftLeftLogical, .{3492 try cg.body.emit(gpa, .OpShiftLeftLogical, .{
3444 .id_result_type = i32_ty_id,3493 .id_result_type = signed_ty_id,
3445 .id_result = shifted_left,3494 .id_result = shifted_left,
3446 .base = as_signed,3495 .base = as_signed,
3447 .shift = shift_id,3496 .shift = shift_id,
3448 });3497 });
3449 const shifted_right = cg.allocId();3498 const shifted_right = cg.allocId();
3450 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{3499 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
3451 .id_result_type = i32_ty_id,3500 .id_result_type = signed_ty_id,
3452 .id_result = shifted_right,3501 .id_result = shifted_right,
3453 .base = shifted_left,3502 .base = shifted_left,
3454 .shift = shift_id,3503 .shift = shift_id,
3455 });3504 });
3456 const back = cg.allocId();3505 const back = cg.allocId();
3457 try cg.body.emit(gpa, .OpBitcast, .{3506 try cg.body.emit(gpa, .OpBitcast, .{
3458 .id_result_type = u32_ty_id,3507 .id_result_type = limb_ty_id,
3459 .id_result = back,3508 .id_result = back,
3460 .operand = shifted_right,3509 .operand = shifted_right,
3461 });3510 });
...@@ -4552,13 +4601,14 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode...@@ -4552,13 +4601,14 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode
4552 switch (info.class) {4601 switch (info.class) {
4553 .composite_integer => {4602 .composite_integer => {
4554 const shift_info = cg.arithmeticTypeInfo(shift.ty);4603 const shift_info = cg.arithmeticTypeInfo(shift.ty);
4604 const limb_ty = cg.limbType();
4555 const shift_amt_id = switch (shift_info.class) {4605 const shift_amt_id = switch (shift_info.class) {
4556 .composite_integer => blk: {4606 .composite_integer => blk: {
4557 const shift_id = try shift.materialize(cg);4607 const shift_id = try shift.materialize(cg);
4558 const u32_ty_id = try cg.resolveType(.u32, .direct);4608 const limb_ty_id = try cg.limbTypeId();
4559 const result_id = cg.allocId();4609 const result_id = cg.allocId();
4560 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{4610 try cg.body.emit(cg.gpa, .OpCompositeExtract, .{
4561 .id_result_type = u32_ty_id,4611 .id_result_type = limb_ty_id,
4562 .id_result = result_id,4612 .id_result = result_id,
4563 .composite = shift_id,4613 .composite = shift_id,
4564 .indexes = &.{@as(u32, 0)},4614 .indexes = &.{@as(u32, 0)},
...@@ -4566,7 +4616,7 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode...@@ -4566,7 +4616,7 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode
4566 break :blk result_id;4616 break :blk result_id;
4567 },4617 },
4568 else => blk: {4618 else => blk: {
4569 const converted = try cg.buildConvert(.u32, shift);4619 const converted = try cg.buildConvert(limb_ty, shift);
4570 break :blk try converted.materialize(cg);4620 break :blk try converted.materialize(cg);
4571 },4621 },
4572 };4622 };
...@@ -4887,12 +4937,12 @@ fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4887,12 +4937,12 @@ fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4887 const is_neg = try ci.cmp(ci_z, .lt);4937 const is_neg = try ci.cmp(ci_z, .lt);
4888 const ci_neg = try ci_z.addSub(ci, false);4938 const ci_neg = try ci_z.addSub(ci, false);
4889 const result_info = cg.arithmeticTypeInfo(result_ty);4939 const result_info = cg.arithmeticTypeInfo(result_ty);
4890 const u32_ty_id = try cg.resolveType(.u32, .direct);4940 const limb_ty_id = try cg.limbTypeId();
4891 const result_limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, ci.n_limbs);4941 const result_limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, ci.n_limbs);
4892 for (0..ci.n_limbs) |i| {4942 for (0..ci.n_limbs) |i| {
4893 result_limbs[i] = cg.allocId();4943 result_limbs[i] = cg.allocId();
4894 try cg.body.emit(cg.gpa, .OpSelect, .{4944 try cg.body.emit(cg.gpa, .OpSelect, .{
4895 .id_result_type = u32_ty_id,4945 .id_result_type = limb_ty_id,
4896 .id_result = result_limbs[i],4946 .id_result = result_limbs[i],
4897 .condition = is_neg,4947 .condition = is_neg,
4898 .object_1 = ci_neg.limbs[i],4948 .object_1 = ci_neg.limbs[i],
...@@ -5066,12 +5116,13 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5066,12 +5116,13 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5066 const high_limbs = wide_limbs[ci_lhs2.n_limbs..];5116 const high_limbs = wide_limbs[ci_lhs2.n_limbs..];
50675117
5068 const bool_ty_id = try cg.resolveType(.bool, .direct);5118 const bool_ty_id = try cg.resolveType(.bool, .direct);
5069 const u32_ty_id = try cg.resolveType(.u32, .direct);5119 const limb_ty_id = try cg.limbTypeId();
5070 const n: usize = info.backing_bits / big_int_bits;5120 const limb_ty = cg.limbType();
5121 const n: usize = info.backing_bits / cg.bigIntBits();
50715122
5072 const ov_bool = switch (info.signedness) {5123 const ov_bool = switch (info.signedness) {
5073 .unsigned => blk: {5124 .unsigned => blk: {
5074 const zero_id = try cg.constInt(.u32, @as(u32, 0));5125 const zero_id = try cg.constInt(limb_ty, @as(u64, 0));
5075 var any_nonzero = cg.allocId();5126 var any_nonzero = cg.allocId();
5076 try cg.body.emit(gpa, .OpINotEqual, .{5127 try cg.body.emit(gpa, .OpINotEqual, .{
5077 .id_result_type = bool_ty_id,5128 .id_result_type = bool_ty_id,
...@@ -5104,32 +5155,33 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5104,32 +5155,33 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5104 .signed => blk: {5155 .signed => blk: {
5105 const ci_res = try CompositeInt.init(cg, result_val_id, info);5156 const ci_res = try CompositeInt.init(cg, result_val_id, info);
5106 const top_limb = ci_res.limbs[n - 1];5157 const top_limb = ci_res.limbs[n - 1];
5107 const i32_ty_id = try cg.resolveType(.i32, .direct);5158 const signed_limb_ty: Type = if (cg.bigIntBits() == 64) .i64 else .i32;
5159 const signed_limb_ty_id = try cg.resolveType(signed_limb_ty, .direct);
51085160
5109 const top_bits: u16 = if (info.bits % big_int_bits == 0)5161 const top_bits: u16 = if (info.bits % cg.bigIntBits() == 0)
5110 big_int_bits5162 cg.bigIntBits()
5111 else5163 else
5112 info.bits % big_int_bits;5164 info.bits % cg.bigIntBits();
51135165
5114 const shift_amt: u32 = top_bits - 1;5166 const shift_amt: u64 = top_bits - 1;
5115 const shift_id = try cg.constInt(.u32, shift_amt);5167 const shift_id = try cg.constInt(limb_ty, shift_amt);
51165168
5117 const as_signed = cg.allocId();5169 const as_signed = cg.allocId();
5118 try cg.body.emit(gpa, .OpBitcast, .{5170 try cg.body.emit(gpa, .OpBitcast, .{
5119 .id_result_type = i32_ty_id,5171 .id_result_type = signed_limb_ty_id,
5120 .id_result = as_signed,5172 .id_result = as_signed,
5121 .operand = top_limb,5173 .operand = top_limb,
5122 });5174 });
5123 const sign_ext = cg.allocId();5175 const sign_ext = cg.allocId();
5124 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{5176 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
5125 .id_result_type = i32_ty_id,5177 .id_result_type = signed_limb_ty_id,
5126 .id_result = sign_ext,5178 .id_result = sign_ext,
5127 .base = as_signed,5179 .base = as_signed,
5128 .shift = shift_id,5180 .shift = shift_id,
5129 });5181 });
5130 const expected = cg.allocId();5182 const expected = cg.allocId();
5131 try cg.body.emit(gpa, .OpBitcast, .{5183 try cg.body.emit(gpa, .OpBitcast, .{
5132 .id_result_type = u32_ty_id,5184 .id_result_type = limb_ty_id,
5133 .id_result = expected,5185 .id_result = expected,
5134 .operand = sign_ext,5186 .operand = sign_ext,
5135 });5187 });
...@@ -5162,25 +5214,25 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5162,25 +5214,25 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5162 }5214 }
51635215
5164 if (info.bits != info.backing_bits) {5216 if (info.bits != info.backing_bits) {
5165 const top_bits_s: u16 = info.bits % big_int_bits;5217 const top_bits_s: u16 = info.bits % cg.bigIntBits();
5166 const s_shift_id = try cg.constInt(.u32, top_bits_s - 1);5218 const s_shift_id = try cg.constInt(limb_ty, @as(u64, top_bits_s - 1));
51675219
5168 const top_as_signed = cg.allocId();5220 const top_as_signed = cg.allocId();
5169 try cg.body.emit(gpa, .OpBitcast, .{5221 try cg.body.emit(gpa, .OpBitcast, .{
5170 .id_result_type = i32_ty_id,5222 .id_result_type = signed_limb_ty_id,
5171 .id_result = top_as_signed,5223 .id_result = top_as_signed,
5172 .operand = top_limb,5224 .operand = top_limb,
5173 });5225 });
5174 const top_sign_ext = cg.allocId();5226 const top_sign_ext = cg.allocId();
5175 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{5227 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
5176 .id_result_type = i32_ty_id,5228 .id_result_type = signed_limb_ty_id,
5177 .id_result = top_sign_ext,5229 .id_result = top_sign_ext,
5178 .base = top_as_signed,5230 .base = top_as_signed,
5179 .shift = s_shift_id,5231 .shift = s_shift_id,
5180 });5232 });
5181 const top_expected = cg.allocId();5233 const top_expected = cg.allocId();
5182 try cg.body.emit(gpa, .OpBitcast, .{5234 try cg.body.emit(gpa, .OpBitcast, .{
5183 .id_result_type = u32_ty_id,5235 .id_result_type = limb_ty_id,
5184 .id_result = top_expected,5236 .id_result = top_expected,
5185 .operand = top_sign_ext,5237 .operand = top_sign_ext,
5186 });5238 });
...@@ -6117,15 +6169,17 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6117,15 +6169,17 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
61176169
6118 if (src_composite and dst_composite) {6170 if (src_composite and dst_composite) {
6119 const src_id = try src.materialize(cg);6171 const src_id = try src.materialize(cg);
6120 const src_n: u16 = src_info.backing_bits / big_int_bits;6172 const limb_bits = cg.bigIntBits();
6121 const dst_n: u16 = dst_info.backing_bits / big_int_bits;6173 const limb_ty = cg.limbType();
6174 const limb_ty_id = try cg.limbTypeId();
6175 const src_n: u16 = src_info.backing_bits / limb_bits;
6176 const dst_n: u16 = dst_info.backing_bits / limb_bits;
6122 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);6177 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
6123 const min_n = @min(src_n, dst_n);6178 const min_n = @min(src_n, dst_n);
6124 const u32_ty_id = try cg.resolveType(.u32, .direct);
6125 for (0..min_n) |i| {6179 for (0..min_n) |i| {
6126 result_limbs[i] = cg.allocId();6180 result_limbs[i] = cg.allocId();
6127 try cg.body.emit(gpa, .OpCompositeExtract, .{6181 try cg.body.emit(gpa, .OpCompositeExtract, .{
6128 .id_result_type = u32_ty_id,6182 .id_result_type = limb_ty_id,
6129 .id_result = result_limbs[i],6183 .id_result = result_limbs[i],
6130 .composite = src_id,6184 .composite = src_id,
6131 .indexes = &.{@as(u32, @intCast(i))},6185 .indexes = &.{@as(u32, @intCast(i))},
...@@ -6133,30 +6187,31 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6133,30 +6187,31 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6133 }6187 }
6134 if (dst_n > src_n) {6188 if (dst_n > src_n) {
6135 const fill = if (src_info.signedness == .signed) blk: {6189 const fill = if (src_info.signedness == .signed) blk: {
6136 const i32_ty_id = try cg.resolveType(.i32, .direct);6190 const signed_limb_ty: Type = if (limb_bits == 64) .i64 else .i32;
6191 const signed_limb_ty_id = try cg.resolveType(signed_limb_ty, .direct);
6137 const msb = result_limbs[src_n - 1];6192 const msb = result_limbs[src_n - 1];
6138 const msb_signed = cg.allocId();6193 const msb_signed = cg.allocId();
6139 try cg.body.emit(gpa, .OpBitcast, .{6194 try cg.body.emit(gpa, .OpBitcast, .{
6140 .id_result_type = i32_ty_id,6195 .id_result_type = signed_limb_ty_id,
6141 .id_result = msb_signed,6196 .id_result = msb_signed,
6142 .operand = msb,6197 .operand = msb,
6143 });6198 });
6144 const shift31 = try cg.constInt(.i32, @as(i32, 31));6199 const shift_amt = try cg.constInt(signed_limb_ty, @as(u64, limb_bits - 1));
6145 const sign_ext = cg.allocId();6200 const sign_ext = cg.allocId();
6146 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{6201 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
6147 .id_result_type = i32_ty_id,6202 .id_result_type = signed_limb_ty_id,
6148 .id_result = sign_ext,6203 .id_result = sign_ext,
6149 .base = msb_signed,6204 .base = msb_signed,
6150 .shift = shift31,6205 .shift = shift_amt,
6151 });6206 });
6152 const back = cg.allocId();6207 const back = cg.allocId();
6153 try cg.body.emit(gpa, .OpBitcast, .{6208 try cg.body.emit(gpa, .OpBitcast, .{
6154 .id_result_type = u32_ty_id,6209 .id_result_type = limb_ty_id,
6155 .id_result = back,6210 .id_result = back,
6156 .operand = sign_ext,6211 .operand = sign_ext,
6157 });6212 });
6158 break :blk back;6213 break :blk back;
6159 } else try cg.constInt(.u32, @as(u32, 0));6214 } else try cg.constInt(limb_ty, @as(u64, 0));
6160 for (min_n..dst_n) |i| {6215 for (min_n..dst_n) |i| {
6161 result_limbs[i] = fill;6216 result_limbs[i] = fill;
6162 }6217 }
...@@ -6166,16 +6221,18 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6166,16 +6221,18 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6166 return try normalized.materialize(dst_ty);6221 return try normalized.materialize(dst_ty);
6167 } else if (src_composite and !dst_composite) {6222 } else if (src_composite and !dst_composite) {
6168 const src_id = try src.materialize(cg);6223 const src_id = try src.materialize(cg);
6169 const u32_ty_id = try cg.resolveType(.u32, .direct);6224 const limb_bits = cg.bigIntBits();
6170 if (dst_info.backing_bits <= 32) {6225 const limb_ty = cg.limbType();
6226 const limb_ty_id = try cg.limbTypeId();
6227 if (dst_info.backing_bits <= limb_bits) {
6171 const limb0 = cg.allocId();6228 const limb0 = cg.allocId();
6172 try cg.body.emit(gpa, .OpCompositeExtract, .{6229 try cg.body.emit(gpa, .OpCompositeExtract, .{
6173 .id_result_type = u32_ty_id,6230 .id_result_type = limb_ty_id,
6174 .id_result = limb0,6231 .id_result = limb0,
6175 .composite = src_id,6232 .composite = src_id,
6176 .indexes = &.{@as(u32, 0)},6233 .indexes = &.{@as(u32, 0)},
6177 });6234 });
6178 const tmp: Temporary = .init(.u32, limb0);6235 const tmp: Temporary = .init(limb_ty, limb0);
6179 const converted = try cg.buildConvert(dst_ty, tmp);6236 const converted = try cg.buildConvert(dst_ty, tmp);
6180 const result = if (dst_info.bits < src_info.bits)6237 const result = if (dst_info.bits < src_info.bits)
6181 try cg.normalize(converted, dst_info)6238 try cg.normalize(converted, dst_info)
...@@ -6183,16 +6240,17 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6183,16 +6240,17 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6183 converted;6240 converted;
6184 return try result.materialize(cg);6241 return try result.materialize(cg);
6185 } else {6242 } else {
6243 assert(limb_bits == 32); // dst > 64 while limbs are 64 shouldn't happen — dst fits in one 64-bit limb.
6186 const limb0 = cg.allocId();6244 const limb0 = cg.allocId();
6187 try cg.body.emit(gpa, .OpCompositeExtract, .{6245 try cg.body.emit(gpa, .OpCompositeExtract, .{
6188 .id_result_type = u32_ty_id,6246 .id_result_type = limb_ty_id,
6189 .id_result = limb0,6247 .id_result = limb0,
6190 .composite = src_id,6248 .composite = src_id,
6191 .indexes = &.{@as(u32, 0)},6249 .indexes = &.{@as(u32, 0)},
6192 });6250 });
6193 const limb1 = cg.allocId();6251 const limb1 = cg.allocId();
6194 try cg.body.emit(gpa, .OpCompositeExtract, .{6252 try cg.body.emit(gpa, .OpCompositeExtract, .{
6195 .id_result_type = u32_ty_id,6253 .id_result_type = limb_ty_id,
6196 .id_result = limb1,6254 .id_result = limb1,
6197 .composite = src_id,6255 .composite = src_id,
6198 .indexes = &.{@as(u32, 1)},6256 .indexes = &.{@as(u32, 1)},
...@@ -6234,19 +6292,21 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6234,19 +6292,21 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6234 return try result.materialize(cg);6292 return try result.materialize(cg);
6235 }6293 }
6236 } else {6294 } else {
6237 const dst_n: u16 = dst_info.backing_bits / big_int_bits;6295 const limb_bits = cg.bigIntBits();
6296 const limb_ty = cg.limbType();
6297 const limb_ty_id = try cg.limbTypeId();
6298 const dst_n: u16 = dst_info.backing_bits / limb_bits;
6238 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);6299 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
6239 const u32_ty_id = try cg.resolveType(.u32, .direct);
62406300
6241 if (src_info.backing_bits <= 32) {6301 if (src_info.backing_bits <= limb_bits) {
6242 const converted = try cg.buildConvert(.u32, src);6302 const converted = try cg.buildConvert(limb_ty, src);
6243 result_limbs[0] = try converted.materialize(cg);6303 result_limbs[0] = try converted.materialize(cg);
6244 } else {6304 } else {
6245 const src_as_u64 = try cg.buildConvert(.u64, src);6305 const src_as_u64 = try cg.buildConvert(.u64, src);
6246 const src_id = try src_as_u64.materialize(cg);6306 const src_id = try src_as_u64.materialize(cg);
6247 result_limbs[0] = cg.allocId();6307 result_limbs[0] = cg.allocId();
6248 try cg.body.emit(gpa, .OpUConvert, .{6308 try cg.body.emit(gpa, .OpUConvert, .{
6249 .id_result_type = u32_ty_id,6309 .id_result_type = limb_ty_id,
6250 .id_result = result_limbs[0],6310 .id_result = result_limbs[0],
6251 .unsigned_value = src_id,6311 .unsigned_value = src_id,
6252 });6312 });
...@@ -6261,38 +6321,39 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6261,38 +6321,39 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6261 });6321 });
6262 result_limbs[1] = cg.allocId();6322 result_limbs[1] = cg.allocId();
6263 try cg.body.emit(gpa, .OpUConvert, .{6323 try cg.body.emit(gpa, .OpUConvert, .{
6264 .id_result_type = u32_ty_id,6324 .id_result_type = limb_ty_id,
6265 .id_result = result_limbs[1],6325 .id_result = result_limbs[1],
6266 .unsigned_value = hi,6326 .unsigned_value = hi,
6267 });6327 });
6268 }6328 }
6269 // Sign/zero-extend remaining limbs.6329 // Sign/zero-extend remaining limbs.
6270 const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2;6330 const fill_start: u16 = if (src_info.backing_bits <= limb_bits) 1 else 2;
6271 const fill = if (src_info.signedness == .signed) blk: {6331 const fill = if (src_info.signedness == .signed) blk: {
6272 const i32_ty_id = try cg.resolveType(.i32, .direct);6332 const signed_limb_ty: Type = if (limb_bits == 64) .i64 else .i32;
6333 const signed_limb_ty_id = try cg.resolveType(signed_limb_ty, .direct);
6273 const msb = result_limbs[fill_start - 1];6334 const msb = result_limbs[fill_start - 1];
6274 const msb_signed = cg.allocId();6335 const msb_signed = cg.allocId();
6275 try cg.body.emit(gpa, .OpBitcast, .{6336 try cg.body.emit(gpa, .OpBitcast, .{
6276 .id_result_type = i32_ty_id,6337 .id_result_type = signed_limb_ty_id,
6277 .id_result = msb_signed,6338 .id_result = msb_signed,
6278 .operand = msb,6339 .operand = msb,
6279 });6340 });
6280 const shift31 = try cg.constInt(.i32, @as(i32, 31));6341 const shift_amt = try cg.constInt(signed_limb_ty, @as(u64, limb_bits - 1));
6281 const sign_ext = cg.allocId();6342 const sign_ext = cg.allocId();
6282 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{6343 try cg.body.emit(gpa, .OpShiftRightArithmetic, .{
6283 .id_result_type = i32_ty_id,6344 .id_result_type = signed_limb_ty_id,
6284 .id_result = sign_ext,6345 .id_result = sign_ext,
6285 .base = msb_signed,6346 .base = msb_signed,
6286 .shift = shift31,6347 .shift = shift_amt,
6287 });6348 });
6288 const back = cg.allocId();6349 const back = cg.allocId();
6289 try cg.body.emit(gpa, .OpBitcast, .{6350 try cg.body.emit(gpa, .OpBitcast, .{
6290 .id_result_type = u32_ty_id,6351 .id_result_type = limb_ty_id,
6291 .id_result = back,6352 .id_result = back,
6292 .operand = sign_ext,6353 .operand = sign_ext,
6293 });6354 });
6294 break :blk back;6355 break :blk back;
6295 } else try cg.constInt(.u32, @as(u32, 0));6356 } else try cg.constInt(limb_ty, @as(u64, 0));
6296 for (fill_start..dst_n) |i| {6357 for (fill_start..dst_n) |i| {
6297 result_limbs[i] = fill;6358 result_limbs[i] = fill;
6298 }6359 }