authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-03-25 05:15:02-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
logb28c966e332623dc43b1481b34016d18ce3262fa
treecd000795a0eee123ca83928ce0aedabcfff9165a
parente70584e2f87ae8daab18d9e28f72dac020d7702e

riscv: fix overflow checks in addition.


3 files changed, 61 insertions(+), 7 deletions(-)

src/arch/riscv64/CodeGen.zig+44-4
......@@ -1019,6 +1019,7 @@ fn binOpRegister(
10191019 .add => .add,
10201020 .sub => .sub,
10211021 .cmp_eq => .cmp_eq,
1022 .cmp_neq => .cmp_neq,
10221023 .cmp_gt => .cmp_gt,
10231024 .cmp_gte => .cmp_gte,
10241025 .cmp_lt => .cmp_lt,
......@@ -1185,6 +1186,8 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
11851186 const rhs_ty = self.typeOf(extra.rhs);
11861187
11871188 const add_result_mcv = try self.binOp(.add, null, lhs, rhs, lhs_ty, rhs_ty);
1189 const add_result_lock = self.register_manager.lockRegAssumeUnused(add_result_mcv.register);
1190 defer self.register_manager.unlockReg(add_result_lock);
11881191
11891192 const tuple_ty = self.typeOfIndex(inst);
11901193 const int_info = lhs_ty.intInfo(mod);
......@@ -1196,15 +1199,44 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
11961199
11971200 const result_offset = tuple_ty.structFieldOffset(0, mod) + offset;
11981201
1199 // set the result first as we don't have a lock on the add_result_mcv register and it will
1200 // get clobbered in the next binOp.
12011202 try self.genSetStack(lhs_ty, @intCast(result_offset), add_result_mcv);
12021203
12031204 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
12041205 if (int_info.signedness == .unsigned) {
12051206 const overflow_offset = tuple_ty.structFieldOffset(1, mod) + offset;
12061207
1207 const overflow_mcv = try self.binOp(.cmp_lt, null, add_result_mcv, lhs, lhs_ty, lhs_ty);
1208 const max_val = std.math.pow(u16, 2, int_info.bits) - 1;
1209
1210 const overflow_reg, const overflow_lock = try self.allocReg();
1211 defer self.register_manager.unlockReg(overflow_lock);
1212
1213 const add_reg, const add_lock = blk: {
1214 if (add_result_mcv == .register) break :blk .{ add_result_mcv.register, null };
1215
1216 const add_reg, const add_lock = try self.allocReg();
1217 try self.genSetReg(lhs_ty, add_reg, add_result_mcv);
1218 break :blk .{ add_reg, add_lock };
1219 };
1220 defer if (add_lock) |lock| self.register_manager.unlockReg(lock);
1221
1222 _ = try self.addInst(.{
1223 .tag = .andi,
1224 .data = .{ .i_type = .{
1225 .rd = overflow_reg,
1226 .rs1 = add_reg,
1227 .imm12 = @intCast(max_val),
1228 } },
1229 });
1230
1231 const overflow_mcv = try self.binOp(
1232 .cmp_neq,
1233 null,
1234 .{ .register = overflow_reg },
1235 .{ .register = add_reg },
1236 lhs_ty,
1237 lhs_ty,
1238 );
1239
12081240 try self.genSetStack(Type.u1, @intCast(overflow_offset), overflow_mcv);
12091241
12101242 break :result result_mcv;
......@@ -3042,7 +3074,15 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_val: MCValue) InnerError!
30423074
30433075fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) !void {
30443076 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3045 const result = try self.resolveInst(un_op);
3077 const result = result: {
3078 const src_mcv = try self.resolveInst(un_op);
3079 if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv;
3080
3081 const dst_mcv = try self.allocRegOrMem(inst, true);
3082 const dst_ty = self.typeOfIndex(inst);
3083 try self.setValue(dst_ty, dst_mcv, src_mcv);
3084 break :result dst_mcv;
3085 };
30463086 return self.finishAir(inst, result, .{ un_op, .none, .none });
30473087}
30483088
src/arch/riscv64/Emit.zig+12-3
......@@ -58,6 +58,7 @@ pub fn emitMir(
5858 .@"or" => try emit.mirRType(inst),
5959
6060 .cmp_eq => try emit.mirRType(inst),
61 .cmp_neq => try emit.mirRType(inst),
6162 .cmp_gt => try emit.mirRType(inst),
6263 .cmp_gte => try emit.mirRType(inst),
6364 .cmp_lt => try emit.mirRType(inst),
......@@ -68,6 +69,7 @@ pub fn emitMir(
6869 .bne => try emit.mirBType(inst),
6970
7071 .addi => try emit.mirIType(inst),
72 .andi => try emit.mirIType(inst),
7173 .jalr => try emit.mirIType(inst),
7274 .abs => try emit.mirIType(inst),
7375
......@@ -201,10 +203,14 @@ fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void {
201203 .cmp_eq => {
202204 // rs1 == rs2
203205
204 // if equal, write 0 to rd
205206 try emit.writeInstruction(Instruction.xor(rd, rs1, rs2));
206 // if rd == 0, set rd to 1
207 try emit.writeInstruction(Instruction.sltiu(rd, rd, 1));
207 try emit.writeInstruction(Instruction.sltiu(rd, rd, 1)); // seqz
208 },
209 .cmp_neq => {
210 // rs1 != rs2
211
212 try emit.writeInstruction(Instruction.xor(rd, rs1, rs2));
213 try emit.writeInstruction(Instruction.sltu(rd, .x0, rd)); // snez
208214 },
209215 .cmp_lt => {
210216 // rd = 1 if rs1 < rs2
......@@ -255,6 +261,8 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
255261 .addi => try emit.writeInstruction(Instruction.addi(rd, rs1, imm12)),
256262 .jalr => try emit.writeInstruction(Instruction.jalr(rd, imm12, rs1)),
257263
264 .andi => try emit.writeInstruction(Instruction.andi(rd, rs1, imm12)),
265
258266 .ld => try emit.writeInstruction(Instruction.ld(rd, imm12, rs1)),
259267 .lw => try emit.writeInstruction(Instruction.lw(rd, imm12, rs1)),
260268 .lh => try emit.writeInstruction(Instruction.lh(rd, imm12, rs1)),
......@@ -515,6 +523,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
515523 => 12,
516524
517525 .cmp_eq,
526 .cmp_neq,
518527 .cmp_imm_eq,
519528 .cmp_gte,
520529 .load_symbol,
src/arch/riscv64/Mir.zig+5
......@@ -57,9 +57,14 @@ pub const Inst = struct {
5757 /// Jumps. Uses `inst` payload.
5858 j,
5959
60 /// Immediate and, uses i_type payload
61 andi,
62
6063 // NOTE: Maybe create a special data for compares that includes the ops
6164 /// Register `==`, uses r_type
6265 cmp_eq,
66 /// Register `!=`, uses r_type
67 cmp_neq,
6368 /// Register `>`, uses r_type
6469 cmp_gt,
6570 /// Register `<`, uses r_type