| ... | @@ -1321,6 +1321,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1321,6 +1321,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1321 | .sub, | 1321 | .sub, |
| 1322 | .sub_wrap, | 1322 | .sub_wrap, |
| 1323 | | 1323 | |
| | 1324 | .add_sat, |
| | 1325 | |
| 1324 | .mul, | 1326 | .mul, |
| 1325 | .mul_wrap, | 1327 | .mul_wrap, |
| 1326 | .div_trunc, | 1328 | .div_trunc, |
| ... | @@ -1372,7 +1374,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1372,7 +1374,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1372 | .shl_with_overflow => try func.airShlWithOverflow(inst), | 1374 | .shl_with_overflow => try func.airShlWithOverflow(inst), |
| 1373 | | 1375 | |
| 1374 | | 1376 | |
| 1375 | .add_sat => try func.airAddSat(inst), | | |
| 1376 | .sub_sat => try func.airSubSat(inst), | 1377 | .sub_sat => try func.airSubSat(inst), |
| 1377 | .mul_sat => try func.airMulSat(inst), | 1378 | .mul_sat => try func.airMulSat(inst), |
| 1378 | .shl_sat => try func.airShlSat(inst), | 1379 | .shl_sat => try func.airShlSat(inst), |
| ... | @@ -1578,7 +1579,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1578,7 +1579,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1578 | for (tracking.getRegs()) |reg| { | 1579 | for (tracking.getRegs()) |reg| { |
| 1579 | if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break; | 1580 | if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break; |
| 1580 | } else return std.debug.panic( | 1581 | } else return std.debug.panic( |
| 1581 | \\%{} takes up these regs: {any}, however these regs {any}, don't use it | 1582 | \\%{} takes up these regs: {any}, however this regs {any}, don't use it |
| 1582 | , .{ tracked_inst, tracking.getRegs(), RegisterManager.regAtTrackedIndex(@intCast(index)) }); | 1583 | , .{ tracked_inst, tracking.getRegs(), RegisterManager.regAtTrackedIndex(@intCast(index)) }); |
| 1583 | } | 1584 | } |
| 1584 | } | 1585 | } |
| ... | @@ -2532,6 +2533,57 @@ fn genBinOp( | ... | @@ -2532,6 +2533,57 @@ fn genBinOp( |
| 2532 | } | 2533 | } |
| 2533 | }, | 2534 | }, |
| 2534 | | 2535 | |
| | 2536 | .add_sat, |
| | 2537 | => { |
| | 2538 | if (bit_size != 64 or !is_unsigned) |
| | 2539 | return func.fail("TODO: genBinOp ty: {}", .{lhs_ty.fmt(pt)}); |
| | 2540 | |
| | 2541 | const tmp_reg = try func.copyToTmpRegister(rhs_ty, .{ .register = rhs_reg }); |
| | 2542 | const tmp_lock = func.register_manager.lockRegAssumeUnused(tmp_reg); |
| | 2543 | defer func.register_manager.unlockReg(tmp_lock); |
| | 2544 | |
| | 2545 | _ = try func.addInst(.{ |
| | 2546 | .tag = .add, |
| | 2547 | .ops = .rrr, |
| | 2548 | .data = .{ .r_type = .{ |
| | 2549 | .rd = tmp_reg, |
| | 2550 | .rs1 = rhs_reg, |
| | 2551 | .rs2 = lhs_reg, |
| | 2552 | } }, |
| | 2553 | }); |
| | 2554 | |
| | 2555 | _ = try func.addInst(.{ |
| | 2556 | .tag = .sltu, |
| | 2557 | .ops = .rrr, |
| | 2558 | .data = .{ .r_type = .{ |
| | 2559 | .rd = dst_reg, |
| | 2560 | .rs1 = tmp_reg, |
| | 2561 | .rs2 = lhs_reg, |
| | 2562 | } }, |
| | 2563 | }); |
| | 2564 | |
| | 2565 | // neg dst_reg, dst_reg |
| | 2566 | _ = try func.addInst(.{ |
| | 2567 | .tag = .sub, |
| | 2568 | .ops = .rrr, |
| | 2569 | .data = .{ .r_type = .{ |
| | 2570 | .rd = dst_reg, |
| | 2571 | .rs1 = .zero, |
| | 2572 | .rs2 = dst_reg, |
| | 2573 | } }, |
| | 2574 | }); |
| | 2575 | |
| | 2576 | _ = try func.addInst(.{ |
| | 2577 | .tag = .@"or", |
| | 2578 | .ops = .rrr, |
| | 2579 | .data = .{ .r_type = .{ |
| | 2580 | .rd = dst_reg, |
| | 2581 | .rs1 = dst_reg, |
| | 2582 | .rs2 = tmp_reg, |
| | 2583 | } }, |
| | 2584 | }); |
| | 2585 | }, |
| | 2586 | |
| 2535 | .ptr_add, | 2587 | .ptr_add, |
| 2536 | .ptr_sub, | 2588 | .ptr_sub, |
| 2537 | => { | 2589 | => { |
| ... | @@ -3096,12 +3148,6 @@ fn airShlWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3096,12 +3148,6 @@ fn airShlWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 3096 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 3148 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 3097 | } | 3149 | } |
| 3098 | | 3150 | |
| 3099 | fn airAddSat(func: *Func, inst: Air.Inst.Index) !void { | | |
| 3100 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | | |
| 3101 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airAddSat", .{}); | | |
| 3102 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 3103 | } | | |
| 3104 | | | |
| 3105 | fn airSubSat(func: *Func, inst: Air.Inst.Index) !void { | 3151 | fn airSubSat(func: *Func, inst: Air.Inst.Index) !void { |
| 3106 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 3152 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 3107 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airSubSat", .{}); | 3153 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airSubSat", .{}); |
| ... | @@ -3495,7 +3541,16 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3495,7 +3541,16 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void { |
| 3495 | | 3541 | |
| 3496 | fn airPtrSliceLenPtr(func: *Func, inst: Air.Inst.Index) !void { | 3542 | fn airPtrSliceLenPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 3497 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3543 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3498 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement ptr_slice_len_ptr for {}", .{func.target.cpu.arch}); | 3544 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| | 3545 | const src_mcv = try func.resolveInst(ty_op.operand); |
| | 3546 | |
| | 3547 | const dst_reg, const dst_lock = try func.allocReg(.int); |
| | 3548 | defer func.register_manager.unlockReg(dst_lock); |
| | 3549 | const dst_mcv: MCValue = .{ .register = dst_reg }; |
| | 3550 | |
| | 3551 | try func.genCopy(Type.u64, dst_mcv, src_mcv.offset(8)); |
| | 3552 | break :result dst_mcv; |
| | 3553 | }; |
| 3499 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3554 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3500 | } | 3555 | } |
| 3501 | | 3556 | |
| ... | @@ -5838,6 +5893,17 @@ fn genInlineMemcpy( | ... | @@ -5838,6 +5893,17 @@ fn genInlineMemcpy( |
| 5838 | try func.genSetReg(Type.usize, src, src_ptr); | 5893 | try func.genSetReg(Type.usize, src, src_ptr); |
| 5839 | try func.genSetReg(Type.usize, dst, dst_ptr); | 5894 | try func.genSetReg(Type.usize, dst, dst_ptr); |
| 5840 | | 5895 | |
| | 5896 | // if count is 0, there's nothing to copy |
| | 5897 | _ = try func.addInst(.{ |
| | 5898 | .tag = .beq, |
| | 5899 | .ops = .rr_inst, |
| | 5900 | .data = .{ .b_type = .{ |
| | 5901 | .rs1 = count, |
| | 5902 | .rs2 = .zero, |
| | 5903 | .inst = @intCast(func.mir_instructions.len + 9), |
| | 5904 | } }, |
| | 5905 | }); |
| | 5906 | |
| 5841 | // lb tmp, 0(src) | 5907 | // lb tmp, 0(src) |
| 5842 | const first_inst = try func.addInst(.{ | 5908 | const first_inst = try func.addInst(.{ |
| 5843 | .tag = .lb, | 5909 | .tag = .lb, |
| ... | @@ -6145,7 +6211,9 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -6145,7 +6211,9 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6145 | } }, | 6211 | } }, |
| 6146 | }); | 6212 | }); |
| 6147 | }, | 6213 | }, |
| 6148 | .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}), | 6214 | // useful in cases like slice_ptr, which can easily reuse the operand |
| | 6215 | // but we need to get only the pointer out. |
| | 6216 | .register_pair => |pair| try func.genSetReg(ty, reg, .{ .register = pair[0] }), |
| 6149 | .load_frame => |frame| { | 6217 | .load_frame => |frame| { |
| 6150 | if (reg.class() == .vector) { | 6218 | if (reg.class() == .vector) { |
| 6151 | // vectors don't support an offset memory load so we need to put the true | 6219 | // vectors don't support an offset memory load so we need to put the true |
| ... | @@ -6507,7 +6575,7 @@ fn airBitCast(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -6507,7 +6575,7 @@ fn airBitCast(func: *Func, inst: Air.Inst.Index) !void { |
| 6507 | const src_lock = if (src_mcv.getReg()) |reg| func.register_manager.lockReg(reg) else null; | 6575 | const src_lock = if (src_mcv.getReg()) |reg| func.register_manager.lockReg(reg) else null; |
| 6508 | defer if (src_lock) |lock| func.register_manager.unlockReg(lock); | 6576 | defer if (src_lock) |lock| func.register_manager.unlockReg(lock); |
| 6509 | | 6577 | |
| 6510 | const dst_mcv = if (dst_ty.abiSize(pt) <= src_ty.abiSize(pt) and | 6578 | const dst_mcv = if (dst_ty.abiSize(pt) <= src_ty.abiSize(pt) and src_mcv != .register_pair and |
| 6511 | func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { | 6579 | func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { |
| 6512 | const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true); | 6580 | const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true); |
| 6513 | try func.genCopy(switch (math.order(dst_ty.abiSize(pt), src_ty.abiSize(pt))) { | 6581 | try func.genCopy(switch (math.order(dst_ty.abiSize(pt), src_ty.abiSize(pt))) { |
| ... | @@ -6827,8 +6895,42 @@ fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -6827,8 +6895,42 @@ fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void { |
| 6827 | } | 6895 | } |
| 6828 | | 6896 | |
| 6829 | fn airMemcpy(func: *Func, inst: Air.Inst.Index) !void { | 6897 | fn airMemcpy(func: *Func, inst: Air.Inst.Index) !void { |
| 6830 | _ = inst; | 6898 | const pt = func.pt; |
| 6831 | return func.fail("TODO implement airMemcpy for {}", .{func.target.cpu.arch}); | 6899 | const zcu = pt.zcu; |
| | 6900 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| | 6901 | |
| | 6902 | const dst_ptr = try func.resolveInst(bin_op.lhs); |
| | 6903 | const src_ptr = try func.resolveInst(bin_op.rhs); |
| | 6904 | |
| | 6905 | const dst_ty = func.typeOf(bin_op.lhs); |
| | 6906 | |
| | 6907 | const len_mcv: MCValue = switch (dst_ty.ptrSize(zcu)) { |
| | 6908 | .Slice => len: { |
| | 6909 | const len_reg, const len_lock = try func.allocReg(.int); |
| | 6910 | defer func.register_manager.unlockReg(len_lock); |
| | 6911 | |
| | 6912 | const elem_size = dst_ty.childType(zcu).abiSize(pt); |
| | 6913 | try func.genBinOp( |
| | 6914 | .mul, |
| | 6915 | .{ .immediate = elem_size }, |
| | 6916 | Type.u64, |
| | 6917 | dst_ptr.address().offset(8).deref(), |
| | 6918 | Type.u64, |
| | 6919 | len_reg, |
| | 6920 | ); |
| | 6921 | break :len .{ .register = len_reg }; |
| | 6922 | }, |
| | 6923 | else => |size| return func.fail("TODO: airMemcpy size {s}", .{@tagName(size)}), |
| | 6924 | }; |
| | 6925 | const len_lock: ?RegisterLock = switch (len_mcv) { |
| | 6926 | .register => |reg| func.register_manager.lockRegAssumeUnused(reg), |
| | 6927 | else => null, |
| | 6928 | }; |
| | 6929 | defer if (len_lock) |lock| func.register_manager.unlockReg(lock); |
| | 6930 | |
| | 6931 | try func.genInlineMemcpy(dst_ptr, src_ptr, len_mcv); |
| | 6932 | |
| | 6933 | return func.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 6832 | } | 6934 | } |
| 6833 | | 6935 | |
| 6834 | fn airTagName(func: *Func, inst: Air.Inst.Index) !void { | 6936 | fn airTagName(func: *Func, inst: Air.Inst.Index) !void { |