aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Rubin <daviru007@icloud.com>2024-07-15 04:01:44 -0700
committerDavid Rubin <daviru007@icloud.com>2024-07-26 04:05:42 -0700
commit1820f4410450a0dfa35eafefa217465f762e26fd (patch)
tree918171f7eb741fb72c0dd1a930982687249d5543 /src
parent81ca3a1d594cb25dcd7dbedf175dd9931cad0d0f (diff)
downloadzig-1820f4410450a0dfa35eafefa217465f762e26fd.tar.gz
zig-1820f4410450a0dfa35eafefa217465f762e26fd.zip
riscv: implement sub-byte addition
Diffstat (limited to 'src')
-rw-r--r--src/arch/riscv64/CodeGen.zig82
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,