diff options
| author | David Rubin <daviru007@icloud.com> | 2024-07-15 04:01:44 -0700 |
|---|---|---|
| committer | David Rubin <daviru007@icloud.com> | 2024-07-26 04:05:42 -0700 |
| commit | 1820f4410450a0dfa35eafefa217465f762e26fd (patch) | |
| tree | 918171f7eb741fb72c0dd1a930982687249d5543 /src | |
| parent | 81ca3a1d594cb25dcd7dbedf175dd9931cad0d0f (diff) | |
| download | zig-1820f4410450a0dfa35eafefa217465f762e26fd.tar.gz zig-1820f4410450a0dfa35eafefa217465f762e26fd.zip | |
riscv: implement sub-byte addition
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/riscv64/CodeGen.zig | 82 |
1 files changed, 73 insertions, 9 deletions
diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index beff7ec879..9e5412fbc9 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -2757,12 +2757,14 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; + const rhs_ty = func.typeOf(extra.rhs); + const lhs_ty = func.typeOf(extra.lhs); + const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { - const ty = func.typeOf(extra.lhs); - switch (ty.zigTypeTag(zcu)) { + switch (lhs_ty.zigTypeTag(zcu)) { .Vector => return func.fail("TODO implement add with overflow for Vector type", .{}), .Int => { - const int_info = ty.intInfo(zcu); + const int_info = lhs_ty.intInfo(zcu); const tuple_ty = func.typeOfIndex(inst); const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false); @@ -2774,11 +2776,11 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { try func.genSetMem( .{ .frame = offset.index }, offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))), - ty, + lhs_ty, add_result, ); - const trunc_reg = try func.copyToTmpRegister(ty, add_result); + const trunc_reg = try func.copyToTmpRegister(lhs_ty, add_result); const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg); defer func.register_manager.unlockReg(trunc_reg_lock); @@ -2787,13 +2789,13 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { // if the result isn't equal after truncating it to the given type, // an overflow must have happened. - try func.truncateRegister(func.typeOf(extra.lhs), trunc_reg); + try func.truncateRegister(lhs_ty, trunc_reg); try func.genBinOp( .cmp_neq, add_result, - ty, + lhs_ty, .{ .register = trunc_reg }, - ty, + rhs_ty, overflow_reg, ); @@ -2806,7 +2808,69 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { break :result result_mcv; } else { - return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{}); + const rhs_mcv = try func.resolveInst(extra.rhs); + const lhs_mcv = try func.resolveInst(extra.lhs); + + const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs_mcv); + const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs_mcv); + defer { + if (rhs_lock) |lock| func.register_manager.unlockReg(lock); + if (lhs_lock) |lock| func.register_manager.unlockReg(lock); + } + + try func.truncateRegister(rhs_ty, rhs_reg); + try func.truncateRegister(lhs_ty, lhs_reg); + + const dest_reg, const dest_lock = try func.allocReg(.int); + defer func.register_manager.unlockReg(dest_lock); + + _ = try func.addInst(.{ + .tag = .add, + .ops = .rrr, + .data = .{ .r_type = .{ + .rs1 = rhs_reg, + .rs2 = lhs_reg, + .rd = dest_reg, + } }, + }); + + try func.truncateRegister(func.typeOfIndex(inst), dest_reg); + const add_result: MCValue = .{ .register = dest_reg }; + + try func.genSetMem( + .{ .frame = offset.index }, + offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))), + lhs_ty, + add_result, + ); + + const trunc_reg = try func.copyToTmpRegister(lhs_ty, add_result); + const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg); + defer func.register_manager.unlockReg(trunc_reg_lock); + + const overflow_reg, const overflow_lock = try func.allocReg(.int); + defer func.register_manager.unlockReg(overflow_lock); + + // if the result isn't equal after truncating it to the given type, + // an overflow must have happened. + try func.truncateRegister(lhs_ty, trunc_reg); + try func.genBinOp( + .cmp_neq, + add_result, + lhs_ty, + .{ .register = trunc_reg }, + rhs_ty, + overflow_reg, + ); + + try func.genSetMem( + .{ .frame = offset.index }, + offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))), + Type.u1, + .{ .register = overflow_reg }, + ); + + break :result result_mcv; } }, else => unreachable, |
