| ... | @@ -1122,7 +1122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1122,7 +1122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1122 | }, | 1122 | }, |
| 1123 | else => {}, | 1123 | else => {}, |
| 1124 | } | 1124 | } |
| 1125 | break :result try self.genBinOp(inst, ty_op.operand, .bool_true, true); | 1125 | break :result try self.genBinOp(.not, inst, ty_op.operand, .bool_true); |
| 1126 | }; | 1126 | }; |
| 1127 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1127 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1128 | } | 1128 | } |
| ... | @@ -1208,10 +1208,13 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1208,10 +1208,13 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1208 | | 1208 | |
| 1209 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | 1209 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1210 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1210 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1211 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1211 | |
| 1212 | .dead | 1212 | if (self.liveness.isUnused(inst)) { |
| 1213 | else | 1213 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1214 | try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); | 1214 | } |
| | 1215 | |
| | 1216 | const tag = self.air.instructions.items(.tag)[inst]; |
| | 1217 | const result = try self.genBinOp(tag, inst, bin_op.lhs, bin_op.rhs); |
| 1215 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1218 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1216 | } | 1219 | } |
| 1217 | | 1220 | |
| ... | @@ -1260,7 +1263,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1260,7 +1263,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1260 | try self.spillCompareFlagsIfOccupied(); | 1263 | try self.spillCompareFlagsIfOccupied(); |
| 1261 | self.compare_flags_inst = inst; | 1264 | self.compare_flags_inst = inst; |
| 1262 | | 1265 | |
| 1263 | const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); | 1266 | const partial = try self.genBinOp(.add, inst, bin_op.lhs, bin_op.rhs); |
| 1264 | const result: MCValue = switch (int_info.signedness) { | 1267 | const result: MCValue = switch (int_info.signedness) { |
| 1265 | .signed => .{ .register_overflow_signed = partial.register }, | 1268 | .signed => .{ .register_overflow_signed = partial.register }, |
| 1266 | .unsigned => .{ .register_overflow_unsigned = partial.register }, | 1269 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| ... | @@ -1292,7 +1295,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1292,7 +1295,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1292 | try self.spillCompareFlagsIfOccupied(); | 1295 | try self.spillCompareFlagsIfOccupied(); |
| 1293 | self.compare_flags_inst = inst; | 1296 | self.compare_flags_inst = inst; |
| 1294 | | 1297 | |
| 1295 | const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); | 1298 | const partial = try self.genBinOp(.sub, inst, bin_op.lhs, bin_op.rhs); |
| 1296 | const result: MCValue = switch (int_info.signedness) { | 1299 | const result: MCValue = switch (int_info.signedness) { |
| 1297 | .signed => .{ .register_overflow_signed = partial.register }, | 1300 | .signed => .{ .register_overflow_signed = partial.register }, |
| 1298 | .unsigned => .{ .register_overflow_unsigned = partial.register }, | 1301 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| ... | @@ -1329,7 +1332,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1329,7 +1332,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1329 | | 1332 | |
| 1330 | if (math.isPowerOfTwo(int_info.bits)) { | 1333 | if (math.isPowerOfTwo(int_info.bits)) { |
| 1331 | self.compare_flags_inst = inst; | 1334 | self.compare_flags_inst = inst; |
| 1332 | const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); | 1335 | const partial = try self.genBinOp(.mul, inst, bin_op.lhs, bin_op.rhs); |
| 1333 | break :result switch (int_info.signedness) { | 1336 | break :result switch (int_info.signedness) { |
| 1334 | .signed => MCValue{ .register_overflow_signed = partial.register }, | 1337 | .signed => MCValue{ .register_overflow_signed = partial.register }, |
| 1335 | .unsigned => MCValue{ .register_overflow_unsigned = partial.register }, | 1338 | .unsigned => MCValue{ .register_overflow_unsigned = partial.register }, |
| ... | @@ -1372,7 +1375,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1372,7 +1375,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1372 | break :dst_reg dst_reg; | 1375 | break :dst_reg dst_reg; |
| 1373 | }, | 1376 | }, |
| 1374 | .unsigned => { | 1377 | .unsigned => { |
| 1375 | const dst_mcv = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, false); | 1378 | const dst_mcv = try self.genBinOp(.mul, null, bin_op.lhs, bin_op.rhs); |
| 1376 | break :dst_reg dst_mcv.register; | 1379 | break :dst_reg dst_mcv.register; |
| 1377 | }, | 1380 | }, |
| 1378 | } | 1381 | } |
| ... | @@ -3211,16 +3214,14 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3211,16 +3214,14 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3211 | /// Result is always a register. | 3214 | /// Result is always a register. |
| 3212 | fn genBinOp( | 3215 | fn genBinOp( |
| 3213 | self: *Self, | 3216 | self: *Self, |
| 3214 | inst: Air.Inst.Index, | 3217 | tag: Air.Inst.Tag, |
| | 3218 | maybe_inst: ?Air.Inst.Index, |
| 3215 | op_lhs: Air.Inst.Ref, | 3219 | op_lhs: Air.Inst.Ref, |
| 3216 | op_rhs: Air.Inst.Ref, | 3220 | op_rhs: Air.Inst.Ref, |
| 3217 | track: bool, | | |
| 3218 | ) !MCValue { | 3221 | ) !MCValue { |
| 3219 | const tag = self.air.instructions.items(.tag)[inst]; | | |
| 3220 | const is_commutative: bool = switch (tag) { | 3222 | const is_commutative: bool = switch (tag) { |
| 3221 | .add, | 3223 | .add, |
| 3222 | .addwrap, | 3224 | .addwrap, |
| 3223 | .add_with_overflow, | | |
| 3224 | .bool_or, | 3225 | .bool_or, |
| 3225 | .bit_or, | 3226 | .bit_or, |
| 3226 | .bool_and, | 3227 | .bool_and, |
| ... | @@ -3231,10 +3232,8 @@ fn genBinOp( | ... | @@ -3231,10 +3232,8 @@ fn genBinOp( |
| 3231 | | 3232 | |
| 3232 | .sub, | 3233 | .sub, |
| 3233 | .subwrap, | 3234 | .subwrap, |
| 3234 | .sub_with_overflow, | | |
| 3235 | .mul, | 3235 | .mul, |
| 3236 | .mulwrap, | 3236 | .mulwrap, |
| 3237 | .mul_with_overflow, | | |
| 3238 | .shl, | 3237 | .shl, |
| 3239 | .shr, | 3238 | .shr, |
| 3240 | .ptr_add, | 3239 | .ptr_add, |
| ... | @@ -3256,10 +3255,9 @@ fn genBinOp( | ... | @@ -3256,10 +3255,9 @@ fn genBinOp( |
| 3256 | switch (tag) { | 3255 | switch (tag) { |
| 3257 | .mul, | 3256 | .mul, |
| 3258 | .mulwrap, | 3257 | .mulwrap, |
| 3259 | .mul_with_overflow, | | |
| 3260 | => { | 3258 | => { |
| 3261 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | 3259 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 3262 | try self.register_manager.getReg(.rax, if (track) inst else null); | 3260 | try self.register_manager.getReg(.rax, maybe_inst); |
| 3263 | try self.register_manager.getReg(.rdx, null); | 3261 | try self.register_manager.getReg(.rdx, null); |
| 3264 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); | 3262 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 3265 | defer for (reg_locks) |reg| { | 3263 | defer for (reg_locks) |reg| { |
| ... | @@ -3299,18 +3297,17 @@ fn genBinOp( | ... | @@ -3299,18 +3297,17 @@ fn genBinOp( |
| 3299 | | 3297 | |
| 3300 | var flipped: bool = false; | 3298 | var flipped: bool = false; |
| 3301 | const dst_mcv: MCValue = blk: { | 3299 | const dst_mcv: MCValue = blk: { |
| 3302 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { | 3300 | if (maybe_inst) |inst| { |
| 3303 | break :blk lhs; | 3301 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { |
| 3304 | } | 3302 | break :blk lhs; |
| 3305 | if (is_commutative and self.reuseOperand(inst, op_rhs, 1, rhs) and rhs.isRegister()) { | 3303 | } |
| 3306 | flipped = true; | 3304 | if (is_commutative and self.reuseOperand(inst, op_rhs, 1, rhs) and rhs.isRegister()) { |
| 3307 | break :blk rhs; | 3305 | flipped = true; |
| 3308 | } | 3306 | break :blk rhs; |
| 3309 | if (track) { | 3307 | } |
| 3310 | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); | 3308 | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); |
| 3311 | } else { | | |
| 3312 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) }; | | |
| 3313 | } | 3309 | } |
| | 3310 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) }; |
| 3314 | }; | 3311 | }; |
| 3315 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { | 3312 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 3316 | .register => |reg| self.register_manager.lockReg(reg), | 3313 | .register => |reg| self.register_manager.lockReg(reg), |
| ... | @@ -3332,12 +3329,10 @@ fn genBinOp( | ... | @@ -3332,12 +3329,10 @@ fn genBinOp( |
| 3332 | switch (tag) { | 3329 | switch (tag) { |
| 3333 | .add, | 3330 | .add, |
| 3334 | .addwrap, | 3331 | .addwrap, |
| 3335 | .add_with_overflow, | | |
| 3336 | => try self.genBinOpMir(.add, dst_ty, dst_mcv, src_mcv), | 3332 | => try self.genBinOpMir(.add, dst_ty, dst_mcv, src_mcv), |
| 3337 | | 3333 | |
| 3338 | .sub, | 3334 | .sub, |
| 3339 | .subwrap, | 3335 | .subwrap, |
| 3340 | .sub_with_overflow, | | |
| 3341 | => try self.genBinOpMir(.sub, dst_ty, dst_mcv, src_mcv), | 3336 | => try self.genBinOpMir(.sub, dst_ty, dst_mcv, src_mcv), |
| 3342 | | 3337 | |
| 3343 | .ptr_add, | 3338 | .ptr_add, |
| ... | @@ -3353,9 +3348,18 @@ fn genBinOp( | ... | @@ -3353,9 +3348,18 @@ fn genBinOp( |
| 3353 | try self.genBinOpMir(mir_tag, dst_ty, dst_mcv, src_mcv); | 3348 | try self.genBinOpMir(mir_tag, dst_ty, dst_mcv, src_mcv); |
| 3354 | }, | 3349 | }, |
| 3355 | | 3350 | |
| 3356 | .bool_or, .bit_or => try self.genBinOpMir(.@"or", dst_ty, dst_mcv, src_mcv), | 3351 | .bool_or, |
| 3357 | .bool_and, .bit_and => try self.genBinOpMir(.@"and", dst_ty, dst_mcv, src_mcv), | 3352 | .bit_or, |
| 3358 | .xor, .not => try self.genBinOpMir(.xor, dst_ty, dst_mcv, src_mcv), | 3353 | => try self.genBinOpMir(.@"or", dst_ty, dst_mcv, src_mcv), |
| | 3354 | |
| | 3355 | .bool_and, |
| | 3356 | .bit_and, |
| | 3357 | => try self.genBinOpMir(.@"and", dst_ty, dst_mcv, src_mcv), |
| | 3358 | |
| | 3359 | .xor, |
| | 3360 | .not, |
| | 3361 | => try self.genBinOpMir(.xor, dst_ty, dst_mcv, src_mcv), |
| | 3362 | |
| 3359 | else => unreachable, | 3363 | else => unreachable, |
| 3360 | } | 3364 | } |
| 3361 | return dst_mcv; | 3365 | return dst_mcv; |