Commit 64c6473443

David Rubin <daviru007@icloud.com>
2024-07-21 10:36:26
riscv: implement `add_sat` and `ptr_slice_len_ptr` this is enough to use the basic functions of an ArrayList!
1 parent 45443f9
Changed files (1)
src
arch
riscv64
src/arch/riscv64/CodeGen.zig
@@ -1321,6 +1321,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
             .sub,
             .sub_wrap,
 
+            .add_sat,
+
             .mul,
             .mul_wrap,
             .div_trunc, 
@@ -1372,7 +1374,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
             .shl_with_overflow => try func.airShlWithOverflow(inst),
 
 
-            .add_sat         => try func.airAddSat(inst),
             .sub_sat         => try func.airSubSat(inst),
             .mul_sat         => try func.airMulSat(inst),
             .shl_sat         => try func.airShlSat(inst),
@@ -1578,7 +1579,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
                     for (tracking.getRegs()) |reg| {
                         if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
                     } else return std.debug.panic(
-                        \\%{} takes up these regs: {any}, however these regs {any}, don't use it
+                        \\%{} takes up these regs: {any}, however this regs {any}, don't use it
                     , .{ tracked_inst, tracking.getRegs(), RegisterManager.regAtTrackedIndex(@intCast(index)) });
                 }
             }
@@ -2532,6 +2533,57 @@ fn genBinOp(
             }
         },
 
+        .add_sat,
+        => {
+            if (bit_size != 64 or !is_unsigned)
+                return func.fail("TODO: genBinOp ty: {}", .{lhs_ty.fmt(pt)});
+
+            const tmp_reg = try func.copyToTmpRegister(rhs_ty, .{ .register = rhs_reg });
+            const tmp_lock = func.register_manager.lockRegAssumeUnused(tmp_reg);
+            defer func.register_manager.unlockReg(tmp_lock);
+
+            _ = try func.addInst(.{
+                .tag = .add,
+                .ops = .rrr,
+                .data = .{ .r_type = .{
+                    .rd = tmp_reg,
+                    .rs1 = rhs_reg,
+                    .rs2 = lhs_reg,
+                } },
+            });
+
+            _ = try func.addInst(.{
+                .tag = .sltu,
+                .ops = .rrr,
+                .data = .{ .r_type = .{
+                    .rd = dst_reg,
+                    .rs1 = tmp_reg,
+                    .rs2 = lhs_reg,
+                } },
+            });
+
+            // neg dst_reg, dst_reg
+            _ = try func.addInst(.{
+                .tag = .sub,
+                .ops = .rrr,
+                .data = .{ .r_type = .{
+                    .rd = dst_reg,
+                    .rs1 = .zero,
+                    .rs2 = dst_reg,
+                } },
+            });
+
+            _ = try func.addInst(.{
+                .tag = .@"or",
+                .ops = .rrr,
+                .data = .{ .r_type = .{
+                    .rd = dst_reg,
+                    .rs1 = dst_reg,
+                    .rs2 = tmp_reg,
+                } },
+            });
+        },
+
         .ptr_add,
         .ptr_sub,
         => {
@@ -3096,12 +3148,6 @@ fn airShlWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
     return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
 
-fn airAddSat(func: *Func, inst: Air.Inst.Index) !void {
-    const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
-    const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airAddSat", .{});
-    return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
-}
-
 fn airSubSat(func: *Func, inst: Air.Inst.Index) !void {
     const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
     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 {
 
 fn airPtrSliceLenPtr(func: *Func, inst: Air.Inst.Index) !void {
     const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
-    const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement ptr_slice_len_ptr for {}", .{func.target.cpu.arch});
+    const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
+        const src_mcv = try func.resolveInst(ty_op.operand);
+
+        const dst_reg, const dst_lock = try func.allocReg(.int);
+        defer func.register_manager.unlockReg(dst_lock);
+        const dst_mcv: MCValue = .{ .register = dst_reg };
+
+        try func.genCopy(Type.u64, dst_mcv, src_mcv.offset(8));
+        break :result dst_mcv;
+    };
     return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
 
@@ -5838,6 +5893,17 @@ fn genInlineMemcpy(
     try func.genSetReg(Type.usize, src, src_ptr);
     try func.genSetReg(Type.usize, dst, dst_ptr);
 
+    // if count is 0, there's nothing to copy
+    _ = try func.addInst(.{
+        .tag = .beq,
+        .ops = .rr_inst,
+        .data = .{ .b_type = .{
+            .rs1 = count,
+            .rs2 = .zero,
+            .inst = @intCast(func.mir_instructions.len + 9),
+        } },
+    });
+
     // lb tmp, 0(src)
     const first_inst = try func.addInst(.{
         .tag = .lb,
@@ -6145,7 +6211,9 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
                 } },
             });
         },
-        .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}),
+        // useful in cases like slice_ptr, which can easily reuse the operand
+        // but we need to get only the pointer out.
+        .register_pair => |pair| try func.genSetReg(ty, reg, .{ .register = pair[0] }),
         .load_frame => |frame| {
             if (reg.class() == .vector) {
                 // 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 {
         const src_lock = if (src_mcv.getReg()) |reg| func.register_manager.lockReg(reg) else null;
         defer if (src_lock) |lock| func.register_manager.unlockReg(lock);
 
-        const dst_mcv = if (dst_ty.abiSize(pt) <= src_ty.abiSize(pt) and
+        const dst_mcv = if (dst_ty.abiSize(pt) <= src_ty.abiSize(pt) and src_mcv != .register_pair and
             func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
             const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true);
             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 {
 }
 
 fn airMemcpy(func: *Func, inst: Air.Inst.Index) !void {
-    _ = inst;
-    return func.fail("TODO implement airMemcpy for {}", .{func.target.cpu.arch});
+    const pt = func.pt;
+    const zcu = pt.zcu;
+    const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
+
+    const dst_ptr = try func.resolveInst(bin_op.lhs);
+    const src_ptr = try func.resolveInst(bin_op.rhs);
+
+    const dst_ty = func.typeOf(bin_op.lhs);
+
+    const len_mcv: MCValue = switch (dst_ty.ptrSize(zcu)) {
+        .Slice => len: {
+            const len_reg, const len_lock = try func.allocReg(.int);
+            defer func.register_manager.unlockReg(len_lock);
+
+            const elem_size = dst_ty.childType(zcu).abiSize(pt);
+            try func.genBinOp(
+                .mul,
+                .{ .immediate = elem_size },
+                Type.u64,
+                dst_ptr.address().offset(8).deref(),
+                Type.u64,
+                len_reg,
+            );
+            break :len .{ .register = len_reg };
+        },
+        else => |size| return func.fail("TODO: airMemcpy size {s}", .{@tagName(size)}),
+    };
+    const len_lock: ?RegisterLock = switch (len_mcv) {
+        .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
+        else => null,
+    };
+    defer if (len_lock) |lock| func.register_manager.unlockReg(lock);
+
+    try func.genInlineMemcpy(dst_ptr, src_ptr, len_mcv);
+
+    return func.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
 }
 
 fn airTagName(func: *Func, inst: Air.Inst.Index) !void {