| ... | ... | @@ -2757,12 +2757,14 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2757 | 2757 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 2758 | 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 | 2763 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 2761 | | const ty = func.typeOf(extra.lhs); |
| 2762 | | switch (ty.zigTypeTag(zcu)) { |
| 2764 | switch (lhs_ty.zigTypeTag(zcu)) { |
| 2763 | 2765 | .Vector => return func.fail("TODO implement add with overflow for Vector type", .{}), |
| 2764 | 2766 | .Int => { |
| 2765 | | const int_info = ty.intInfo(zcu); |
| 2767 | const int_info = lhs_ty.intInfo(zcu); |
| 2766 | 2768 | |
| 2767 | 2769 | const tuple_ty = func.typeOfIndex(inst); |
| 2768 | 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 | 2776 | try func.genSetMem( |
| 2775 | 2777 | .{ .frame = offset.index }, |
| 2776 | 2778 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))), |
| 2777 | | ty, |
| 2779 | lhs_ty, |
| 2778 | 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 | 2784 | const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg); |
| 2783 | 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 | 2789 | |
| 2788 | 2790 | // if the result isn't equal after truncating it to the given type, |
| 2789 | 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 | 2793 | try func.genBinOp( |
| 2792 | 2794 | .cmp_neq, |
| 2793 | 2795 | add_result, |
| 2794 | | ty, |
| 2796 | lhs_ty, |
| 2795 | 2797 | .{ .register = trunc_reg }, |
| 2796 | | ty, |
| 2798 | rhs_ty, |
| 2797 | 2799 | overflow_reg, |
| 2798 | 2800 | ); |
| 2799 | 2801 | |
| ... | ... | @@ -2806,7 +2808,69 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2806 | 2808 | |
| 2807 | 2809 | break :result result_mcv; |
| 2808 | 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 | 2876 | else => unreachable, |