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, diff --git a/test/behavior/array.zig b/test/behavior/array.zig index 4520fdde68..05da574edf 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -773,8 +773,6 @@ test "array init with no result pointer sets field result types" { } test "runtime side-effects in comptime-known array init" { - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - var side_effects: u4 = 0; const init = [4]u4{ blk: { diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index a6712d04ed..5b449ab8fc 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -1274,7 +1274,6 @@ test "2-byte packed struct argument in C calling convention" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = packed struct(u16) { x: u15 = 0, diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 38bbd4b0c4..7fdf7b489a 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -1768,8 +1768,6 @@ test "struct init with no result pointer sets field result types" { } test "runtime side-effects in comptime-known struct init" { - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - var side_effects: u4 = 0; const S = struct { a: u4, b: u4, c: u4, d: u4 }; const init = S{