| ... | @@ -2757,12 +2757,14 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2757,12 +2757,14 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2757 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 2757 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 2758 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; | 2758 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2759 | | 2759 | |
| | 2760 | const rhs_ty = func.typeOf(extra.rhs); |
| | 2761 | const lhs_ty = func.typeOf(extra.lhs); |
| | 2762 | |
| 2760 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2763 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 2761 | const ty = func.typeOf(extra.lhs); | 2764 | switch (lhs_ty.zigTypeTag(zcu)) { |
| 2762 | switch (ty.zigTypeTag(zcu)) { | | |
| 2763 | .Vector => return func.fail("TODO implement add with overflow for Vector type", .{}), | 2765 | .Vector => return func.fail("TODO implement add with overflow for Vector type", .{}), |
| 2764 | .Int => { | 2766 | .Int => { |
| 2765 | const int_info = ty.intInfo(zcu); | 2767 | const int_info = lhs_ty.intInfo(zcu); |
| 2766 | | 2768 | |
| 2767 | const tuple_ty = func.typeOfIndex(inst); | 2769 | const tuple_ty = func.typeOfIndex(inst); |
| 2768 | const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false); | 2770 | const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false); |
| ... | @@ -2774,11 +2776,11 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2774,11 +2776,11 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2774 | try func.genSetMem( | 2776 | try func.genSetMem( |
| 2775 | .{ .frame = offset.index }, | 2777 | .{ .frame = offset.index }, |
| 2776 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))), | 2778 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))), |
| 2777 | ty, | 2779 | lhs_ty, |
| 2778 | add_result, | 2780 | add_result, |
| 2779 | ); | 2781 | ); |
| 2780 | | 2782 | |
| 2781 | const trunc_reg = try func.copyToTmpRegister(ty, add_result); | 2783 | const trunc_reg = try func.copyToTmpRegister(lhs_ty, add_result); |
| 2782 | const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg); | 2784 | const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg); |
| 2783 | defer func.register_manager.unlockReg(trunc_reg_lock); | 2785 | defer func.register_manager.unlockReg(trunc_reg_lock); |
| 2784 | | 2786 | |
| ... | @@ -2787,13 +2789,13 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2787,13 +2789,13 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2787 | | 2789 | |
| 2788 | // if the result isn't equal after truncating it to the given type, | 2790 | // if the result isn't equal after truncating it to the given type, |
| 2789 | // an overflow must have happened. | 2791 | // an overflow must have happened. |
| 2790 | try func.truncateRegister(func.typeOf(extra.lhs), trunc_reg); | 2792 | try func.truncateRegister(lhs_ty, trunc_reg); |
| 2791 | try func.genBinOp( | 2793 | try func.genBinOp( |
| 2792 | .cmp_neq, | 2794 | .cmp_neq, |
| 2793 | add_result, | 2795 | add_result, |
| 2794 | ty, | 2796 | lhs_ty, |
| 2795 | .{ .register = trunc_reg }, | 2797 | .{ .register = trunc_reg }, |
| 2796 | ty, | 2798 | rhs_ty, |
| 2797 | overflow_reg, | 2799 | overflow_reg, |
| 2798 | ); | 2800 | ); |
| 2799 | | 2801 | |
| ... | @@ -2806,7 +2808,69 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2806,7 +2808,69 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2806 | | 2808 | |
| 2807 | break :result result_mcv; | 2809 | break :result result_mcv; |
| 2808 | } else { | 2810 | } else { |
| 2809 | return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{}); | 2811 | const rhs_mcv = try func.resolveInst(extra.rhs); |
| | 2812 | const lhs_mcv = try func.resolveInst(extra.lhs); |
| | 2813 | |
| | 2814 | const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs_mcv); |
| | 2815 | const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs_mcv); |
| | 2816 | defer { |
| | 2817 | if (rhs_lock) |lock| func.register_manager.unlockReg(lock); |
| | 2818 | if (lhs_lock) |lock| func.register_manager.unlockReg(lock); |
| | 2819 | } |
| | 2820 | |
| | 2821 | try func.truncateRegister(rhs_ty, rhs_reg); |
| | 2822 | try func.truncateRegister(lhs_ty, lhs_reg); |
| | 2823 | |
| | 2824 | const dest_reg, const dest_lock = try func.allocReg(.int); |
| | 2825 | defer func.register_manager.unlockReg(dest_lock); |
| | 2826 | |
| | 2827 | _ = try func.addInst(.{ |
| | 2828 | .tag = .add, |
| | 2829 | .ops = .rrr, |
| | 2830 | .data = .{ .r_type = .{ |
| | 2831 | .rs1 = rhs_reg, |
| | 2832 | .rs2 = lhs_reg, |
| | 2833 | .rd = dest_reg, |
| | 2834 | } }, |
| | 2835 | }); |
| | 2836 | |
| | 2837 | try func.truncateRegister(func.typeOfIndex(inst), dest_reg); |
| | 2838 | const add_result: MCValue = .{ .register = dest_reg }; |
| | 2839 | |
| | 2840 | try func.genSetMem( |
| | 2841 | .{ .frame = offset.index }, |
| | 2842 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))), |
| | 2843 | lhs_ty, |
| | 2844 | add_result, |
| | 2845 | ); |
| | 2846 | |
| | 2847 | const trunc_reg = try func.copyToTmpRegister(lhs_ty, add_result); |
| | 2848 | const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg); |
| | 2849 | defer func.register_manager.unlockReg(trunc_reg_lock); |
| | 2850 | |
| | 2851 | const overflow_reg, const overflow_lock = try func.allocReg(.int); |
| | 2852 | defer func.register_manager.unlockReg(overflow_lock); |
| | 2853 | |
| | 2854 | // if the result isn't equal after truncating it to the given type, |
| | 2855 | // an overflow must have happened. |
| | 2856 | try func.truncateRegister(lhs_ty, trunc_reg); |
| | 2857 | try func.genBinOp( |
| | 2858 | .cmp_neq, |
| | 2859 | add_result, |
| | 2860 | lhs_ty, |
| | 2861 | .{ .register = trunc_reg }, |
| | 2862 | rhs_ty, |
| | 2863 | overflow_reg, |
| | 2864 | ); |
| | 2865 | |
| | 2866 | try func.genSetMem( |
| | 2867 | .{ .frame = offset.index }, |
| | 2868 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))), |
| | 2869 | Type.u1, |
| | 2870 | .{ .register = overflow_reg }, |
| | 2871 | ); |
| | 2872 | |
| | 2873 | break :result result_mcv; |
| 2810 | } | 2874 | } |
| 2811 | }, | 2875 | }, |
| 2812 | else => unreachable, | 2876 | else => unreachable, |