authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-07-15 04:01:44-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-07-26 04:05:42-07:00
log1820f4410450a0dfa35eafefa217465f762e26fd
tree918171f7eb741fb72c0dd1a930982687249d5543
parent81ca3a1d594cb25dcd7dbedf175dd9931cad0d0f
signaturelock-open Commit is signed but in an unrecognized format.

riscv: implement sub-byte addition


4 files changed, 73 insertions(+), 14 deletions(-)

src/arch/riscv64/CodeGen.zig+73-9
......@@ -2757,12 +2757,14 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
27572757 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
27582758 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
27592759
2760 const rhs_ty = func.typeOf(extra.rhs);
2761 const lhs_ty = func.typeOf(extra.lhs);
2762
27602763 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2761 const ty = func.typeOf(extra.lhs);
2762 switch (ty.zigTypeTag(zcu)) {
2764 switch (lhs_ty.zigTypeTag(zcu)) {
27632765 .Vector => return func.fail("TODO implement add with overflow for Vector type", .{}),
27642766 .Int => {
2765 const int_info = ty.intInfo(zcu);
2767 const int_info = lhs_ty.intInfo(zcu);
27662768
27672769 const tuple_ty = func.typeOfIndex(inst);
27682770 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
......@@ -2774,11 +2776,11 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
27742776 try func.genSetMem(
27752777 .{ .frame = offset.index },
27762778 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))),
2777 ty,
2779 lhs_ty,
27782780 add_result,
27792781 );
27802782
2781 const trunc_reg = try func.copyToTmpRegister(ty, add_result);
2783 const trunc_reg = try func.copyToTmpRegister(lhs_ty, add_result);
27822784 const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg);
27832785 defer func.register_manager.unlockReg(trunc_reg_lock);
27842786
......@@ -2787,13 +2789,13 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
27872789
27882790 // if the result isn't equal after truncating it to the given type,
27892791 // an overflow must have happened.
2790 try func.truncateRegister(func.typeOf(extra.lhs), trunc_reg);
2792 try func.truncateRegister(lhs_ty, trunc_reg);
27912793 try func.genBinOp(
27922794 .cmp_neq,
27932795 add_result,
2794 ty,
2796 lhs_ty,
27952797 .{ .register = trunc_reg },
2796 ty,
2798 rhs_ty,
27972799 overflow_reg,
27982800 );
27992801
......@@ -2806,7 +2808,69 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
28062808
28072809 break :result result_mcv;
28082810 } else {
2809 return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{});
2811 const rhs_mcv = try func.resolveInst(extra.rhs);
2812 const lhs_mcv = try func.resolveInst(extra.lhs);
2813
2814 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs_mcv);
2815 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs_mcv);
2816 defer {
2817 if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
2818 if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
2819 }
2820
2821 try func.truncateRegister(rhs_ty, rhs_reg);
2822 try func.truncateRegister(lhs_ty, lhs_reg);
2823
2824 const dest_reg, const dest_lock = try func.allocReg(.int);
2825 defer func.register_manager.unlockReg(dest_lock);
2826
2827 _ = try func.addInst(.{
2828 .tag = .add,
2829 .ops = .rrr,
2830 .data = .{ .r_type = .{
2831 .rs1 = rhs_reg,
2832 .rs2 = lhs_reg,
2833 .rd = dest_reg,
2834 } },
2835 });
2836
2837 try func.truncateRegister(func.typeOfIndex(inst), dest_reg);
2838 const add_result: MCValue = .{ .register = dest_reg };
2839
2840 try func.genSetMem(
2841 .{ .frame = offset.index },
2842 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))),
2843 lhs_ty,
2844 add_result,
2845 );
2846
2847 const trunc_reg = try func.copyToTmpRegister(lhs_ty, add_result);
2848 const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg);
2849 defer func.register_manager.unlockReg(trunc_reg_lock);
2850
2851 const overflow_reg, const overflow_lock = try func.allocReg(.int);
2852 defer func.register_manager.unlockReg(overflow_lock);
2853
2854 // if the result isn't equal after truncating it to the given type,
2855 // an overflow must have happened.
2856 try func.truncateRegister(lhs_ty, trunc_reg);
2857 try func.genBinOp(
2858 .cmp_neq,
2859 add_result,
2860 lhs_ty,
2861 .{ .register = trunc_reg },
2862 rhs_ty,
2863 overflow_reg,
2864 );
2865
2866 try func.genSetMem(
2867 .{ .frame = offset.index },
2868 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))),
2869 Type.u1,
2870 .{ .register = overflow_reg },
2871 );
2872
2873 break :result result_mcv;
28102874 }
28112875 },
28122876 else => unreachable,
test/behavior/array.zig-2
......@@ -773,8 +773,6 @@ test "array init with no result pointer sets field result types" {
773773}
774774
775775test "runtime side-effects in comptime-known array init" {
776 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
777
778776 var side_effects: u4 = 0;
779777 const init = [4]u4{
780778 blk: {
test/behavior/packed-struct.zig-1
......@@ -1274,7 +1274,6 @@ test "2-byte packed struct argument in C calling convention" {
12741274 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
12751275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
12761276 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1277 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12781277
12791278 const S = packed struct(u16) {
12801279 x: u15 = 0,
test/behavior/struct.zig-2
......@@ -1768,8 +1768,6 @@ test "struct init with no result pointer sets field result types" {
17681768}
17691769
17701770test "runtime side-effects in comptime-known struct init" {
1771 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1772
17731771 var side_effects: u4 = 0;
17741772 const S = struct { a: u4, b: u4, c: u4, d: u4 };
17751773 const init = S{