| ... | ... | @@ -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,18 @@ 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 bigIntBits(cg: *const CodeGen) u16 { |
| 57 | const target = cg.zcu.getTarget(); |
| 58 | return if (target.cpu.has(.spirv, .int64)) 64 else 32; |
| 59 | } |
| 60 | |
| 61 | fn limbType(cg: *const CodeGen) Type { |
| 62 | return if (cg.bigIntBits() == 64) .u64 else .u32; |
| 63 | } |
| 64 | |
| 65 | fn limbTypeId(cg: *CodeGen) !Id { |
| 66 | return cg.resolveType(cg.limbType(), .direct); |
| 67 | } |
| 53 | 68 | |
| 54 | 69 | /// Data can be lowered into in two basic representations: indirect, which is when |
| 55 | 70 | /// 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 | 178 | cg.block_stack.deinit(gpa); |
| 164 | 179 | cg.block_results.deinit(gpa); |
| 165 | 180 | cg.args.deinit(gpa); |
| 181 | cg.composite_limbs.deinit(gpa); |
| 166 | 182 | cg.tracked_allocas.deinit(gpa); |
| 167 | 183 | cg.inst_results.deinit(gpa); |
| 168 | 184 | cg.loop_switches.deinit(gpa); |
| ... | ... | @@ -478,7 +494,7 @@ pub fn backingIntBits(cg: *const CodeGen, bits: u16) struct { u16, bool } { |
| 478 | 494 | if (bits <= int.bits and int.enabled) return .{ int.bits, false }; |
| 479 | 495 | } |
| 480 | 496 | |
| 481 | | return .{ std.mem.alignForward(u16, bits, big_int_bits), true }; |
| 497 | return .{ std.mem.alignForward(u16, bits, cg.bigIntBits()), true }; |
| 482 | 498 | } |
| 483 | 499 | |
| 484 | 500 | 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 | 509 | const backing_bits, const big_int = cg.backingIntBits(bits); |
| 494 | 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 | 514 | const len_id = cg.allocId(); |
| 497 | 515 | try cg.sections.globals.emit(cg.gpa, .OpConstant, .{ |
| 498 | | .id_result_type = u32_ty, |
| 516 | .id_result_type = len_ty, |
| 499 | 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 | } |
| 504 | 522 | |
| 505 | 523 | const result_id = cg.allocId(); |
| ... | ... | @@ -1443,7 +1461,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { |
| 1443 | 1461 | .signed => @bitCast(@as(i64, @intCast(value))), |
| 1444 | 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 | 1465 | const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0; |
| 1448 | 1466 | const scratch_top = cg.id_scratch.items.len; |
| 1449 | 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 | 1634 | const int_info = ty.intInfo(zcu); |
| 1617 | 1635 | const backing_bits, const is_big_int = cg.backingIntBits(int_info.bits); |
| 1618 | 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 | 1639 | const big_result_ty_id = try cg.resolveType(ty, .indirect); |
| 1621 | 1640 | var bigint_space: Value.BigIntSpace = undefined; |
| 1622 | 1641 | 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 | | } |
| 1642 | const limb_bytes = try gpa.alloc(u8, backing_bits / 8); |
| 1643 | defer gpa.free(limb_bytes); |
| 1644 | bigint.writeTwosComplement(limb_bytes, .little); |
| 1629 | 1645 | const scratch_top = cg.id_scratch.items.len; |
| 1630 | 1646 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| 1631 | 1647 | 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]); |
| 1648 | switch (limb_bits) { |
| 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 | 1665 | break :cache try cg.constructComposite(big_result_ty_id, constituents); |
| 1636 | 1666 | } |
| ... | ... | @@ -2766,20 +2796,28 @@ const CompositeInt = struct { |
| 2766 | 2796 | info: ArithmeticTypeInfo, |
| 2767 | 2797 | |
| 2768 | 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 | 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 | 2808 | const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs); |
| 2773 | 2809 | for (limbs, 0..) |*limb, i| { |
| 2774 | 2810 | const result_id = cg.allocId(); |
| 2775 | 2811 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 2776 | | .id_result_type = u32_ty_id, |
| 2812 | .id_result_type = limb_ty_id, |
| 2777 | 2813 | .id_result = result_id, |
| 2778 | 2814 | .composite = composite_id, |
| 2779 | 2815 | .indexes = &.{@as(u32, @intCast(i))}, |
| 2780 | 2816 | }); |
| 2781 | 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 | 2821 | return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info }; |
| 2784 | 2822 | } |
| 2785 | 2823 | |
| ... | ... | @@ -2793,9 +2831,9 @@ const CompositeInt = struct { |
| 2793 | 2831 | } |
| 2794 | 2832 | |
| 2795 | 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 | 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 | 2837 | for (limbs) |*limb| limb.* = zero_id; |
| 2800 | 2838 | return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info }; |
| 2801 | 2839 | } |
| ... | ... | @@ -2808,10 +2846,10 @@ const CompositeInt = struct { |
| 2808 | 2846 | fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id { |
| 2809 | 2847 | const cg = ci.cg; |
| 2810 | 2848 | const gpa = cg.gpa; |
| 2811 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 2849 | const limb_ty_id = try cg.limbTypeId(); |
| 2812 | 2850 | const result_id = cg.allocId(); |
| 2813 | 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 | 2853 | cg.body.writeOperand(Id, result_id); |
| 2816 | 2854 | cg.body.writeOperand(Id, lhs); |
| 2817 | 2855 | cg.body.writeOperand(Id, rhs); |
| ... | ... | @@ -2821,10 +2859,10 @@ const CompositeInt = struct { |
| 2821 | 2859 | fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id { |
| 2822 | 2860 | const cg = ci.cg; |
| 2823 | 2861 | const gpa = cg.gpa; |
| 2824 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 2862 | const limb_ty_id = try cg.limbTypeId(); |
| 2825 | 2863 | const result_id = cg.allocId(); |
| 2826 | 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 | 2866 | cg.body.writeOperand(Id, result_id); |
| 2829 | 2867 | cg.body.writeOperand(Id, operand); |
| 2830 | 2868 | return result_id; |
| ... | ... | @@ -2916,16 +2954,17 @@ const CompositeInt = struct { |
| 2916 | 2954 | var cmp_l = l; |
| 2917 | 2955 | var cmp_r = r; |
| 2918 | 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 | 2959 | const sl = cg.allocId(); |
| 2921 | 2960 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 2922 | | .id_result_type = i32_ty_id, |
| 2961 | .id_result_type = signed_limb_ty_id, |
| 2923 | 2962 | .id_result = sl, |
| 2924 | 2963 | .operand = l, |
| 2925 | 2964 | }); |
| 2926 | 2965 | const sr = cg.allocId(); |
| 2927 | 2966 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 2928 | | .id_result_type = i32_ty_id, |
| 2967 | .id_result_type = signed_limb_ty_id, |
| 2929 | 2968 | .id_result = sr, |
| 2930 | 2969 | .operand = r, |
| 2931 | 2970 | }); |
| ... | ... | @@ -2969,16 +3008,17 @@ const CompositeInt = struct { |
| 2969 | 3008 | const comp = zcu.comp; |
| 2970 | 3009 | const io = comp.io; |
| 2971 | 3010 | |
| 2972 | | const u32_zig = try pt.intType(.unsigned, 32); |
| 2973 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 3011 | const limb_bits = cg.bigIntBits(); |
| 3012 | const limb_zig = try pt.intType(.unsigned, limb_bits); |
| 3013 | const limb_ty_id = try cg.limbTypeId(); |
| 2974 | 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 | 3016 | .values = &.{ .none, .none }, |
| 2977 | 3017 | })); |
| 2978 | 3018 | const carry_struct_ty_id = try cg.resolveType(carry_struct_ty, .direct); |
| 2979 | 3019 | |
| 2980 | 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)); |
| 2982 | 3022 | |
| 2983 | 3023 | const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow; |
| 2984 | 3024 | |
| ... | ... | @@ -2992,14 +3032,14 @@ const CompositeInt = struct { |
| 2992 | 3032 | |
| 2993 | 3033 | const sum1 = cg.allocId(); |
| 2994 | 3034 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 2995 | | .id_result_type = u32_ty_id, |
| 3035 | .id_result_type = limb_ty_id, |
| 2996 | 3036 | .id_result = sum1, |
| 2997 | 3037 | .composite = op1, |
| 2998 | 3038 | .indexes = &.{0}, |
| 2999 | 3039 | }); |
| 3000 | 3040 | const carry1 = cg.allocId(); |
| 3001 | 3041 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3002 | | .id_result_type = u32_ty_id, |
| 3042 | .id_result_type = limb_ty_id, |
| 3003 | 3043 | .id_result = carry1, |
| 3004 | 3044 | .composite = op1, |
| 3005 | 3045 | .indexes = &.{1}, |
| ... | ... | @@ -3014,14 +3054,14 @@ const CompositeInt = struct { |
| 3014 | 3054 | |
| 3015 | 3055 | result_limbs[i] = cg.allocId(); |
| 3016 | 3056 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3017 | | .id_result_type = u32_ty_id, |
| 3057 | .id_result_type = limb_ty_id, |
| 3018 | 3058 | .id_result = result_limbs[i], |
| 3019 | 3059 | .composite = op2, |
| 3020 | 3060 | .indexes = &.{0}, |
| 3021 | 3061 | }); |
| 3022 | 3062 | const carry2 = cg.allocId(); |
| 3023 | 3063 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3024 | | .id_result_type = u32_ty_id, |
| 3064 | .id_result_type = limb_ty_id, |
| 3025 | 3065 | .id_result = carry2, |
| 3026 | 3066 | .composite = op2, |
| 3027 | 3067 | .indexes = &.{1}, |
| ... | ... | @@ -3036,16 +3076,18 @@ const CompositeInt = struct { |
| 3036 | 3076 | fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt { |
| 3037 | 3077 | const cg = ci.cg; |
| 3038 | 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 | 3082 | 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); |
| 3083 | const zero_id = try cg.constInt(limb_ty, @as(u64, 0)); |
| 3084 | const log2_bits_id = try cg.constInt(limb_ty, @as(u64, std.math.log2_int(u16, limb_bits))); |
| 3085 | const bits_minus_1_id = try cg.constInt(limb_ty, @as(u64, limb_bits - 1)); |
| 3086 | const bits_id = try cg.constInt(limb_ty, @as(u64, limb_bits)); |
| 3087 | |
| 3088 | const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, log2_bits_id); |
| 3089 | const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, bits_minus_1_id); |
| 3090 | const comp_frac = try ci.limbBinOp(.OpISub, bits_id, frac); |
| 3049 | 3091 | const frac_is_zero = blk: { |
| 3050 | 3092 | const r = cg.allocId(); |
| 3051 | 3093 | try cg.body.emit(gpa, .OpIEqual, .{ |
| ... | ... | @@ -3060,12 +3102,12 @@ const CompositeInt = struct { |
| 3060 | 3102 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| 3061 | 3103 | |
| 3062 | 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 | 3106 | var main_val = zero_id; |
| 3065 | 3107 | var carry_val = zero_id; |
| 3066 | 3108 | |
| 3067 | 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 | 3111 | const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole); |
| 3070 | 3112 | |
| 3071 | 3113 | const is_main = blk: { |
| ... | ... | @@ -3082,7 +3124,7 @@ const CompositeInt = struct { |
| 3082 | 3124 | main_val = blk: { |
| 3083 | 3125 | const r = cg.allocId(); |
| 3084 | 3126 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3085 | | .id_result_type = u32_ty_id, |
| 3127 | .id_result_type = limb_ty_id, |
| 3086 | 3128 | .id_result = r, |
| 3087 | 3129 | .condition = is_main, |
| 3088 | 3130 | .object_1 = shifted, |
| ... | ... | @@ -3091,7 +3133,7 @@ const CompositeInt = struct { |
| 3091 | 3133 | break :blk r; |
| 3092 | 3134 | }; |
| 3093 | 3135 | |
| 3094 | | const one_id = try cg.constInt(.u32, @as(u32, 1)); |
| 3136 | const one_id = try cg.constInt(limb_ty, @as(u64, 1)); |
| 3095 | 3137 | const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id); |
| 3096 | 3138 | const is_carry = blk: { |
| 3097 | 3139 | const r = cg.allocId(); |
| ... | ... | @@ -3107,7 +3149,7 @@ const CompositeInt = struct { |
| 3107 | 3149 | const guarded_carry = blk: { |
| 3108 | 3150 | const r = cg.allocId(); |
| 3109 | 3151 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3110 | | .id_result_type = u32_ty_id, |
| 3152 | .id_result_type = limb_ty_id, |
| 3111 | 3153 | .id_result = r, |
| 3112 | 3154 | .condition = frac_is_zero, |
| 3113 | 3155 | .object_1 = zero_id, |
| ... | ... | @@ -3118,7 +3160,7 @@ const CompositeInt = struct { |
| 3118 | 3160 | carry_val = blk: { |
| 3119 | 3161 | const r = cg.allocId(); |
| 3120 | 3162 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3121 | | .id_result_type = u32_ty_id, |
| 3163 | .id_result_type = limb_ty_id, |
| 3122 | 3164 | .id_result = r, |
| 3123 | 3165 | .condition = is_carry, |
| 3124 | 3166 | .object_1 = guarded_carry, |
| ... | ... | @@ -3137,16 +3179,18 @@ const CompositeInt = struct { |
| 3137 | 3179 | fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt { |
| 3138 | 3180 | const cg = ci.cg; |
| 3139 | 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 | 3185 | 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); |
| 3186 | const zero_id = try cg.constInt(limb_ty, @as(u64, 0)); |
| 3187 | const log2_bits_id = try cg.constInt(limb_ty, @as(u64, std.math.log2_int(u16, limb_bits))); |
| 3188 | const bits_minus_1_id = try cg.constInt(limb_ty, @as(u64, limb_bits - 1)); |
| 3189 | const bits_id = try cg.constInt(limb_ty, @as(u64, limb_bits)); |
| 3190 | |
| 3191 | const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, log2_bits_id); |
| 3192 | const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, bits_minus_1_id); |
| 3193 | const comp_frac = try ci.limbBinOp(.OpISub, bits_id, frac); |
| 3150 | 3194 | const frac_is_zero = blk: { |
| 3151 | 3195 | const r = cg.allocId(); |
| 3152 | 3196 | try cg.body.emit(gpa, .OpIEqual, .{ |
| ... | ... | @@ -3159,24 +3203,25 @@ const CompositeInt = struct { |
| 3159 | 3203 | }; |
| 3160 | 3204 | |
| 3161 | 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 | 3208 | const msb_signed = cg.allocId(); |
| 3164 | 3209 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 3165 | | .id_result_type = i32_ty_id, |
| 3210 | .id_result_type = signed_limb_ty_id, |
| 3166 | 3211 | .id_result = msb_signed, |
| 3167 | 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 | 3215 | const sign_ext = cg.allocId(); |
| 3171 | 3216 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 3172 | | .id_result_type = i32_ty_id, |
| 3217 | .id_result_type = signed_limb_ty_id, |
| 3173 | 3218 | .id_result = sign_ext, |
| 3174 | 3219 | .base = msb_signed, |
| 3175 | | .shift = shift31, |
| 3220 | .shift = shift_amt, |
| 3176 | 3221 | }); |
| 3177 | 3222 | const back = cg.allocId(); |
| 3178 | 3223 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 3179 | | .id_result_type = u32_ty_id, |
| 3224 | .id_result_type = limb_ty_id, |
| 3180 | 3225 | .id_result = back, |
| 3181 | 3226 | .operand = sign_ext, |
| 3182 | 3227 | }); |
| ... | ... | @@ -3189,7 +3234,7 @@ const CompositeInt = struct { |
| 3189 | 3234 | const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac); |
| 3190 | 3235 | const guarded = cg.allocId(); |
| 3191 | 3236 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3192 | | .id_result_type = u32_ty_id, |
| 3237 | .id_result_type = limb_ty_id, |
| 3193 | 3238 | .id_result = guarded, |
| 3194 | 3239 | .condition = frac_is_zero, |
| 3195 | 3240 | .object_1 = zero_id, |
| ... | ... | @@ -3199,12 +3244,12 @@ const CompositeInt = struct { |
| 3199 | 3244 | } else zero_id; |
| 3200 | 3245 | |
| 3201 | 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 | 3248 | var main_val = fill_id; |
| 3204 | 3249 | var carry_val = arith_carry_init; |
| 3205 | 3250 | |
| 3206 | 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 | 3253 | const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole); |
| 3209 | 3254 | const is_main = blk: { |
| 3210 | 3255 | const r = cg.allocId(); |
| ... | ... | @@ -3220,7 +3265,7 @@ const CompositeInt = struct { |
| 3220 | 3265 | main_val = blk: { |
| 3221 | 3266 | const r = cg.allocId(); |
| 3222 | 3267 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3223 | | .id_result_type = u32_ty_id, |
| 3268 | .id_result_type = limb_ty_id, |
| 3224 | 3269 | .id_result = r, |
| 3225 | 3270 | .condition = is_main, |
| 3226 | 3271 | .object_1 = shifted, |
| ... | ... | @@ -3229,7 +3274,7 @@ const CompositeInt = struct { |
| 3229 | 3274 | break :blk r; |
| 3230 | 3275 | }; |
| 3231 | 3276 | |
| 3232 | | const one_id = try cg.constInt(.u32, @as(u32, 1)); |
| 3277 | const one_id = try cg.constInt(limb_ty, @as(u64, 1)); |
| 3233 | 3278 | const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id); |
| 3234 | 3279 | const is_carry = blk: { |
| 3235 | 3280 | const r = cg.allocId(); |
| ... | ... | @@ -3245,7 +3290,7 @@ const CompositeInt = struct { |
| 3245 | 3290 | const guarded_carry = blk: { |
| 3246 | 3291 | const r = cg.allocId(); |
| 3247 | 3292 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3248 | | .id_result_type = u32_ty_id, |
| 3293 | .id_result_type = limb_ty_id, |
| 3249 | 3294 | .id_result = r, |
| 3250 | 3295 | .condition = frac_is_zero, |
| 3251 | 3296 | .object_1 = zero_id, |
| ... | ... | @@ -3256,7 +3301,7 @@ const CompositeInt = struct { |
| 3256 | 3301 | carry_val = blk: { |
| 3257 | 3302 | const r = cg.allocId(); |
| 3258 | 3303 | try cg.body.emit(gpa, .OpSelect, .{ |
| 3259 | | .id_result_type = u32_ty_id, |
| 3304 | .id_result_type = limb_ty_id, |
| 3260 | 3305 | .id_result = r, |
| 3261 | 3306 | .condition = is_carry, |
| 3262 | 3307 | .object_1 = guarded_carry, |
| ... | ... | @@ -3284,17 +3329,18 @@ const CompositeInt = struct { |
| 3284 | 3329 | |
| 3285 | 3330 | const n: usize = ci.n_limbs; |
| 3286 | 3331 | 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); |
| 3332 | const limb_bits = cg.bigIntBits(); |
| 3333 | const limb_zig = try pt.intType(.unsigned, limb_bits); |
| 3334 | const limb_ty_id = try cg.limbTypeId(); |
| 3289 | 3335 | |
| 3290 | 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 | 3338 | .values = &.{ .none, .none }, |
| 3293 | 3339 | })); |
| 3294 | 3340 | const pair_struct_ty_id = try cg.resolveType(pair_struct_ty, .direct); |
| 3295 | 3341 | |
| 3296 | 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 | 3344 | for (result_limbs) |*r| r.* = zero_id; |
| 3299 | 3345 | |
| 3300 | 3346 | for (0..n) |i| { |
| ... | ... | @@ -3309,7 +3355,7 @@ const CompositeInt = struct { |
| 3309 | 3355 | .opencl => { |
| 3310 | 3356 | lo = cg.allocId(); |
| 3311 | 3357 | try cg.body.emit(gpa, .OpIMul, .{ |
| 3312 | | .id_result_type = u32_ty_id, |
| 3358 | .id_result_type = limb_ty_id, |
| 3313 | 3359 | .id_result = lo, |
| 3314 | 3360 | .operand_1 = ci.limbs[i], |
| 3315 | 3361 | .operand_2 = other.limbs[j], |
| ... | ... | @@ -3318,7 +3364,7 @@ const CompositeInt = struct { |
| 3318 | 3364 | const set = try cg.importExtendedSet(); |
| 3319 | 3365 | hi = cg.allocId(); |
| 3320 | 3366 | try cg.body.emit(gpa, .OpExtInst, .{ |
| 3321 | | .id_result_type = u32_ty_id, |
| 3367 | .id_result_type = limb_ty_id, |
| 3322 | 3368 | .id_result = hi, |
| 3323 | 3369 | .set = set, |
| 3324 | 3370 | .instruction = .{ .inst = @intFromEnum(spec.OpenClOpcode.u_mul_hi) }, |
| ... | ... | @@ -3336,14 +3382,14 @@ const CompositeInt = struct { |
| 3336 | 3382 | |
| 3337 | 3383 | lo = cg.allocId(); |
| 3338 | 3384 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3339 | | .id_result_type = u32_ty_id, |
| 3385 | .id_result_type = limb_ty_id, |
| 3340 | 3386 | .id_result = lo, |
| 3341 | 3387 | .composite = mul_result, |
| 3342 | 3388 | .indexes = &.{0}, |
| 3343 | 3389 | }); |
| 3344 | 3390 | hi = cg.allocId(); |
| 3345 | 3391 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3346 | | .id_result_type = u32_ty_id, |
| 3392 | .id_result_type = limb_ty_id, |
| 3347 | 3393 | .id_result = hi, |
| 3348 | 3394 | .composite = mul_result, |
| 3349 | 3395 | .indexes = &.{1}, |
| ... | ... | @@ -3361,14 +3407,14 @@ const CompositeInt = struct { |
| 3361 | 3407 | |
| 3362 | 3408 | const sum1 = cg.allocId(); |
| 3363 | 3409 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3364 | | .id_result_type = u32_ty_id, |
| 3410 | .id_result_type = limb_ty_id, |
| 3365 | 3411 | .id_result = sum1, |
| 3366 | 3412 | .composite = add1, |
| 3367 | 3413 | .indexes = &.{0}, |
| 3368 | 3414 | }); |
| 3369 | 3415 | const c1 = cg.allocId(); |
| 3370 | 3416 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3371 | | .id_result_type = u32_ty_id, |
| 3417 | .id_result_type = limb_ty_id, |
| 3372 | 3418 | .id_result = c1, |
| 3373 | 3419 | .composite = add1, |
| 3374 | 3420 | .indexes = &.{1}, |
| ... | ... | @@ -3384,14 +3430,14 @@ const CompositeInt = struct { |
| 3384 | 3430 | |
| 3385 | 3431 | result_limbs[k] = cg.allocId(); |
| 3386 | 3432 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3387 | | .id_result_type = u32_ty_id, |
| 3433 | .id_result_type = limb_ty_id, |
| 3388 | 3434 | .id_result = result_limbs[k], |
| 3389 | 3435 | .composite = add2, |
| 3390 | 3436 | .indexes = &.{0}, |
| 3391 | 3437 | }); |
| 3392 | 3438 | const c2 = cg.allocId(); |
| 3393 | 3439 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 3394 | | .id_result_type = u32_ty_id, |
| 3440 | .id_result_type = limb_ty_id, |
| 3395 | 3441 | .id_result = c2, |
| 3396 | 3442 | .composite = add2, |
| 3397 | 3443 | .indexes = &.{1}, |
| ... | ... | @@ -3412,7 +3458,8 @@ const CompositeInt = struct { |
| 3412 | 3458 | if (ci.info.bits == ci.info.backing_bits) return ci; |
| 3413 | 3459 | const cg = ci.cg; |
| 3414 | 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 | 3463 | assert(top_bits != 0); |
| 3417 | 3464 | |
| 3418 | 3465 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| ... | ... | @@ -3421,41 +3468,43 @@ const CompositeInt = struct { |
| 3421 | 3468 | } |
| 3422 | 3469 | |
| 3423 | 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 | 3473 | switch (ci.info.signedness) { |
| 3425 | 3474 | .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); |
| 3475 | const mask_val: u64 = (@as(u64, 1) << @as(u6, @intCast(top_bits))) - 1; |
| 3476 | const mask_id = try cg.constInt(limb_ty, mask_val); |
| 3428 | 3477 | result_limbs[ci.n_limbs - 1] = try ci.limbBinOp(.OpBitwiseAnd, top_limb, mask_id); |
| 3429 | 3478 | }, |
| 3430 | 3479 | .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); |
| 3480 | const limb_ty_id = try cg.limbTypeId(); |
| 3481 | const signed_ty_id = try cg.resolveType(limb_signed_ty, .direct); |
| 3482 | const shift_amt: u32 = @intCast(limb_bits - top_bits); |
| 3483 | const shift_id = try cg.constInt(limb_ty, shift_amt); |
| 3435 | 3484 | |
| 3436 | 3485 | const as_signed = cg.allocId(); |
| 3437 | 3486 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 3438 | | .id_result_type = i32_ty_id, |
| 3487 | .id_result_type = signed_ty_id, |
| 3439 | 3488 | .id_result = as_signed, |
| 3440 | 3489 | .operand = top_limb, |
| 3441 | 3490 | }); |
| 3442 | 3491 | const shifted_left = cg.allocId(); |
| 3443 | 3492 | try cg.body.emit(gpa, .OpShiftLeftLogical, .{ |
| 3444 | | .id_result_type = i32_ty_id, |
| 3493 | .id_result_type = signed_ty_id, |
| 3445 | 3494 | .id_result = shifted_left, |
| 3446 | 3495 | .base = as_signed, |
| 3447 | 3496 | .shift = shift_id, |
| 3448 | 3497 | }); |
| 3449 | 3498 | const shifted_right = cg.allocId(); |
| 3450 | 3499 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 3451 | | .id_result_type = i32_ty_id, |
| 3500 | .id_result_type = signed_ty_id, |
| 3452 | 3501 | .id_result = shifted_right, |
| 3453 | 3502 | .base = shifted_left, |
| 3454 | 3503 | .shift = shift_id, |
| 3455 | 3504 | }); |
| 3456 | 3505 | const back = cg.allocId(); |
| 3457 | 3506 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 3458 | | .id_result_type = u32_ty_id, |
| 3507 | .id_result_type = limb_ty_id, |
| 3459 | 3508 | .id_result = back, |
| 3460 | 3509 | .operand = shifted_right, |
| 3461 | 3510 | }); |
| ... | ... | @@ -4552,13 +4601,14 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode |
| 4552 | 4601 | switch (info.class) { |
| 4553 | 4602 | .composite_integer => { |
| 4554 | 4603 | const shift_info = cg.arithmeticTypeInfo(shift.ty); |
| 4604 | const limb_ty = cg.limbType(); |
| 4555 | 4605 | const shift_amt_id = switch (shift_info.class) { |
| 4556 | 4606 | .composite_integer => blk: { |
| 4557 | 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 | 4609 | const result_id = cg.allocId(); |
| 4560 | 4610 | try cg.body.emit(cg.gpa, .OpCompositeExtract, .{ |
| 4561 | | .id_result_type = u32_ty_id, |
| 4611 | .id_result_type = limb_ty_id, |
| 4562 | 4612 | .id_result = result_id, |
| 4563 | 4613 | .composite = shift_id, |
| 4564 | 4614 | .indexes = &.{@as(u32, 0)}, |
| ... | ... | @@ -4566,7 +4616,7 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode |
| 4566 | 4616 | break :blk result_id; |
| 4567 | 4617 | }, |
| 4568 | 4618 | else => blk: { |
| 4569 | | const converted = try cg.buildConvert(.u32, shift); |
| 4619 | const converted = try cg.buildConvert(limb_ty, shift); |
| 4570 | 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 | 4937 | const is_neg = try ci.cmp(ci_z, .lt); |
| 4888 | 4938 | const ci_neg = try ci_z.addSub(ci, false); |
| 4889 | 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 | 4941 | const result_limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, ci.n_limbs); |
| 4892 | 4942 | for (0..ci.n_limbs) |i| { |
| 4893 | 4943 | result_limbs[i] = cg.allocId(); |
| 4894 | 4944 | try cg.body.emit(cg.gpa, .OpSelect, .{ |
| 4895 | | .id_result_type = u32_ty_id, |
| 4945 | .id_result_type = limb_ty_id, |
| 4896 | 4946 | .id_result = result_limbs[i], |
| 4897 | 4947 | .condition = is_neg, |
| 4898 | 4948 | .object_1 = ci_neg.limbs[i], |
| ... | ... | @@ -5066,12 +5116,13 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5066 | 5116 | const high_limbs = wide_limbs[ci_lhs2.n_limbs..]; |
| 5067 | 5117 | |
| 5068 | 5118 | const bool_ty_id = try cg.resolveType(.bool, .direct); |
| 5069 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 5070 | | const n: usize = info.backing_bits / big_int_bits; |
| 5119 | const limb_ty_id = try cg.limbTypeId(); |
| 5120 | const limb_ty = cg.limbType(); |
| 5121 | const n: usize = info.backing_bits / cg.bigIntBits(); |
| 5071 | 5122 | |
| 5072 | 5123 | const ov_bool = switch (info.signedness) { |
| 5073 | 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 | 5126 | var any_nonzero = cg.allocId(); |
| 5076 | 5127 | try cg.body.emit(gpa, .OpINotEqual, .{ |
| 5077 | 5128 | .id_result_type = bool_ty_id, |
| ... | ... | @@ -5104,32 +5155,33 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5104 | 5155 | .signed => blk: { |
| 5105 | 5156 | const ci_res = try CompositeInt.init(cg, result_val_id, info); |
| 5106 | 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); |
| 5108 | 5160 | |
| 5109 | | const top_bits: u16 = if (info.bits % big_int_bits == 0) |
| 5110 | | big_int_bits |
| 5161 | const top_bits: u16 = if (info.bits % cg.bigIntBits() == 0) |
| 5162 | cg.bigIntBits() |
| 5111 | 5163 | else |
| 5112 | | info.bits % big_int_bits; |
| 5164 | info.bits % cg.bigIntBits(); |
| 5113 | 5165 | |
| 5114 | | const shift_amt: u32 = top_bits - 1; |
| 5115 | | const shift_id = try cg.constInt(.u32, shift_amt); |
| 5166 | const shift_amt: u64 = top_bits - 1; |
| 5167 | const shift_id = try cg.constInt(limb_ty, shift_amt); |
| 5116 | 5168 | |
| 5117 | 5169 | const as_signed = cg.allocId(); |
| 5118 | 5170 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 5119 | | .id_result_type = i32_ty_id, |
| 5171 | .id_result_type = signed_limb_ty_id, |
| 5120 | 5172 | .id_result = as_signed, |
| 5121 | 5173 | .operand = top_limb, |
| 5122 | 5174 | }); |
| 5123 | 5175 | const sign_ext = cg.allocId(); |
| 5124 | 5176 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 5125 | | .id_result_type = i32_ty_id, |
| 5177 | .id_result_type = signed_limb_ty_id, |
| 5126 | 5178 | .id_result = sign_ext, |
| 5127 | 5179 | .base = as_signed, |
| 5128 | 5180 | .shift = shift_id, |
| 5129 | 5181 | }); |
| 5130 | 5182 | const expected = cg.allocId(); |
| 5131 | 5183 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 5132 | | .id_result_type = u32_ty_id, |
| 5184 | .id_result_type = limb_ty_id, |
| 5133 | 5185 | .id_result = expected, |
| 5134 | 5186 | .operand = sign_ext, |
| 5135 | 5187 | }); |
| ... | ... | @@ -5162,25 +5214,25 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5162 | 5214 | } |
| 5163 | 5215 | |
| 5164 | 5216 | if (info.bits != info.backing_bits) { |
| 5165 | | const top_bits_s: u16 = info.bits % big_int_bits; |
| 5166 | | const s_shift_id = try cg.constInt(.u32, top_bits_s - 1); |
| 5217 | const top_bits_s: u16 = info.bits % cg.bigIntBits(); |
| 5218 | const s_shift_id = try cg.constInt(limb_ty, @as(u64, top_bits_s - 1)); |
| 5167 | 5219 | |
| 5168 | 5220 | const top_as_signed = cg.allocId(); |
| 5169 | 5221 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 5170 | | .id_result_type = i32_ty_id, |
| 5222 | .id_result_type = signed_limb_ty_id, |
| 5171 | 5223 | .id_result = top_as_signed, |
| 5172 | 5224 | .operand = top_limb, |
| 5173 | 5225 | }); |
| 5174 | 5226 | const top_sign_ext = cg.allocId(); |
| 5175 | 5227 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 5176 | | .id_result_type = i32_ty_id, |
| 5228 | .id_result_type = signed_limb_ty_id, |
| 5177 | 5229 | .id_result = top_sign_ext, |
| 5178 | 5230 | .base = top_as_signed, |
| 5179 | 5231 | .shift = s_shift_id, |
| 5180 | 5232 | }); |
| 5181 | 5233 | const top_expected = cg.allocId(); |
| 5182 | 5234 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 5183 | | .id_result_type = u32_ty_id, |
| 5235 | .id_result_type = limb_ty_id, |
| 5184 | 5236 | .id_result = top_expected, |
| 5185 | 5237 | .operand = top_sign_ext, |
| 5186 | 5238 | }); |
| ... | ... | @@ -6117,15 +6169,17 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6117 | 6169 | |
| 6118 | 6170 | if (src_composite and dst_composite) { |
| 6119 | 6171 | const src_id = try src.materialize(cg); |
| 6120 | | const src_n: u16 = src_info.backing_bits / big_int_bits; |
| 6121 | | const dst_n: u16 = dst_info.backing_bits / big_int_bits; |
| 6172 | const limb_bits = cg.bigIntBits(); |
| 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 | 6177 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n); |
| 6123 | 6178 | const min_n = @min(src_n, dst_n); |
| 6124 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 6125 | 6179 | for (0..min_n) |i| { |
| 6126 | 6180 | result_limbs[i] = cg.allocId(); |
| 6127 | 6181 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 6128 | | .id_result_type = u32_ty_id, |
| 6182 | .id_result_type = limb_ty_id, |
| 6129 | 6183 | .id_result = result_limbs[i], |
| 6130 | 6184 | .composite = src_id, |
| 6131 | 6185 | .indexes = &.{@as(u32, @intCast(i))}, |
| ... | ... | @@ -6133,30 +6187,31 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6133 | 6187 | } |
| 6134 | 6188 | if (dst_n > src_n) { |
| 6135 | 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 | 6192 | const msb = result_limbs[src_n - 1]; |
| 6138 | 6193 | const msb_signed = cg.allocId(); |
| 6139 | 6194 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 6140 | | .id_result_type = i32_ty_id, |
| 6195 | .id_result_type = signed_limb_ty_id, |
| 6141 | 6196 | .id_result = msb_signed, |
| 6142 | 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 | 6200 | const sign_ext = cg.allocId(); |
| 6146 | 6201 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 6147 | | .id_result_type = i32_ty_id, |
| 6202 | .id_result_type = signed_limb_ty_id, |
| 6148 | 6203 | .id_result = sign_ext, |
| 6149 | 6204 | .base = msb_signed, |
| 6150 | | .shift = shift31, |
| 6205 | .shift = shift_amt, |
| 6151 | 6206 | }); |
| 6152 | 6207 | const back = cg.allocId(); |
| 6153 | 6208 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 6154 | | .id_result_type = u32_ty_id, |
| 6209 | .id_result_type = limb_ty_id, |
| 6155 | 6210 | .id_result = back, |
| 6156 | 6211 | .operand = sign_ext, |
| 6157 | 6212 | }); |
| 6158 | 6213 | break :blk back; |
| 6159 | | } else try cg.constInt(.u32, @as(u32, 0)); |
| 6214 | } else try cg.constInt(limb_ty, @as(u64, 0)); |
| 6160 | 6215 | for (min_n..dst_n) |i| { |
| 6161 | 6216 | result_limbs[i] = fill; |
| 6162 | 6217 | } |
| ... | ... | @@ -6166,16 +6221,18 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6166 | 6221 | return try normalized.materialize(dst_ty); |
| 6167 | 6222 | } else if (src_composite and !dst_composite) { |
| 6168 | 6223 | const src_id = try src.materialize(cg); |
| 6169 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 6170 | | if (dst_info.backing_bits <= 32) { |
| 6224 | const limb_bits = cg.bigIntBits(); |
| 6225 | const limb_ty = cg.limbType(); |
| 6226 | const limb_ty_id = try cg.limbTypeId(); |
| 6227 | if (dst_info.backing_bits <= limb_bits) { |
| 6171 | 6228 | const limb0 = cg.allocId(); |
| 6172 | 6229 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 6173 | | .id_result_type = u32_ty_id, |
| 6230 | .id_result_type = limb_ty_id, |
| 6174 | 6231 | .id_result = limb0, |
| 6175 | 6232 | .composite = src_id, |
| 6176 | 6233 | .indexes = &.{@as(u32, 0)}, |
| 6177 | 6234 | }); |
| 6178 | | const tmp: Temporary = .init(.u32, limb0); |
| 6235 | const tmp: Temporary = .init(limb_ty, limb0); |
| 6179 | 6236 | const converted = try cg.buildConvert(dst_ty, tmp); |
| 6180 | 6237 | const result = if (dst_info.bits < src_info.bits) |
| 6181 | 6238 | try cg.normalize(converted, dst_info) |
| ... | ... | @@ -6183,16 +6240,17 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6183 | 6240 | converted; |
| 6184 | 6241 | return try result.materialize(cg); |
| 6185 | 6242 | } else { |
| 6243 | assert(limb_bits == 32); // dst > 64 while limbs are 64 shouldn't happen — dst fits in one 64-bit limb. |
| 6186 | 6244 | const limb0 = cg.allocId(); |
| 6187 | 6245 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 6188 | | .id_result_type = u32_ty_id, |
| 6246 | .id_result_type = limb_ty_id, |
| 6189 | 6247 | .id_result = limb0, |
| 6190 | 6248 | .composite = src_id, |
| 6191 | 6249 | .indexes = &.{@as(u32, 0)}, |
| 6192 | 6250 | }); |
| 6193 | 6251 | const limb1 = cg.allocId(); |
| 6194 | 6252 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| 6195 | | .id_result_type = u32_ty_id, |
| 6253 | .id_result_type = limb_ty_id, |
| 6196 | 6254 | .id_result = limb1, |
| 6197 | 6255 | .composite = src_id, |
| 6198 | 6256 | .indexes = &.{@as(u32, 1)}, |
| ... | ... | @@ -6234,19 +6292,21 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6234 | 6292 | return try result.materialize(cg); |
| 6235 | 6293 | } |
| 6236 | 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 | 6299 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n); |
| 6239 | | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| 6240 | 6300 | |
| 6241 | | if (src_info.backing_bits <= 32) { |
| 6242 | | const converted = try cg.buildConvert(.u32, src); |
| 6301 | if (src_info.backing_bits <= limb_bits) { |
| 6302 | const converted = try cg.buildConvert(limb_ty, src); |
| 6243 | 6303 | result_limbs[0] = try converted.materialize(cg); |
| 6244 | 6304 | } else { |
| 6245 | 6305 | const src_as_u64 = try cg.buildConvert(.u64, src); |
| 6246 | 6306 | const src_id = try src_as_u64.materialize(cg); |
| 6247 | 6307 | result_limbs[0] = cg.allocId(); |
| 6248 | 6308 | try cg.body.emit(gpa, .OpUConvert, .{ |
| 6249 | | .id_result_type = u32_ty_id, |
| 6309 | .id_result_type = limb_ty_id, |
| 6250 | 6310 | .id_result = result_limbs[0], |
| 6251 | 6311 | .unsigned_value = src_id, |
| 6252 | 6312 | }); |
| ... | ... | @@ -6261,38 +6321,39 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 6261 | 6321 | }); |
| 6262 | 6322 | result_limbs[1] = cg.allocId(); |
| 6263 | 6323 | try cg.body.emit(gpa, .OpUConvert, .{ |
| 6264 | | .id_result_type = u32_ty_id, |
| 6324 | .id_result_type = limb_ty_id, |
| 6265 | 6325 | .id_result = result_limbs[1], |
| 6266 | 6326 | .unsigned_value = hi, |
| 6267 | 6327 | }); |
| 6268 | 6328 | } |
| 6269 | 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 | 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 | 6334 | const msb = result_limbs[fill_start - 1]; |
| 6274 | 6335 | const msb_signed = cg.allocId(); |
| 6275 | 6336 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 6276 | | .id_result_type = i32_ty_id, |
| 6337 | .id_result_type = signed_limb_ty_id, |
| 6277 | 6338 | .id_result = msb_signed, |
| 6278 | 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 | 6342 | const sign_ext = cg.allocId(); |
| 6282 | 6343 | try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ |
| 6283 | | .id_result_type = i32_ty_id, |
| 6344 | .id_result_type = signed_limb_ty_id, |
| 6284 | 6345 | .id_result = sign_ext, |
| 6285 | 6346 | .base = msb_signed, |
| 6286 | | .shift = shift31, |
| 6347 | .shift = shift_amt, |
| 6287 | 6348 | }); |
| 6288 | 6349 | const back = cg.allocId(); |
| 6289 | 6350 | try cg.body.emit(gpa, .OpBitcast, .{ |
| 6290 | | .id_result_type = u32_ty_id, |
| 6351 | .id_result_type = limb_ty_id, |
| 6291 | 6352 | .id_result = back, |
| 6292 | 6353 | .operand = sign_ext, |
| 6293 | 6354 | }); |
| 6294 | 6355 | break :blk back; |
| 6295 | | } else try cg.constInt(.u32, @as(u32, 0)); |
| 6356 | } else try cg.constInt(limb_ty, @as(u64, 0)); |
| 6296 | 6357 | for (fill_start..dst_n) |i| { |
| 6297 | 6358 | result_limbs[i] = fill; |
| 6298 | 6359 | } |