| ... | @@ -1026,7 +1026,7 @@ pub const Value = struct { | ... | @@ -1026,7 +1026,7 @@ pub const Value = struct { |
| 1026 | } | 1026 | } |
| 1027 | | 1027 | |
| 1028 | /// Defines a value with a register. | 1028 | /// Defines a value with a register. |
| 1029 | /// Returned registers are free-ed. | 1029 | /// Returned registers are free-ed and marked as written. |
| 1030 | /// Extension unchanged. | 1030 | /// Extension unchanged. |
| 1031 | fn defReg(vi: Value.Index, isel: *Select) !?Register.Alias { | 1031 | fn defReg(vi: Value.Index, isel: *Select) !?Register.Alias { |
| 1032 | const value = vi.get(isel); | 1032 | const value = vi.get(isel); |
| ... | @@ -3573,6 +3573,26 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, | ... | @@ -3573,6 +3573,26 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 3573 | }, | 3573 | }, |
| 3574 | }) else return isel.fail("unimplemented float", .{}); | 3574 | }) else return isel.fail("unimplemented float", .{}); |
| 3575 | }, | 3575 | }, |
| | 3576 | .add_with_overflow, .sub_with_overflow => if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| { |
| | 3577 | defer res_vi.value.deref(isel); |
| | 3578 | |
| | 3579 | const ty_pl = air.data(air.inst_index).ty_pl; |
| | 3580 | const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 3581 | const ty = isel.air.typeOf(bin_op.lhs, ip); |
| | 3582 | const lhs_vi = try isel.use(bin_op.lhs); |
| | 3583 | const rhs_vi = try isel.use(bin_op.rhs); |
| | 3584 | const ty_size = lhs_vi.size(isel); |
| | 3585 | |
| | 3586 | const wrapped_vi = try res_vi.value.partExact(isel, 0, ty_size); |
| | 3587 | const overflow_vi = try res_vi.value.partExact(isel, ty_size, 1); |
| | 3588 | try isel.addOrSubtract(ty, wrapped_vi, switch (air_tag) { |
| | 3589 | else => unreachable, |
| | 3590 | .add_with_overflow => .add, |
| | 3591 | .sub_with_overflow => .sub, |
| | 3592 | }, lhs_vi, rhs_vi, .{ |
| | 3593 | .overflow = if (try overflow_vi.defReg(isel)) |overflow_ra| .{ .overflow_ra = overflow_ra } else .wrap, |
| | 3594 | }); |
| | 3595 | }, |
| 3576 | .not => if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | 3596 | .not => if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { |
| 3577 | defer res_vi.value.deref(isel); | 3597 | defer res_vi.value.deref(isel); |
| 3578 | | 3598 | |
| ... | @@ -3676,7 +3696,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, | ... | @@ -3676,7 +3696,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 3676 | try rhs_mat.finish(isel); | 3696 | try rhs_mat.finish(isel); |
| 3677 | try lhs_mat.finish(isel); | 3697 | try lhs_mat.finish(isel); |
| 3678 | }, | 3698 | }, |
| 3679 | else => try isel.failUnimplemented("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }), | 3699 | else => { |
| | 3700 | _ = try res_vi.value.def(isel); |
| | 3701 | try isel.failUnimplemented("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }); |
| | 3702 | }, |
| 3680 | } | 3703 | } |
| 3681 | } else try isel.failUnimplemented("unimplemented float div", .{}); | 3704 | } else try isel.failUnimplemented("unimplemented float div", .{}); |
| 3682 | }, | 3705 | }, |
| ... | @@ -5996,7 +6019,7 @@ const AddOrSubtractOptions = struct { | ... | @@ -5996,7 +6019,7 @@ const AddOrSubtractOptions = struct { |
| 5996 | @"unreachable", | 6019 | @"unreachable", |
| 5997 | panic: Zcu.SimplePanicId, | 6020 | panic: Zcu.SimplePanicId, |
| 5998 | wrap, | 6021 | wrap, |
| 5999 | reg: Register, | 6022 | overflow_ra: Register.Alias, |
| 6000 | }; | 6023 | }; |
| 6001 | }; | 6024 | }; |
| 6002 | | 6025 | |
| ... | @@ -6011,11 +6034,25 @@ fn addOrSubtract( | ... | @@ -6011,11 +6034,25 @@ fn addOrSubtract( |
| 6011 | opts: AddOrSubtractOptions, | 6034 | opts: AddOrSubtractOptions, |
| 6012 | ) !void { | 6035 | ) !void { |
| 6013 | wip_mir_log.debug(" | # {t} ty = {f}, res = {f}, lhs = {f}, rhs = {f}, overflow = {t}", .{ op, isel.fmtType(ty), res_vi, lhs_vi, rhs_vi, opts.overflow }); | 6036 | wip_mir_log.debug(" | # {t} ty = {f}, res = {f}, lhs = {f}, rhs = {f}, overflow = {t}", .{ op, isel.fmtType(ty), res_vi, lhs_vi, rhs_vi, opts.overflow }); |
| 6014 | // TODO: implement opts.overflow | | |
| 6015 | const zcu = isel.pt.zcu; | 6037 | const zcu = isel.pt.zcu; |
| 6016 | assert(ty.isAbiInt(zcu)); | 6038 | assert(ty.isAbiInt(zcu)); |
| 6017 | const int_info = ty.intInfo(zcu); | 6039 | const int_info = ty.intInfo(zcu); |
| 6018 | | 6040 | |
| | 6041 | switch (opts.overflow) { |
| | 6042 | .wrap, .@"unreachable" => {}, |
| | 6043 | .overflow_ra => |overflow_ra| { |
| | 6044 | const overflow_reg = if (overflow_ra.mod == .integer) overflow_ra.reg else try isel.allocRegForWrite(.int); |
| | 6045 | defer if (overflow_ra.mod != .integer) isel.freeReg(overflow_reg); |
| | 6046 | switch (op) { |
| | 6047 | .add => try isel.cmp(overflow_reg, ty, res_vi, .lt, lhs_vi), |
| | 6048 | .sub => try isel.cmp(overflow_reg, ty, res_vi, .gt, lhs_vi), |
| | 6049 | } |
| | 6050 | }, |
| | 6051 | .panic => { |
| | 6052 | try isel.failUnimplemented("unimplemented {t} with {t}", .{ op, opts.overflow }); |
| | 6053 | }, |
| | 6054 | } |
| | 6055 | |
| 6019 | if (int_info.bits <= 32) { | 6056 | if (int_info.bits <= 32) { |
| 6020 | try res_vi.reextendToGarbage(isel); // TODO optimize | 6057 | try res_vi.reextendToGarbage(isel); // TODO optimize |
| 6021 | const res_reg = try res_vi.defRegMod(isel, .integer) orelse return; | 6058 | const res_reg = try res_vi.defRegMod(isel, .integer) orelse return; |