| ... | ... | @@ -402,8 +402,8 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 402 | 402 | fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void { |
| 403 | 403 | _ = try self.addInst(.{ |
| 404 | 404 | .tag = .setcc, |
| 405 | | .ops = .r_c, |
| 406 | | .data = .{ .r_c = .{ |
| 405 | .ops = .r_cc, |
| 406 | .data = .{ .r_cc = .{ |
| 407 | 407 | .r1 = reg, |
| 408 | 408 | .cc = cc, |
| 409 | 409 | } }, |
| ... | ... | @@ -413,8 +413,8 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void { |
| 413 | 413 | fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void { |
| 414 | 414 | _ = try self.addInst(.{ |
| 415 | 415 | .tag = .cmovcc, |
| 416 | | .ops = .rr_c, |
| 417 | | .data = .{ .rr_c = .{ |
| 416 | .ops = .rr_cc, |
| 417 | .data = .{ .rr_cc = .{ |
| 418 | 418 | .r1 = reg1, |
| 419 | 419 | .r2 = reg2, |
| 420 | 420 | .cc = cc, |
| ... | ... | @@ -422,6 +422,26 @@ fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bi |
| 422 | 422 | }); |
| 423 | 423 | } |
| 424 | 424 | |
| 425 | fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condition) !void { |
| 426 | _ = try self.addInst(.{ |
| 427 | .tag = .cmovcc, |
| 428 | .ops = switch (m) { |
| 429 | .sib => .rm_sib_cc, |
| 430 | .rip => .rm_rip_cc, |
| 431 | else => unreachable, |
| 432 | }, |
| 433 | .data = .{ .rx_cc = .{ |
| 434 | .r1 = reg, |
| 435 | .cc = cc, |
| 436 | .payload = switch (m) { |
| 437 | .sib => try self.addExtra(Mir.MemorySib.encode(m)), |
| 438 | .rip => try self.addExtra(Mir.MemoryRip.encode(m)), |
| 439 | else => unreachable, |
| 440 | }, |
| 441 | } }, |
| 442 | }); |
| 443 | } |
| 444 | |
| 425 | 445 | fn asmJmpReloc(self: *Self, target: Mir.Inst.Index) !Mir.Inst.Index { |
| 426 | 446 | return self.addInst(.{ |
| 427 | 447 | .tag = .jmp_reloc, |
| ... | ... | @@ -793,18 +813,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 793 | 813 | |
| 794 | 814 | switch (air_tags[inst]) { |
| 795 | 815 | // zig fmt: off |
| 796 | | .add => try self.airBinOp(inst, .add), |
| 797 | | .addwrap => try self.airBinOp(inst, .addwrap), |
| 798 | | .sub => try self.airBinOp(inst, .sub), |
| 799 | | .subwrap => try self.airBinOp(inst, .subwrap), |
| 800 | | .bool_and => try self.airBinOp(inst, .bool_and), |
| 801 | | .bool_or => try self.airBinOp(inst, .bool_or), |
| 802 | | .bit_and => try self.airBinOp(inst, .bit_and), |
| 803 | | .bit_or => try self.airBinOp(inst, .bit_or), |
| 804 | | .xor => try self.airBinOp(inst, .xor), |
| 805 | | |
| 806 | | .ptr_add => try self.airPtrArithmetic(inst, .ptr_add), |
| 807 | | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), |
| 816 | .add, |
| 817 | .addwrap, |
| 818 | .sub, |
| 819 | .subwrap, |
| 820 | .bool_and, |
| 821 | .bool_or, |
| 822 | .bit_and, |
| 823 | .bit_or, |
| 824 | .xor, |
| 825 | .min, |
| 826 | .max, |
| 827 | => |tag| try self.airBinOp(inst, tag), |
| 828 | |
| 829 | .ptr_add, .ptr_sub => |tag| try self.airPtrArithmetic(inst, tag), |
| 808 | 830 | |
| 809 | 831 | .shr, .shr_exact => try self.airShlShrBinOp(inst), |
| 810 | 832 | .shl, .shl_exact => try self.airShlShrBinOp(inst), |
| ... | ... | @@ -818,8 +840,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 818 | 840 | .sub_sat => try self.airSubSat(inst), |
| 819 | 841 | .mul_sat => try self.airMulSat(inst), |
| 820 | 842 | .shl_sat => try self.airShlSat(inst), |
| 821 | | .min => try self.airMin(inst), |
| 822 | | .max => try self.airMax(inst), |
| 823 | 843 | .slice => try self.airSlice(inst), |
| 824 | 844 | |
| 825 | 845 | .sqrt, |
| ... | ... | @@ -1466,61 +1486,6 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1466 | 1486 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1467 | 1487 | } |
| 1468 | 1488 | |
| 1469 | | fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| 1470 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1471 | | if (self.liveness.isUnused(inst)) { |
| 1472 | | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1473 | | } |
| 1474 | | |
| 1475 | | const ty = self.air.typeOfIndex(inst); |
| 1476 | | if (ty.zigTypeTag() != .Int) { |
| 1477 | | return self.fail("TODO implement min for type {}", .{ty.fmtDebug()}); |
| 1478 | | } |
| 1479 | | const signedness = ty.intInfo(self.target.*).signedness; |
| 1480 | | const result: MCValue = result: { |
| 1481 | | // TODO improve by checking if any operand can be reused. |
| 1482 | | // TODO audit register allocation |
| 1483 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 1484 | | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 1485 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1486 | | else => null, |
| 1487 | | }; |
| 1488 | | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1489 | | |
| 1490 | | const lhs_reg = try self.copyToTmpRegister(ty, lhs); |
| 1491 | | const lhs_reg_lock = self.register_manager.lockRegAssumeUnused(lhs_reg); |
| 1492 | | defer self.register_manager.unlockReg(lhs_reg_lock); |
| 1493 | | |
| 1494 | | const rhs_mcv = try self.limitImmediateType(bin_op.rhs, i32); |
| 1495 | | const rhs_lock: ?RegisterLock = switch (rhs_mcv) { |
| 1496 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1497 | | else => null, |
| 1498 | | }; |
| 1499 | | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1500 | | |
| 1501 | | try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv); |
| 1502 | | |
| 1503 | | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv); |
| 1504 | | const cc: Condition = switch (signedness) { |
| 1505 | | .unsigned => .b, |
| 1506 | | .signed => .l, |
| 1507 | | }; |
| 1508 | | try self.asmCmovccRegisterRegister(dst_mcv.register, lhs_reg, cc); |
| 1509 | | |
| 1510 | | break :result dst_mcv; |
| 1511 | | }; |
| 1512 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1513 | | } |
| 1514 | | |
| 1515 | | fn airMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1516 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1517 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1518 | | .dead |
| 1519 | | else |
| 1520 | | return self.fail("TODO implement max for {}", .{self.target.cpu.arch}); |
| 1521 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1522 | | } |
| 1523 | | |
| 1524 | 1489 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1525 | 1490 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1526 | 1491 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| ... | ... | @@ -1545,11 +1510,10 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1545 | 1510 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1546 | 1511 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1547 | 1512 | |
| 1548 | | if (self.liveness.isUnused(inst)) { |
| 1549 | | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1550 | | } |
| 1551 | | |
| 1552 | | const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1513 | const result = if (self.liveness.isUnused(inst)) |
| 1514 | .dead |
| 1515 | else |
| 1516 | try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1553 | 1517 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1554 | 1518 | } |
| 1555 | 1519 | |
| ... | ... | @@ -1557,11 +1521,10 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void |
| 1557 | 1521 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1558 | 1522 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1559 | 1523 | |
| 1560 | | if (self.liveness.isUnused(inst)) { |
| 1561 | | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1562 | | } |
| 1563 | | |
| 1564 | | const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1524 | const result = if (self.liveness.isUnused(inst)) |
| 1525 | .dead |
| 1526 | else |
| 1527 | try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1565 | 1528 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1566 | 1529 | } |
| 1567 | 1530 | |
| ... | ... | @@ -3486,10 +3449,10 @@ fn genBinOp( |
| 3486 | 3449 | const lhs_ty = self.air.typeOf(lhs_air); |
| 3487 | 3450 | const rhs_ty = self.air.typeOf(rhs_air); |
| 3488 | 3451 | if (lhs_ty.zigTypeTag() == .Vector) { |
| 3489 | | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); |
| 3452 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)}); |
| 3490 | 3453 | } |
| 3491 | 3454 | if (lhs_ty.abiSize(self.target.*) > 8) { |
| 3492 | | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); |
| 3455 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)}); |
| 3493 | 3456 | } |
| 3494 | 3457 | |
| 3495 | 3458 | const is_commutative: bool = switch (tag) { |
| ... | ... | @@ -3500,6 +3463,8 @@ fn genBinOp( |
| 3500 | 3463 | .bool_and, |
| 3501 | 3464 | .bit_and, |
| 3502 | 3465 | .xor, |
| 3466 | .min, |
| 3467 | .max, |
| 3503 | 3468 | => true, |
| 3504 | 3469 | |
| 3505 | 3470 | else => false, |
| ... | ... | @@ -3520,10 +3485,10 @@ fn genBinOp( |
| 3520 | 3485 | var flipped: bool = false; |
| 3521 | 3486 | const dst_mcv: MCValue = blk: { |
| 3522 | 3487 | if (maybe_inst) |inst| { |
| 3523 | | if (self.reuseOperand(inst, lhs_air, 0, lhs) and lhs.isRegister()) { |
| 3488 | if (lhs.isRegister() and self.reuseOperand(inst, lhs_air, 0, lhs)) { |
| 3524 | 3489 | break :blk lhs; |
| 3525 | 3490 | } |
| 3526 | | if (is_commutative and self.reuseOperand(inst, rhs_air, 1, rhs) and rhs.isRegister()) { |
| 3491 | if (rhs.isRegister() and is_commutative and self.reuseOperand(inst, rhs_air, 1, rhs)) { |
| 3527 | 3492 | flipped = true; |
| 3528 | 3493 | break :blk rhs; |
| 3529 | 3494 | } |
| ... | ... | @@ -3580,6 +3545,58 @@ fn genBinOp( |
| 3580 | 3545 | |
| 3581 | 3546 | .xor => try self.genBinOpMir(.xor, lhs_ty, dst_mcv, src_mcv), |
| 3582 | 3547 | |
| 3548 | .min, |
| 3549 | .max, |
| 3550 | => { |
| 3551 | if (!lhs_ty.isAbiInt() or !rhs_ty.isAbiInt()) { |
| 3552 | return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }); |
| 3553 | } |
| 3554 | |
| 3555 | const mat_src_mcv = switch (src_mcv) { |
| 3556 | .immediate => MCValue{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) }, |
| 3557 | else => src_mcv, |
| 3558 | }; |
| 3559 | const mat_mcv_lock = switch (mat_src_mcv) { |
| 3560 | .register => |reg| self.register_manager.lockReg(reg), |
| 3561 | else => null, |
| 3562 | }; |
| 3563 | defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3564 | |
| 3565 | try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv); |
| 3566 | |
| 3567 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3568 | const cc: Condition = switch (int_info.signedness) { |
| 3569 | .unsigned => switch (tag) { |
| 3570 | .min => .a, |
| 3571 | .max => .b, |
| 3572 | else => unreachable, |
| 3573 | }, |
| 3574 | .signed => switch (tag) { |
| 3575 | .min => .g, |
| 3576 | .max => .l, |
| 3577 | else => unreachable, |
| 3578 | }, |
| 3579 | }; |
| 3580 | |
| 3581 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); |
| 3582 | switch (dst_mcv) { |
| 3583 | .register => |dst_reg| switch (mat_src_mcv) { |
| 3584 | .register => |src_reg| try self.asmCmovccRegisterRegister( |
| 3585 | registerAlias(dst_reg, abi_size), |
| 3586 | registerAlias(src_reg, abi_size), |
| 3587 | cc, |
| 3588 | ), |
| 3589 | .stack_offset => |off| try self.asmCmovccRegisterMemory( |
| 3590 | registerAlias(dst_reg, abi_size), |
| 3591 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }), |
| 3592 | cc, |
| 3593 | ), |
| 3594 | else => unreachable, |
| 3595 | }, |
| 3596 | else => unreachable, |
| 3597 | } |
| 3598 | }, |
| 3599 | |
| 3583 | 3600 | else => unreachable, |
| 3584 | 3601 | } |
| 3585 | 3602 | return dst_mcv; |
| ... | ... | @@ -3660,13 +3677,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu |
| 3660 | 3677 | Immediate.s(small), |
| 3661 | 3678 | ); |
| 3662 | 3679 | } else { |
| 3663 | | const tmp_reg = try self.register_manager.allocReg(null, gp); |
| 3664 | | const tmp_alias = registerAlias(tmp_reg, abi_size); |
| 3665 | | try self.asmRegisterImmediate(.mov, tmp_alias, Immediate.u(imm)); |
| 3666 | 3680 | try self.asmRegisterRegister( |
| 3667 | 3681 | mir_tag, |
| 3668 | 3682 | registerAlias(dst_reg, abi_size), |
| 3669 | | tmp_alias, |
| 3683 | registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size), |
| 3670 | 3684 | ); |
| 3671 | 3685 | } |
| 3672 | 3686 | }, |