| ... | ... | @@ -1019,6 +1019,7 @@ fn binOpRegister( |
| 1019 | 1019 | .add => .add, |
| 1020 | 1020 | .sub => .sub, |
| 1021 | 1021 | .cmp_eq => .cmp_eq, |
| 1022 | .cmp_neq => .cmp_neq, |
| 1022 | 1023 | .cmp_gt => .cmp_gt, |
| 1023 | 1024 | .cmp_gte => .cmp_gte, |
| 1024 | 1025 | .cmp_lt => .cmp_lt, |
| ... | ... | @@ -1185,6 +1186,8 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1185 | 1186 | const rhs_ty = self.typeOf(extra.rhs); |
| 1186 | 1187 | |
| 1187 | 1188 | 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); |
| 1188 | 1191 | |
| 1189 | 1192 | const tuple_ty = self.typeOfIndex(inst); |
| 1190 | 1193 | const int_info = lhs_ty.intInfo(mod); |
| ... | ... | @@ -1196,15 +1199,44 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1196 | 1199 | |
| 1197 | 1200 | const result_offset = tuple_ty.structFieldOffset(0, mod) + offset; |
| 1198 | 1201 | |
| 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. |
| 1201 | 1202 | try self.genSetStack(lhs_ty, @intCast(result_offset), add_result_mcv); |
| 1202 | 1203 | |
| 1203 | 1204 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 1204 | 1205 | if (int_info.signedness == .unsigned) { |
| 1205 | 1206 | const overflow_offset = tuple_ty.structFieldOffset(1, mod) + offset; |
| 1206 | 1207 | |
| 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 | |
| 1208 | 1240 | try self.genSetStack(Type.u1, @intCast(overflow_offset), overflow_mcv); |
| 1209 | 1241 | |
| 1210 | 1242 | break :result result_mcv; |
| ... | ... | @@ -3042,7 +3074,15 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_val: MCValue) InnerError! |
| 3042 | 3074 | |
| 3043 | 3075 | fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3044 | 3076 | 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 | }; |
| 3046 | 3086 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 3047 | 3087 | } |
| 3048 | 3088 | |