authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-09 22:31:36+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-09 22:31:36+02:00
log20e7f1218b997e3da5d10cb5d038ed782d772716
tree23be728df99e0102bf6fae759b86dd1349b41d19
parent9c3d24ea0bffa53fb08a73493d72a6a0866f6432

x64: make one entry point for binary ops

* rename `genBinMathOp` into `genBinOp` and handle commutativity * rename `genBinMathOpMir` into `genBinOpMir`

1 files changed, 113 insertions(+), 210 deletions(-)

src/arch/x86_64/CodeGen.zig+113-210
......@@ -586,11 +586,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
586586
587587 switch (air_tags[inst]) {
588588 // zig fmt: off
589 .add => try self.airAdd(inst),
590 .addwrap => try self.airAdd(inst),
589 .add => try self.airBinOp(inst),
590 .addwrap => try self.airBinOp(inst),
591591 .add_sat => try self.airAddSat(inst),
592 .sub => try self.airSub(inst),
593 .subwrap => try self.airSub(inst),
592 .sub => try self.airBinOp(inst),
593 .subwrap => try self.airBinOp(inst),
594594 .sub_sat => try self.airSubSat(inst),
595595 .mul => try self.airMul(inst),
596596 .mulwrap => try self.airMul(inst),
......@@ -601,8 +601,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
601601 .shl_sat => try self.airShlSat(inst),
602602 .min => try self.airMin(inst),
603603 .max => try self.airMax(inst),
604 .ptr_add => try self.airPtrAdd(inst),
605 .ptr_sub => try self.airPtrSub(inst),
604 .ptr_add => try self.airBinOp(inst),
605 .ptr_sub => try self.airBinOp(inst),
606606 .slice => try self.airSlice(inst),
607607
608608 .sqrt,
......@@ -638,11 +638,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
638638 .cmp_vector => try self.airCmpVector(inst),
639639 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
640640
641 .bool_and => try self.airBoolOp(inst),
642 .bool_or => try self.airBoolOp(inst),
643 .bit_and => try self.airBitAnd(inst),
644 .bit_or => try self.airBitOr(inst),
645 .xor => try self.airXor(inst),
641 .bool_and => try self.airBinOp(inst),
642 .bool_or => try self.airBinOp(inst),
643 .bit_and => try self.airBinOp(inst),
644 .bit_or => try self.airBinOp(inst),
645 .xor => try self.airBinOp(inst),
646646 .shr, .shr_exact => try self.airShr(inst),
647647
648648 .alloc => try self.airAlloc(inst),
......@@ -1122,7 +1122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11221122 },
11231123 else => {},
11241124 }
1125 break :result try self.genBinMathOp(inst, ty_op.operand, .bool_true);
1125 break :result try self.genBinOp(inst, ty_op.operand, .bool_true);
11261126 };
11271127 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11281128}
......@@ -1159,7 +1159,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
11591159 };
11601160 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
11611161
1162 try self.genBinMathOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv);
1162 try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv);
11631163
11641164 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);
11651165 _ = try self.addInst(.{
......@@ -1185,63 +1185,12 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void {
11851185 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
11861186}
11871187
1188fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
1189 const dst_ty = self.air.typeOfIndex(inst);
1190 const elem_size = dst_ty.elemType2().abiSize(self.target.*);
1191 const ptr = try self.resolveInst(op_lhs);
1192 const offset = try self.resolveInst(op_rhs);
1193 const offset_ty = self.air.typeOf(op_rhs);
1194
1195 const offset_lock: ?RegisterLock = switch (offset) {
1196 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1197 else => null,
1198 };
1199 defer if (offset_lock) |lock| self.register_manager.unlockReg(lock);
1200
1201 const dst_mcv: MCValue = blk: {
1202 if (self.reuseOperand(inst, op_lhs, 0, ptr)) {
1203 if (ptr.isMemory() or ptr.isRegister()) break :blk ptr;
1204 }
1205 break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, ptr) };
1206 };
1207
1208 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
1209 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1210 else => null,
1211 };
1212 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
1213
1214 const offset_mcv: MCValue = blk: {
1215 if (self.reuseOperand(inst, op_rhs, 1, offset)) {
1216 if (offset.isRegister()) break :blk offset;
1217 }
1218 break :blk MCValue{ .register = try self.copyToTmpRegister(offset_ty, offset) };
1219 };
1220
1221 const offset_mcv_lock: ?RegisterLock = switch (offset_mcv) {
1222 .register => |reg| self.register_manager.lockReg(reg),
1223 else => null,
1224 };
1225 defer if (offset_mcv_lock) |lock| self.register_manager.unlockReg(lock);
1226
1227 try self.genIntMulComplexOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size });
1228
1229 const tag = self.air.instructions.items(.tag)[inst];
1230 switch (tag) {
1231 .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, offset_mcv),
1232 .ptr_sub => try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, offset_mcv),
1233 else => unreachable,
1234 }
1235
1236 return dst_mcv;
1237}
1238
12391188fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void {
12401189 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
12411190 const result = if (self.liveness.isUnused(inst))
12421191 .dead
12431192 else
1244 try self.genPtrBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1193 try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);
12451194 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12461195}
12471196
......@@ -1250,7 +1199,7 @@ fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void {
12501199 const result = if (self.liveness.isUnused(inst))
12511200 .dead
12521201 else
1253 try self.genPtrBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1202 try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);
12541203 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12551204}
12561205
......@@ -1275,21 +1224,12 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
12751224 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12761225}
12771226
1278fn airAdd(self: *Self, inst: Air.Inst.Index) !void {
1279 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1280 const result: MCValue = if (self.liveness.isUnused(inst))
1281 .dead
1282 else
1283 try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1284 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1285}
1286
1287fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void {
1227fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
12881228 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
12891229 const result: MCValue = if (self.liveness.isUnused(inst))
12901230 .dead
12911231 else
1292 try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1232 try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);
12931233 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12941234}
12951235
......@@ -1302,60 +1242,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
13021242 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
13031243}
13041244
1305/// Result is always a register.
1306fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
1307 const dst_ty = self.air.typeOf(op_lhs);
1308
1309 const lhs = try self.resolveInst(op_lhs);
1310 const lhs_lock: ?RegisterLock = switch (lhs) {
1311 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1312 else => null,
1313 };
1314 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
1315
1316 const rhs = try self.resolveInst(op_rhs);
1317 const rhs_lock: ?RegisterLock = switch (rhs) {
1318 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1319 else => null,
1320 };
1321 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
1322
1323 const dst_mcv: MCValue = blk: {
1324 if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) {
1325 break :blk lhs;
1326 }
1327 break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs);
1328 };
1329 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
1330 .register => |reg| self.register_manager.lockReg(reg),
1331 else => null,
1332 };
1333 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
1334
1335 const rhs_mcv: MCValue = blk: {
1336 if (rhs.isMemory() or rhs.isRegister()) break :blk rhs;
1337 break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) };
1338 };
1339 const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) {
1340 .register => |reg| self.register_manager.lockReg(reg),
1341 else => null,
1342 };
1343 defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock);
1344
1345 try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, rhs_mcv);
1346
1347 return dst_mcv;
1348}
1349
1350fn airSub(self: *Self, inst: Air.Inst.Index) !void {
1351 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1352 const result: MCValue = if (self.liveness.isUnused(inst))
1353 .dead
1354 else
1355 try self.genSubOp(inst, bin_op.lhs, bin_op.rhs);
1356 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1357}
1358
13591245fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
13601246 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
13611247 const result: MCValue = if (self.liveness.isUnused(inst))
......@@ -1422,7 +1308,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
14221308 try self.spillCompareFlagsIfOccupied();
14231309 self.compare_flags_inst = inst;
14241310
1425 const partial = try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1311 const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);
14261312 const result: MCValue = switch (int_info.signedness) {
14271313 .signed => .{ .register_overflow_signed = partial.register },
14281314 .unsigned => .{ .register_overflow_unsigned = partial.register },
......@@ -1454,7 +1340,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
14541340 try self.spillCompareFlagsIfOccupied();
14551341 self.compare_flags_inst = inst;
14561342
1457 const partial = try self.genSubOp(inst, bin_op.lhs, bin_op.rhs);
1343 const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);
14581344 const result: MCValue = switch (int_info.signedness) {
14591345 .signed => .{ .register_overflow_signed = partial.register },
14601346 .unsigned => .{ .register_overflow_unsigned = partial.register },
......@@ -1605,7 +1491,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
16051491 const scratch_reg = temp_regs[1];
16061492 try self.genSetReg(extended_ty, scratch_reg, .{ .register = dst_reg });
16071493 try self.truncateRegister(ty, scratch_reg);
1608 try self.genBinMathOpMir(
1494 try self.genBinOpMir(
16091495 .cmp,
16101496 extended_ty,
16111497 .{ .register = dst_reg },
......@@ -1622,7 +1508,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
16221508 .data = undefined,
16231509 });
16241510
1625 try self.genBinMathOpMir(
1511 try self.genBinOpMir(
16261512 .@"or",
16271513 Type.u8,
16281514 .{ .register = overflow_reg },
......@@ -1781,7 +1667,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
17811667 }).encode(),
17821668 .data = undefined,
17831669 });
1784 try self.genBinMathOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });
1670 try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });
17851671 return MCValue{ .register = divisor };
17861672}
17871673
......@@ -1945,7 +1831,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void {
19451831 try self.genIntMulComplexOpMir(ty, div_floor, rhs);
19461832
19471833 const result = try self.copyToRegisterWithInstTracking(inst, ty, lhs);
1948 try self.genBinMathOpMir(.sub, ty, result, div_floor);
1834 try self.genBinOpMir(.sub, ty, result, div_floor);
19491835
19501836 break :result result;
19511837 },
......@@ -1955,33 +1841,6 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void {
19551841 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
19561842}
19571843
1958fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void {
1959 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1960 const result: MCValue = if (self.liveness.isUnused(inst))
1961 .dead
1962 else
1963 try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1964 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1965}
1966
1967fn airBitOr(self: *Self, inst: Air.Inst.Index) !void {
1968 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1969 const result: MCValue = if (self.liveness.isUnused(inst))
1970 .dead
1971 else
1972 try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1973 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1974}
1975
1976fn airXor(self: *Self, inst: Air.Inst.Index) !void {
1977 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1978 const result: MCValue = if (self.liveness.isUnused(inst))
1979 .dead
1980 else
1981 try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1982 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1983}
1984
19851844fn airShl(self: *Self, inst: Air.Inst.Index) !void {
19861845 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
19871846 if (self.liveness.isUnused(inst)) {
......@@ -1989,6 +1848,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void {
19891848 }
19901849
19911850 const ty = self.air.typeOfIndex(inst);
1851
19921852 const tag = self.air.instructions.items(.tag)[inst];
19931853 switch (tag) {
19941854 .shl_exact => return self.fail("TODO implement {} for type {}", .{ tag, ty.fmtDebug() }),
......@@ -2470,7 +2330,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
24702330 }
24712331 // TODO we could allocate register here, but need to expect addr register and potentially
24722332 // offset register.
2473 try self.genBinMathOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg }, .{
2333 try self.genBinOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg }, .{
24742334 .register = offset_reg,
24752335 });
24762336 return MCValue{ .register = addr_reg.to64() };
......@@ -2573,7 +2433,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
25732433 // TODO we could allocate register here, but need to expect addr register and potentially
25742434 // offset register.
25752435 const dst_mcv = try self.allocRegOrMem(inst, false);
2576 try self.genBinMathOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg });
2436 try self.genBinOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg });
25772437 try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty);
25782438
25792439 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -2613,7 +2473,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
26132473 defer self.register_manager.unlockReg(offset_reg_lock);
26142474
26152475 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
2616 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
2476 try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
26172477
26182478 const result: MCValue = result: {
26192479 if (elem_abi_size > 8) {
......@@ -2667,7 +2527,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
26672527 defer self.register_manager.unlockReg(offset_reg_lock);
26682528
26692529 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
2670 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
2530 try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
26712531
26722532 return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });
26732533}
......@@ -2700,7 +2560,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
27002560 const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: {
27012561 // TODO reusing the operand
27022562 const reg = try self.copyToTmpRegister(ptr_ty, ptr);
2703 try self.genBinMathOpMir(.add, ptr_ty, .{ .register = reg }, .{ .immediate = layout.payload_size });
2563 try self.genBinOpMir(.add, ptr_ty, .{ .register = reg }, .{ .immediate = layout.payload_size });
27042564 break :blk MCValue{ .register = reg };
27052565 } else ptr;
27062566
......@@ -3267,7 +3127,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
32673127 defer self.register_manager.unlockReg(offset_reg_lock);
32683128
32693129 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, mcv);
3270 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
3130 try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
32713131 break :result dst_mcv;
32723132 },
32733133 .ptr_stack_offset => |off| {
......@@ -3297,7 +3157,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
32973157 const result_reg_lock = self.register_manager.lockReg(result_reg);
32983158 defer if (result_reg_lock) |lock| self.register_manager.unlockReg(lock);
32993159
3300 try self.genBinMathOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg });
3160 try self.genBinOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg });
33013161 break :result MCValue{ .register = result_reg };
33023162 },
33033163 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
......@@ -3357,7 +3217,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
33573217 const mask = (~@as(u64, 0)) >> mask_shift;
33583218
33593219 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
3360 try self.genBinMathOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg });
3220 try self.genBinOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg });
33613221
33623222 const signedness: std.builtin.Signedness = blk: {
33633223 if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned;
......@@ -3426,8 +3286,39 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
34263286}
34273287
34283288/// Result is always a register.
3429fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
3289fn genBinOp(
3290 self: *Self,
3291 inst: Air.Inst.Index,
3292 op_lhs: Air.Inst.Ref,
3293 op_rhs: Air.Inst.Ref,
3294) !MCValue {
3295 const tag = self.air.instructions.items(.tag)[inst];
3296 const is_commutative: bool = switch (tag) {
3297 .add,
3298 .addwrap,
3299 .add_with_overflow,
3300 .bool_or,
3301 .bit_or,
3302 .bool_and,
3303 .bit_and,
3304 .xor,
3305 .not,
3306 => true,
3307
3308 .sub,
3309 .subwrap,
3310 .sub_with_overflow,
3311 .mul,
3312 .shl,
3313 .shr,
3314 .ptr_add,
3315 .ptr_sub,
3316 => false,
3317
3318 else => unreachable,
3319 };
34303320 const dst_ty = self.air.typeOf(op_lhs);
3321 const src_ty = self.air.typeOf(op_rhs);
34313322
34323323 const lhs = try self.resolveInst(op_lhs);
34333324 const lhs_lock: ?RegisterLock = switch (lhs) {
......@@ -3448,7 +3339,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
34483339 if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) {
34493340 break :blk lhs;
34503341 }
3451 if (self.reuseOperand(inst, op_rhs, 1, rhs) and rhs.isRegister()) {
3342 if (is_commutative and self.reuseOperand(inst, op_rhs, 1, rhs) and rhs.isRegister()) {
34523343 flipped = true;
34533344 break :blk rhs;
34543345 }
......@@ -3463,7 +3354,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
34633354 const src_mcv: MCValue = blk: {
34643355 const mcv = if (flipped) lhs else rhs;
34653356 if (mcv.isRegister() or mcv.isMemory()) break :blk mcv;
3466 break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, mcv) };
3357 break :blk MCValue{ .register = try self.copyToTmpRegister(src_ty, mcv) };
34673358 };
34683359 const src_mcv_lock: ?RegisterLock = switch (src_mcv) {
34693360 .register => |reg| self.register_manager.lockReg(reg),
......@@ -3471,18 +3362,39 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
34713362 };
34723363 defer if (src_mcv_lock) |lock| self.register_manager.unlockReg(lock);
34733364
3474 const tag = self.air.instructions.items(.tag)[inst];
34753365 switch (tag) {
3476 .add, .addwrap, .add_with_overflow => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
3477 .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv),
3478 .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv),
3479 .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, dst_mcv, src_mcv),
3366 .add,
3367 .addwrap,
3368 .add_with_overflow,
3369 => try self.genBinOpMir(.add, dst_ty, dst_mcv, src_mcv),
3370
3371 .sub,
3372 .subwrap,
3373 .sub_with_overflow,
3374 => try self.genBinOpMir(.sub, dst_ty, dst_mcv, src_mcv),
3375
3376 .ptr_add,
3377 .ptr_sub,
3378 => {
3379 const mir_tag: Mir.Inst.Tag = switch (tag) {
3380 .ptr_add => .add,
3381 .ptr_sub => .sub,
3382 else => unreachable,
3383 };
3384 const elem_size = dst_ty.elemType2().abiSize(self.target.*);
3385 try self.genIntMulComplexOpMir(src_ty, src_mcv, .{ .immediate = elem_size });
3386 try self.genBinOpMir(mir_tag, dst_ty, dst_mcv, src_mcv);
3387 },
3388
3389 .bool_or, .bit_or => try self.genBinOpMir(.@"or", dst_ty, dst_mcv, src_mcv),
3390 .bool_and, .bit_and => try self.genBinOpMir(.@"and", dst_ty, dst_mcv, src_mcv),
3391 .xor, .not => try self.genBinOpMir(.xor, dst_ty, dst_mcv, src_mcv),
34803392 else => unreachable,
34813393 }
34823394 return dst_mcv;
34833395}
34843396
3485fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
3397fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
34863398 const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
34873399 switch (dst_mcv) {
34883400 .none => unreachable,
......@@ -3504,7 +3416,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
35043416 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
35053417
35063418 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);
3507 return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
3419 return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
35083420 },
35093421 .register => |src_reg| {
35103422 _ = try self.addInst(.{
......@@ -3536,7 +3448,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
35363448 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
35373449
35383450 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);
3539 return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
3451 return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
35403452 },
35413453 .stack_offset => |off| {
35423454 if (off > math.maxInt(i32)) {
......@@ -3637,7 +3549,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
36373549
36383550/// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv.
36393551/// Does not support byte-size operands.
3640fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
3552fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {
36413553 const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
36423554 switch (dst_mcv) {
36433555 .none => unreachable,
......@@ -3733,11 +3645,17 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
37333645 .data = undefined,
37343646 });
37353647 // copy dst_reg back out
3736 return self.genSetStack(dst_ty, off, MCValue{ .register = dst_reg }, .{});
3648 return self.genSetStack(dst_ty, off, .{ .register = dst_reg }, .{});
37373649 },
3738 .immediate => |imm| {
3739 _ = imm;
3740 return self.fail("TODO implement x86 multiply source immediate", .{});
3650 .immediate => {
3651 // copy dst to a register
3652 const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
3653 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
3654 defer self.register_manager.unlockReg(dst_reg_lock);
3655
3656 try self.genIntMulComplexOpMir(dst_ty, .{ .register = dst_reg }, src_mcv);
3657
3658 return self.genSetStack(dst_ty, off, .{ .register = dst_reg }, .{});
37413659 },
37423660 .memory, .stack_offset => {
37433661 return self.fail("TODO implement x86 multiply source memory", .{});
......@@ -4213,7 +4131,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
42134131 // This instruction supports only signed 32-bit immediates at most.
42144132 const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);
42154133
4216 try self.genBinMathOpMir(.cmp, ty, dst_mcv, src_mcv);
4134 try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);
42174135 break :result switch (signedness) {
42184136 .signed => MCValue{ .compare_flags_signed = op },
42194137 .unsigned => MCValue{ .compare_flags_unsigned = op },
......@@ -4606,7 +4524,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu
46064524 break :blk if (payload_ty.hasRuntimeBits()) Type.bool else ty;
46074525 } else ty;
46084526
4609 try self.genBinMathOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });
4527 try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });
46104528
46114529 return MCValue{ .compare_flags_unsigned = .eq };
46124530}
......@@ -4629,13 +4547,13 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue
46294547
46304548 if (!payload_type.hasRuntimeBits()) {
46314549 if (err_type.abiSize(self.target.*) <= 8) {
4632 try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });
4550 try self.genBinOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });
46334551 return MCValue{ .compare_flags_unsigned = .gt };
46344552 } else {
46354553 return self.fail("TODO isErr for errors with size larger than register size", .{});
46364554 }
46374555 } else {
4638 try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });
4556 try self.genBinOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });
46394557 return MCValue{ .compare_flags_unsigned = .gt };
46404558 }
46414559}
......@@ -5053,21 +4971,6 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
50534971 return self.finishAir(inst, .dead, .{ branch.operand, .none, .none });
50544972}
50554973
5056fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
5057 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5058 const air_tags = self.air.instructions.items(.tag);
5059 const result: MCValue = if (self.liveness.isUnused(inst))
5060 .dead
5061 else switch (air_tags[inst]) {
5062 // lhs AND rhs
5063 .bool_and => try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs),
5064 // lhs OR rhs
5065 .bool_or => try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs),
5066 else => unreachable, // Not a boolean operation
5067 };
5068 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
5069}
5070
50714974fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
50724975 const block_data = self.blocks.getPtr(block).?;
50734976
......@@ -5844,7 +5747,7 @@ fn genInlineMemset(
58445747 defer self.register_manager.unlockReg(addr_reg_lock);
58455748
58465749 try self.genSetReg(Type.usize, .rax, len);
5847 try self.genBinMathOpMir(.sub, Type.usize, .{ .register = .rax }, .{ .immediate = 1 });
5750 try self.genBinOpMir(.sub, Type.usize, .{ .register = .rax }, .{ .immediate = 1 });
58485751
58495752 // loop:
58505753 // cmp rax, -1
......@@ -6963,10 +6866,10 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
69636866 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
69646867 const mask = (~@as(u64, 0)) >> shift;
69656868 if (int_info.bits <= 32) {
6966 try self.genBinMathOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask });
6869 try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask });
69676870 } else {
69686871 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
6969 try self.genBinMathOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg });
6872 try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg });
69706873 }
69716874 },
69726875 }