| ... | ... | @@ -917,17 +917,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 917 | 917 | const air_tags = self.air.instructions.items(.tag); |
| 918 | 918 | |
| 919 | 919 | for (body) |inst| { |
| 920 | | // TODO: remove now-redundant isUnused calls from AIR handler functions |
| 921 | | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) { |
| 922 | | continue; |
| 923 | | } |
| 924 | | |
| 925 | | const old_air_bookkeeping = self.air_bookkeeping; |
| 926 | | try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); |
| 927 | 920 | if (builtin.mode == .Debug) { |
| 928 | 921 | const mir_inst = @intCast(Mir.Inst.Index, self.mir_instructions.len); |
| 929 | 922 | try self.mir_to_air_map.put(self.gpa, mir_inst, inst); |
| 930 | 923 | } |
| 924 | |
| 925 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue; |
| 931 | 926 | if (debug_wip_mir) @import("../../print_air.zig").dumpInst( |
| 932 | 927 | inst, |
| 933 | 928 | self.bin_file.options.module.?, |
| ... | ... | @@ -935,6 +930,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 935 | 930 | self.liveness, |
| 936 | 931 | ); |
| 937 | 932 | |
| 933 | const old_air_bookkeeping = self.air_bookkeeping; |
| 934 | try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); |
| 938 | 935 | switch (air_tags[inst]) { |
| 939 | 936 | // zig fmt: off |
| 940 | 937 | .not, |
| ... | ... | @@ -1505,22 +1502,14 @@ fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Ty |
| 1505 | 1502 | } |
| 1506 | 1503 | |
| 1507 | 1504 | fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 1508 | | const result: MCValue = result: { |
| 1509 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 1510 | | |
| 1511 | | const stack_offset = try self.allocMemPtr(inst); |
| 1512 | | break :result .{ .ptr_stack_offset = @intCast(i32, stack_offset) }; |
| 1513 | | }; |
| 1505 | const stack_offset = try self.allocMemPtr(inst); |
| 1506 | const result = MCValue{ .ptr_stack_offset = @intCast(i32, stack_offset) }; |
| 1514 | 1507 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 1515 | 1508 | } |
| 1516 | 1509 | |
| 1517 | 1510 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1518 | | const result: MCValue = result: { |
| 1519 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 1520 | | |
| 1521 | | const stack_offset = try self.allocMemPtr(inst); |
| 1522 | | break :result .{ .ptr_stack_offset = @intCast(i32, stack_offset) }; |
| 1523 | | }; |
| 1511 | const stack_offset = try self.allocMemPtr(inst); |
| 1512 | const result = MCValue{ .ptr_stack_offset = @intCast(i32, stack_offset) }; |
| 1524 | 1513 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 1525 | 1514 | } |
| 1526 | 1515 | |
| ... | ... | @@ -1540,126 +1529,125 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 1540 | 1529 | |
| 1541 | 1530 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1542 | 1531 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1543 | | const result = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 1544 | | const src_ty = self.air.typeOf(ty_op.operand); |
| 1545 | | const src_int_info = src_ty.intInfo(self.target.*); |
| 1546 | | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| 1547 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 1548 | | const src_lock = switch (src_mcv) { |
| 1549 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1550 | | else => null, |
| 1551 | | }; |
| 1552 | | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 1553 | | |
| 1554 | | const dst_ty = self.air.typeOfIndex(inst); |
| 1555 | | const dst_int_info = dst_ty.intInfo(self.target.*); |
| 1556 | | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 1557 | | const dst_mcv = if (dst_abi_size <= src_abi_size and |
| 1558 | | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 1559 | | src_mcv |
| 1560 | | else |
| 1561 | | try self.allocRegOrMem(inst, true); |
| 1562 | 1532 | |
| 1563 | | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; |
| 1564 | | const signedness: std.builtin.Signedness = if (dst_int_info.signedness == .signed and |
| 1565 | | src_int_info.signedness == .signed) .signed else .unsigned; |
| 1566 | | switch (dst_mcv) { |
| 1567 | | .register => |dst_reg| { |
| 1568 | | const min_abi_size = @min(dst_abi_size, src_abi_size); |
| 1569 | | const tag: Mir.Inst.Tag = switch (signedness) { |
| 1570 | | .signed => .movsx, |
| 1571 | | .unsigned => if (min_abi_size > 2) .mov else .movzx, |
| 1572 | | }; |
| 1573 | | const dst_alias = switch (tag) { |
| 1574 | | .movsx => dst_reg.to64(), |
| 1575 | | .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(), |
| 1576 | | else => unreachable, |
| 1577 | | }; |
| 1578 | | switch (src_mcv) { |
| 1579 | | .register => |src_reg| { |
| 1580 | | try self.asmRegisterRegister( |
| 1581 | | tag, |
| 1582 | | dst_alias, |
| 1583 | | registerAlias(src_reg, min_abi_size), |
| 1584 | | ); |
| 1585 | | }, |
| 1586 | | .stack_offset => |src_off| { |
| 1587 | | try self.asmRegisterMemory(tag, dst_alias, Memory.sib( |
| 1588 | | Memory.PtrSize.fromSize(min_abi_size), |
| 1589 | | .{ .base = .rbp, .disp = -src_off }, |
| 1590 | | )); |
| 1591 | | }, |
| 1592 | | else => return self.fail("TODO airIntCast from {s} to {s}", .{ |
| 1593 | | @tagName(src_mcv), |
| 1594 | | @tagName(dst_mcv), |
| 1595 | | }), |
| 1596 | | } |
| 1597 | | if (self.regExtraBits(min_ty) > 0) try self.truncateRegister(min_ty, dst_reg); |
| 1598 | | }, |
| 1599 | | else => { |
| 1600 | | try self.setRegOrMem(min_ty, dst_mcv, src_mcv); |
| 1601 | | const extra = dst_abi_size * 8 - dst_int_info.bits; |
| 1602 | | if (extra > 0) { |
| 1603 | | try self.genShiftBinOpMir(switch (signedness) { |
| 1604 | | .signed => .sal, |
| 1605 | | .unsigned => .shl, |
| 1606 | | }, dst_ty, dst_mcv, .{ .immediate = extra }); |
| 1607 | | try self.genShiftBinOpMir(switch (signedness) { |
| 1608 | | .signed => .sar, |
| 1609 | | .unsigned => .shr, |
| 1610 | | }, dst_ty, dst_mcv, .{ .immediate = extra }); |
| 1611 | | } |
| 1612 | | }, |
| 1613 | | } |
| 1614 | | break :result dst_mcv; |
| 1533 | const src_ty = self.air.typeOf(ty_op.operand); |
| 1534 | const src_int_info = src_ty.intInfo(self.target.*); |
| 1535 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| 1536 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 1537 | const src_lock = switch (src_mcv) { |
| 1538 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1539 | else => null, |
| 1615 | 1540 | }; |
| 1616 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1541 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 1542 | |
| 1543 | const dst_ty = self.air.typeOfIndex(inst); |
| 1544 | const dst_int_info = dst_ty.intInfo(self.target.*); |
| 1545 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 1546 | const dst_mcv = if (dst_abi_size <= src_abi_size and |
| 1547 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 1548 | src_mcv |
| 1549 | else |
| 1550 | try self.allocRegOrMem(inst, true); |
| 1551 | |
| 1552 | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; |
| 1553 | const signedness: std.builtin.Signedness = if (dst_int_info.signedness == .signed and |
| 1554 | src_int_info.signedness == .signed) .signed else .unsigned; |
| 1555 | switch (dst_mcv) { |
| 1556 | .register => |dst_reg| { |
| 1557 | const min_abi_size = @min(dst_abi_size, src_abi_size); |
| 1558 | const tag: Mir.Inst.Tag = switch (signedness) { |
| 1559 | .signed => .movsx, |
| 1560 | .unsigned => if (min_abi_size > 2) .mov else .movzx, |
| 1561 | }; |
| 1562 | const dst_alias = switch (tag) { |
| 1563 | .movsx => dst_reg.to64(), |
| 1564 | .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(), |
| 1565 | else => unreachable, |
| 1566 | }; |
| 1567 | switch (src_mcv) { |
| 1568 | .register => |src_reg| { |
| 1569 | try self.asmRegisterRegister( |
| 1570 | tag, |
| 1571 | dst_alias, |
| 1572 | registerAlias(src_reg, min_abi_size), |
| 1573 | ); |
| 1574 | }, |
| 1575 | .stack_offset => |src_off| { |
| 1576 | try self.asmRegisterMemory(tag, dst_alias, Memory.sib( |
| 1577 | Memory.PtrSize.fromSize(min_abi_size), |
| 1578 | .{ .base = .rbp, .disp = -src_off }, |
| 1579 | )); |
| 1580 | }, |
| 1581 | else => return self.fail("TODO airIntCast from {s} to {s}", .{ |
| 1582 | @tagName(src_mcv), |
| 1583 | @tagName(dst_mcv), |
| 1584 | }), |
| 1585 | } |
| 1586 | if (self.regExtraBits(min_ty) > 0) try self.truncateRegister(min_ty, dst_reg); |
| 1587 | }, |
| 1588 | else => { |
| 1589 | try self.setRegOrMem(min_ty, dst_mcv, src_mcv); |
| 1590 | const extra = dst_abi_size * 8 - dst_int_info.bits; |
| 1591 | if (extra > 0) { |
| 1592 | try self.genShiftBinOpMir(switch (signedness) { |
| 1593 | .signed => .sal, |
| 1594 | .unsigned => .shl, |
| 1595 | }, dst_ty, dst_mcv, .{ .immediate = extra }); |
| 1596 | try self.genShiftBinOpMir(switch (signedness) { |
| 1597 | .signed => .sar, |
| 1598 | .unsigned => .shr, |
| 1599 | }, dst_ty, dst_mcv, .{ .immediate = extra }); |
| 1600 | } |
| 1601 | }, |
| 1602 | } |
| 1603 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 1617 | 1604 | } |
| 1618 | 1605 | |
| 1619 | 1606 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1620 | 1607 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1621 | | const result = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 1622 | | const dst_ty = self.air.typeOfIndex(inst); |
| 1623 | | const dst_abi_size = dst_ty.abiSize(self.target.*); |
| 1624 | | if (dst_abi_size > 8) { |
| 1625 | | return self.fail("TODO implement trunc for abi sizes larger than 8", .{}); |
| 1626 | | } |
| 1627 | | |
| 1628 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 1629 | | const src_lock = switch (src_mcv) { |
| 1630 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1631 | | else => null, |
| 1632 | | }; |
| 1633 | | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 1634 | 1608 | |
| 1635 | | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 1636 | | src_mcv |
| 1637 | | else |
| 1638 | | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 1609 | const dst_ty = self.air.typeOfIndex(inst); |
| 1610 | const dst_abi_size = dst_ty.abiSize(self.target.*); |
| 1611 | if (dst_abi_size > 8) { |
| 1612 | return self.fail("TODO implement trunc for abi sizes larger than 8", .{}); |
| 1613 | } |
| 1639 | 1614 | |
| 1640 | | // when truncating a `u16` to `u5`, for example, those top 3 bits in the result |
| 1641 | | // have to be removed. this only happens if the dst if not a power-of-two size. |
| 1642 | | if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64()); |
| 1643 | | break :result dst_mcv; |
| 1615 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 1616 | const src_lock = switch (src_mcv) { |
| 1617 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1618 | else => null, |
| 1644 | 1619 | }; |
| 1645 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1620 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 1621 | |
| 1622 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 1623 | src_mcv |
| 1624 | else |
| 1625 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 1626 | |
| 1627 | // when truncating a `u16` to `u5`, for example, those top 3 bits in the result |
| 1628 | // have to be removed. this only happens if the dst if not a power-of-two size. |
| 1629 | if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64()); |
| 1630 | |
| 1631 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 1646 | 1632 | } |
| 1647 | 1633 | |
| 1648 | 1634 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 1649 | 1635 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1636 | const ty = self.air.typeOfIndex(inst); |
| 1637 | |
| 1650 | 1638 | const operand = try self.resolveInst(un_op); |
| 1651 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else operand; |
| 1652 | | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 1639 | const dst_mcv = if (self.reuseOperand(inst, un_op, 0, operand)) |
| 1640 | operand |
| 1641 | else |
| 1642 | try self.copyToRegisterWithInstTracking(inst, ty, operand); |
| 1643 | |
| 1644 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 1653 | 1645 | } |
| 1654 | 1646 | |
| 1655 | 1647 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1656 | 1648 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1657 | 1649 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1658 | 1650 | |
| 1659 | | if (self.liveness.isUnused(inst)) { |
| 1660 | | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1661 | | } |
| 1662 | | |
| 1663 | 1651 | const ptr = try self.resolveInst(bin_op.lhs); |
| 1664 | 1652 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 1665 | 1653 | const len = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -1675,33 +1663,21 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1675 | 1663 | |
| 1676 | 1664 | fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1677 | 1665 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1678 | | |
| 1679 | | const result = if (self.liveness.isUnused(inst)) |
| 1680 | | .unreach |
| 1681 | | else |
| 1682 | | try self.genUnOp(inst, tag, ty_op.operand); |
| 1683 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1666 | const dst_mcv = try self.genUnOp(inst, tag, ty_op.operand); |
| 1667 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 1684 | 1668 | } |
| 1685 | 1669 | |
| 1686 | 1670 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1687 | 1671 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1688 | | |
| 1689 | | const result = if (self.liveness.isUnused(inst)) |
| 1690 | | .unreach |
| 1691 | | else |
| 1692 | | try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1693 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1672 | const dst_mcv = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1673 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1694 | 1674 | } |
| 1695 | 1675 | |
| 1696 | 1676 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1697 | 1677 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1698 | 1678 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1699 | | |
| 1700 | | const result = if (self.liveness.isUnused(inst)) |
| 1701 | | .unreach |
| 1702 | | else |
| 1703 | | try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1704 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1679 | const dst_mcv = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1680 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1705 | 1681 | } |
| 1706 | 1682 | |
| 1707 | 1683 | fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| ... | ... | @@ -1741,7 +1717,7 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| 1741 | 1717 | |
| 1742 | 1718 | fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1743 | 1719 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1744 | | const result = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 1720 | const result = result: { |
| 1745 | 1721 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1746 | 1722 | const dst_ty = self.air.typeOfIndex(inst); |
| 1747 | 1723 | if (dst_ty.zigTypeTag() == .Float) |
| ... | ... | @@ -1772,168 +1748,162 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1772 | 1748 | |
| 1773 | 1749 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1774 | 1750 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1775 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 1776 | | const ty = self.air.typeOf(bin_op.lhs); |
| 1751 | const ty = self.air.typeOf(bin_op.lhs); |
| 1777 | 1752 | |
| 1778 | | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 1779 | | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) |
| 1780 | | lhs_mcv |
| 1781 | | else |
| 1782 | | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv); |
| 1783 | | const dst_reg = dst_mcv.register; |
| 1784 | | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 1785 | | defer self.register_manager.unlockReg(dst_lock); |
| 1753 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 1754 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) |
| 1755 | lhs_mcv |
| 1756 | else |
| 1757 | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv); |
| 1758 | const dst_reg = dst_mcv.register; |
| 1759 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 1760 | defer self.register_manager.unlockReg(dst_lock); |
| 1786 | 1761 | |
| 1787 | | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 1788 | | const rhs_lock = switch (rhs_mcv) { |
| 1789 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1790 | | else => null, |
| 1791 | | }; |
| 1792 | | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1793 | | |
| 1794 | | const limit_reg = try self.register_manager.allocReg(null, gp); |
| 1795 | | const limit_mcv = MCValue{ .register = limit_reg }; |
| 1796 | | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| 1797 | | defer self.register_manager.unlockReg(limit_lock); |
| 1798 | | |
| 1799 | | const reg_bits = self.regBitSize(ty); |
| 1800 | | const cc: Condition = if (ty.isSignedInt()) cc: { |
| 1801 | | try self.genSetReg(ty, limit_reg, dst_mcv); |
| 1802 | | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 1803 | | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| 1804 | | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| 1805 | | }); |
| 1806 | | break :cc .o; |
| 1807 | | } else cc: { |
| 1808 | | try self.genSetReg(ty, limit_reg, .{ |
| 1809 | | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), |
| 1810 | | }); |
| 1811 | | break :cc .c; |
| 1812 | | }; |
| 1813 | | try self.genBinOpMir(.add, ty, dst_mcv, rhs_mcv); |
| 1762 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 1763 | const rhs_lock = switch (rhs_mcv) { |
| 1764 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1765 | else => null, |
| 1766 | }; |
| 1767 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1814 | 1768 | |
| 1815 | | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| 1816 | | try self.asmCmovccRegisterRegister( |
| 1817 | | registerAlias(dst_reg, cmov_abi_size), |
| 1818 | | registerAlias(limit_reg, cmov_abi_size), |
| 1819 | | cc, |
| 1820 | | ); |
| 1821 | | break :result dst_mcv; |
| 1769 | const limit_reg = try self.register_manager.allocReg(null, gp); |
| 1770 | const limit_mcv = MCValue{ .register = limit_reg }; |
| 1771 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| 1772 | defer self.register_manager.unlockReg(limit_lock); |
| 1773 | |
| 1774 | const reg_bits = self.regBitSize(ty); |
| 1775 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| 1776 | try self.genSetReg(ty, limit_reg, dst_mcv); |
| 1777 | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 1778 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| 1779 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| 1780 | }); |
| 1781 | break :cc .o; |
| 1782 | } else cc: { |
| 1783 | try self.genSetReg(ty, limit_reg, .{ |
| 1784 | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), |
| 1785 | }); |
| 1786 | break :cc .c; |
| 1822 | 1787 | }; |
| 1823 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1788 | try self.genBinOpMir(.add, ty, dst_mcv, rhs_mcv); |
| 1789 | |
| 1790 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| 1791 | try self.asmCmovccRegisterRegister( |
| 1792 | registerAlias(dst_reg, cmov_abi_size), |
| 1793 | registerAlias(limit_reg, cmov_abi_size), |
| 1794 | cc, |
| 1795 | ); |
| 1796 | |
| 1797 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1824 | 1798 | } |
| 1825 | 1799 | |
| 1826 | 1800 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1827 | 1801 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1828 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 1829 | | const ty = self.air.typeOf(bin_op.lhs); |
| 1830 | | |
| 1831 | | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 1832 | | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) |
| 1833 | | lhs_mcv |
| 1834 | | else |
| 1835 | | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv); |
| 1836 | | const dst_reg = dst_mcv.register; |
| 1837 | | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 1838 | | defer self.register_manager.unlockReg(dst_lock); |
| 1802 | const ty = self.air.typeOf(bin_op.lhs); |
| 1839 | 1803 | |
| 1840 | | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 1841 | | const rhs_lock = switch (rhs_mcv) { |
| 1842 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1843 | | else => null, |
| 1844 | | }; |
| 1845 | | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1846 | | |
| 1847 | | const limit_reg = try self.register_manager.allocReg(null, gp); |
| 1848 | | const limit_mcv = MCValue{ .register = limit_reg }; |
| 1849 | | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| 1850 | | defer self.register_manager.unlockReg(limit_lock); |
| 1851 | | |
| 1852 | | const reg_bits = self.regBitSize(ty); |
| 1853 | | const cc: Condition = if (ty.isSignedInt()) cc: { |
| 1854 | | try self.genSetReg(ty, limit_reg, dst_mcv); |
| 1855 | | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 1856 | | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| 1857 | | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| 1858 | | }); |
| 1859 | | break :cc .o; |
| 1860 | | } else cc: { |
| 1861 | | try self.genSetReg(ty, limit_reg, .{ .immediate = 0 }); |
| 1862 | | break :cc .c; |
| 1863 | | }; |
| 1864 | | try self.genBinOpMir(.sub, ty, dst_mcv, rhs_mcv); |
| 1804 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 1805 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) |
| 1806 | lhs_mcv |
| 1807 | else |
| 1808 | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv); |
| 1809 | const dst_reg = dst_mcv.register; |
| 1810 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 1811 | defer self.register_manager.unlockReg(dst_lock); |
| 1865 | 1812 | |
| 1866 | | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| 1867 | | try self.asmCmovccRegisterRegister( |
| 1868 | | registerAlias(dst_reg, cmov_abi_size), |
| 1869 | | registerAlias(limit_reg, cmov_abi_size), |
| 1870 | | cc, |
| 1871 | | ); |
| 1872 | | break :result dst_mcv; |
| 1813 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 1814 | const rhs_lock = switch (rhs_mcv) { |
| 1815 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1816 | else => null, |
| 1873 | 1817 | }; |
| 1874 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1818 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1819 | |
| 1820 | const limit_reg = try self.register_manager.allocReg(null, gp); |
| 1821 | const limit_mcv = MCValue{ .register = limit_reg }; |
| 1822 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| 1823 | defer self.register_manager.unlockReg(limit_lock); |
| 1824 | |
| 1825 | const reg_bits = self.regBitSize(ty); |
| 1826 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| 1827 | try self.genSetReg(ty, limit_reg, dst_mcv); |
| 1828 | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 1829 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| 1830 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| 1831 | }); |
| 1832 | break :cc .o; |
| 1833 | } else cc: { |
| 1834 | try self.genSetReg(ty, limit_reg, .{ .immediate = 0 }); |
| 1835 | break :cc .c; |
| 1836 | }; |
| 1837 | try self.genBinOpMir(.sub, ty, dst_mcv, rhs_mcv); |
| 1838 | |
| 1839 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| 1840 | try self.asmCmovccRegisterRegister( |
| 1841 | registerAlias(dst_reg, cmov_abi_size), |
| 1842 | registerAlias(limit_reg, cmov_abi_size), |
| 1843 | cc, |
| 1844 | ); |
| 1845 | |
| 1846 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1875 | 1847 | } |
| 1876 | 1848 | |
| 1877 | 1849 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1878 | 1850 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1879 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 1880 | | const ty = self.air.typeOf(bin_op.lhs); |
| 1851 | const ty = self.air.typeOf(bin_op.lhs); |
| 1881 | 1852 | |
| 1882 | | try self.spillRegisters(&.{ .rax, .rdx }); |
| 1883 | | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| 1884 | | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 1853 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 1854 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| 1855 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 1885 | 1856 | |
| 1886 | | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 1887 | | const lhs_lock = switch (lhs_mcv) { |
| 1888 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1889 | | else => null, |
| 1890 | | }; |
| 1891 | | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1857 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 1858 | const lhs_lock = switch (lhs_mcv) { |
| 1859 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1860 | else => null, |
| 1861 | }; |
| 1862 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1892 | 1863 | |
| 1893 | | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 1894 | | const rhs_lock = switch (rhs_mcv) { |
| 1895 | | .register => |reg| self.register_manager.lockReg(reg), |
| 1896 | | else => null, |
| 1897 | | }; |
| 1898 | | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1899 | | |
| 1900 | | const limit_reg = try self.register_manager.allocReg(null, gp); |
| 1901 | | const limit_mcv = MCValue{ .register = limit_reg }; |
| 1902 | | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| 1903 | | defer self.register_manager.unlockReg(limit_lock); |
| 1904 | | |
| 1905 | | const reg_bits = self.regBitSize(ty); |
| 1906 | | const cc: Condition = if (ty.isSignedInt()) cc: { |
| 1907 | | try self.genSetReg(ty, limit_reg, lhs_mcv); |
| 1908 | | try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv); |
| 1909 | | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 1910 | | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| 1911 | | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| 1912 | | }); |
| 1913 | | break :cc .o; |
| 1914 | | } else cc: { |
| 1915 | | try self.genSetReg(ty, limit_reg, .{ |
| 1916 | | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), |
| 1917 | | }); |
| 1918 | | break :cc .c; |
| 1919 | | }; |
| 1864 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 1865 | const rhs_lock = switch (rhs_mcv) { |
| 1866 | .register => |reg| self.register_manager.lockReg(reg), |
| 1867 | else => null, |
| 1868 | }; |
| 1869 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1920 | 1870 | |
| 1921 | | const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, ty, lhs_mcv, rhs_mcv); |
| 1922 | | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| 1923 | | try self.asmCmovccRegisterRegister( |
| 1924 | | registerAlias(dst_mcv.register, cmov_abi_size), |
| 1925 | | registerAlias(limit_reg, cmov_abi_size), |
| 1926 | | cc, |
| 1927 | | ); |
| 1928 | | break :result dst_mcv; |
| 1871 | const limit_reg = try self.register_manager.allocReg(null, gp); |
| 1872 | const limit_mcv = MCValue{ .register = limit_reg }; |
| 1873 | const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg); |
| 1874 | defer self.register_manager.unlockReg(limit_lock); |
| 1875 | |
| 1876 | const reg_bits = self.regBitSize(ty); |
| 1877 | const cc: Condition = if (ty.isSignedInt()) cc: { |
| 1878 | try self.genSetReg(ty, limit_reg, lhs_mcv); |
| 1879 | try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv); |
| 1880 | try self.genShiftBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 1881 | try self.genBinOpMir(.xor, ty, limit_mcv, .{ |
| 1882 | .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1, |
| 1883 | }); |
| 1884 | break :cc .o; |
| 1885 | } else cc: { |
| 1886 | try self.genSetReg(ty, limit_reg, .{ |
| 1887 | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits), |
| 1888 | }); |
| 1889 | break :cc .c; |
| 1929 | 1890 | }; |
| 1930 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1891 | |
| 1892 | const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, ty, lhs_mcv, rhs_mcv); |
| 1893 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); |
| 1894 | try self.asmCmovccRegisterRegister( |
| 1895 | registerAlias(dst_mcv.register, cmov_abi_size), |
| 1896 | registerAlias(limit_reg, cmov_abi_size), |
| 1897 | cc, |
| 1898 | ); |
| 1899 | |
| 1900 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1931 | 1901 | } |
| 1932 | 1902 | |
| 1933 | 1903 | fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1934 | 1904 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1935 | 1905 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1936 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 1906 | const result: MCValue = result: { |
| 1937 | 1907 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1938 | 1908 | const ty = self.air.typeOf(bin_op.lhs); |
| 1939 | 1909 | switch (ty.zigTypeTag()) { |
| ... | ... | @@ -1992,7 +1962,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1992 | 1962 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1993 | 1963 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1994 | 1964 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1995 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 1965 | const result: MCValue = result: { |
| 1996 | 1966 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 1997 | 1967 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 1998 | 1968 | switch (lhs_ty.zigTypeTag()) { |
| ... | ... | @@ -2114,7 +2084,7 @@ fn genSetStackTruncatedOverflowCompare( |
| 2114 | 2084 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2115 | 2085 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2116 | 2086 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2117 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 2087 | const result: MCValue = result: { |
| 2118 | 2088 | const dst_ty = self.air.typeOf(bin_op.lhs); |
| 2119 | 2089 | switch (dst_ty.zigTypeTag()) { |
| 2120 | 2090 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| ... | ... | @@ -2303,10 +2273,6 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 2303 | 2273 | fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2304 | 2274 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2305 | 2275 | |
| 2306 | | if (self.liveness.isUnused(inst)) { |
| 2307 | | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2308 | | } |
| 2309 | | |
| 2310 | 2276 | try self.spillRegisters(&.{.rcx}); |
| 2311 | 2277 | |
| 2312 | 2278 | const tag = self.air.instructions.items(.tag)[inst]; |
| ... | ... | @@ -2323,18 +2289,14 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2323 | 2289 | |
| 2324 | 2290 | fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2325 | 2291 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2326 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 2327 | | .unreach |
| 2328 | | else |
| 2329 | | return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); |
| 2330 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2292 | _ = bin_op; |
| 2293 | return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); |
| 2294 | //return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2331 | 2295 | } |
| 2332 | 2296 | |
| 2333 | 2297 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2334 | 2298 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2335 | 2299 | const result: MCValue = result: { |
| 2336 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 2337 | | |
| 2338 | 2300 | const pl_ty = self.air.typeOfIndex(inst); |
| 2339 | 2301 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 2340 | 2302 | |
| ... | ... | @@ -2359,18 +2321,15 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2359 | 2321 | |
| 2360 | 2322 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2361 | 2323 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2362 | | const result: MCValue = result: { |
| 2363 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 2364 | 2324 | |
| 2365 | | const dst_ty = self.air.typeOfIndex(inst); |
| 2366 | | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 2325 | const dst_ty = self.air.typeOfIndex(inst); |
| 2326 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 2367 | 2327 | |
| 2368 | | break :result if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) |
| 2369 | | opt_mcv |
| 2370 | | else |
| 2371 | | try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv); |
| 2372 | | }; |
| 2373 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2328 | const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) |
| 2329 | opt_mcv |
| 2330 | else |
| 2331 | try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv); |
| 2332 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2374 | 2333 | } |
| 2375 | 2334 | |
| 2376 | 2335 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -2409,9 +2368,6 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 2409 | 2368 | |
| 2410 | 2369 | fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2411 | 2370 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2412 | | if (self.liveness.isUnused(inst)) { |
| 2413 | | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); |
| 2414 | | } |
| 2415 | 2371 | const err_union_ty = self.air.typeOf(ty_op.operand); |
| 2416 | 2372 | const err_ty = err_union_ty.errorUnionSet(); |
| 2417 | 2373 | const payload_ty = err_union_ty.errorUnionPayload(); |
| ... | ... | @@ -2454,9 +2410,6 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2454 | 2410 | |
| 2455 | 2411 | fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2456 | 2412 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2457 | | if (self.liveness.isUnused(inst)) { |
| 2458 | | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); |
| 2459 | | } |
| 2460 | 2413 | const err_union_ty = self.air.typeOf(ty_op.operand); |
| 2461 | 2414 | const operand = try self.resolveInst(ty_op.operand); |
| 2462 | 2415 | const result = try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, operand); |
| ... | ... | @@ -2507,72 +2460,68 @@ fn genUnwrapErrorUnionPayloadMir( |
| 2507 | 2460 | // *(E!T) -> E |
| 2508 | 2461 | fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2509 | 2462 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2510 | | const result: MCValue = result: { |
| 2511 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 2512 | 2463 | |
| 2513 | | const src_ty = self.air.typeOf(ty_op.operand); |
| 2514 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2515 | | const src_reg = switch (src_mcv) { |
| 2516 | | .register => |reg| reg, |
| 2517 | | else => try self.copyToTmpRegister(src_ty, src_mcv), |
| 2518 | | }; |
| 2519 | | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 2520 | | defer self.register_manager.unlockReg(src_lock); |
| 2464 | const src_ty = self.air.typeOf(ty_op.operand); |
| 2465 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2466 | const src_reg = switch (src_mcv) { |
| 2467 | .register => |reg| reg, |
| 2468 | else => try self.copyToTmpRegister(src_ty, src_mcv), |
| 2469 | }; |
| 2470 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 2471 | defer self.register_manager.unlockReg(src_lock); |
| 2521 | 2472 | |
| 2522 | | const dst_reg = try self.register_manager.allocReg(inst, gp); |
| 2523 | | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 2524 | | defer self.register_manager.unlockReg(dst_lock); |
| 2473 | const dst_reg = try self.register_manager.allocReg(inst, gp); |
| 2474 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 2475 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 2476 | defer self.register_manager.unlockReg(dst_lock); |
| 2525 | 2477 | |
| 2526 | | const eu_ty = src_ty.childType(); |
| 2527 | | const pl_ty = eu_ty.errorUnionPayload(); |
| 2528 | | const err_ty = eu_ty.errorUnionSet(); |
| 2529 | | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); |
| 2530 | | const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*)); |
| 2531 | | try self.asmRegisterMemory( |
| 2532 | | .mov, |
| 2533 | | registerAlias(dst_reg, err_abi_size), |
| 2534 | | Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{ .base = src_reg, .disp = err_off }), |
| 2535 | | ); |
| 2536 | | break :result .{ .register = dst_reg }; |
| 2537 | | }; |
| 2538 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2478 | const eu_ty = src_ty.childType(); |
| 2479 | const pl_ty = eu_ty.errorUnionPayload(); |
| 2480 | const err_ty = eu_ty.errorUnionSet(); |
| 2481 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); |
| 2482 | const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*)); |
| 2483 | try self.asmRegisterMemory( |
| 2484 | .mov, |
| 2485 | registerAlias(dst_reg, err_abi_size), |
| 2486 | Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{ .base = src_reg, .disp = err_off }), |
| 2487 | ); |
| 2488 | |
| 2489 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2539 | 2490 | } |
| 2540 | 2491 | |
| 2541 | 2492 | // *(E!T) -> *T |
| 2542 | 2493 | fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2543 | 2494 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2544 | | const result: MCValue = result: { |
| 2545 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 2546 | 2495 | |
| 2547 | | const src_ty = self.air.typeOf(ty_op.operand); |
| 2548 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2549 | | const src_reg = switch (src_mcv) { |
| 2550 | | .register => |reg| reg, |
| 2551 | | else => try self.copyToTmpRegister(src_ty, src_mcv), |
| 2552 | | }; |
| 2553 | | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 2554 | | defer self.register_manager.unlockReg(src_lock); |
| 2496 | const src_ty = self.air.typeOf(ty_op.operand); |
| 2497 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2498 | const src_reg = switch (src_mcv) { |
| 2499 | .register => |reg| reg, |
| 2500 | else => try self.copyToTmpRegister(src_ty, src_mcv), |
| 2501 | }; |
| 2502 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 2503 | defer self.register_manager.unlockReg(src_lock); |
| 2555 | 2504 | |
| 2556 | | const dst_ty = self.air.typeOfIndex(inst); |
| 2557 | | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2558 | | src_reg |
| 2559 | | else |
| 2560 | | try self.register_manager.allocReg(inst, gp); |
| 2561 | | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 2562 | | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2505 | const dst_ty = self.air.typeOfIndex(inst); |
| 2506 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2507 | src_reg |
| 2508 | else |
| 2509 | try self.register_manager.allocReg(inst, gp); |
| 2510 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 2511 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 2512 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2563 | 2513 | |
| 2564 | | const eu_ty = src_ty.childType(); |
| 2565 | | const pl_ty = eu_ty.errorUnionPayload(); |
| 2566 | | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); |
| 2567 | | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 2568 | | try self.asmRegisterMemory( |
| 2569 | | .lea, |
| 2570 | | registerAlias(dst_reg, dst_abi_size), |
| 2571 | | Memory.sib(.qword, .{ .base = src_reg, .disp = pl_off }), |
| 2572 | | ); |
| 2573 | | break :result .{ .register = dst_reg }; |
| 2574 | | }; |
| 2575 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2514 | const eu_ty = src_ty.childType(); |
| 2515 | const pl_ty = eu_ty.errorUnionPayload(); |
| 2516 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); |
| 2517 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 2518 | try self.asmRegisterMemory( |
| 2519 | .lea, |
| 2520 | registerAlias(dst_reg, dst_abi_size), |
| 2521 | Memory.sib(.qword, .{ .base = src_reg, .disp = pl_off }), |
| 2522 | ); |
| 2523 | |
| 2524 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2576 | 2525 | } |
| 2577 | 2526 | |
| 2578 | 2527 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -2621,11 +2570,9 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 2621 | 2570 | } |
| 2622 | 2571 | |
| 2623 | 2572 | fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { |
| 2624 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 2625 | | .unreach |
| 2626 | | else |
| 2627 | | return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch}); |
| 2628 | | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 2573 | _ = inst; |
| 2574 | return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch}); |
| 2575 | //return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 2629 | 2576 | } |
| 2630 | 2577 | |
| 2631 | 2578 | fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -2641,8 +2588,6 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { |
| 2641 | 2588 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2642 | 2589 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2643 | 2590 | const result: MCValue = result: { |
| 2644 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 2645 | | |
| 2646 | 2591 | const pl_ty = self.air.typeOf(ty_op.operand); |
| 2647 | 2592 | if (!pl_ty.hasRuntimeBits()) break :result .{ .immediate = 1 }; |
| 2648 | 2593 | |
| ... | ... | @@ -2687,10 +2632,6 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2687 | 2632 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2688 | 2633 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2689 | 2634 | |
| 2690 | | if (self.liveness.isUnused(inst)) { |
| 2691 | | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); |
| 2692 | | } |
| 2693 | | |
| 2694 | 2635 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2695 | 2636 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2696 | 2637 | const operand = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -2717,9 +2658,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2717 | 2658 | /// E to E!T |
| 2718 | 2659 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2719 | 2660 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2720 | | if (self.liveness.isUnused(inst)) { |
| 2721 | | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); |
| 2722 | | } |
| 2661 | |
| 2723 | 2662 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2724 | 2663 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2725 | 2664 | const operand = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -2745,7 +2684,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2745 | 2684 | |
| 2746 | 2685 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2747 | 2686 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2748 | | const result = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 2687 | const result = result: { |
| 2749 | 2688 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2750 | 2689 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 2751 | 2690 | |
| ... | ... | @@ -2759,72 +2698,65 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2759 | 2698 | |
| 2760 | 2699 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 2761 | 2700 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2762 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 2763 | | const operand = try self.resolveInst(ty_op.operand); |
| 2764 | | const dst_mcv: MCValue = blk: { |
| 2765 | | switch (operand) { |
| 2766 | | .stack_offset => |off| { |
| 2767 | | break :blk MCValue{ .stack_offset = off - 8 }; |
| 2768 | | }, |
| 2769 | | else => return self.fail("TODO implement slice_len for {}", .{operand}), |
| 2770 | | } |
| 2771 | | }; |
| 2772 | | break :result dst_mcv; |
| 2701 | |
| 2702 | const operand = try self.resolveInst(ty_op.operand); |
| 2703 | const dst_mcv: MCValue = blk: { |
| 2704 | switch (operand) { |
| 2705 | .stack_offset => |off| { |
| 2706 | break :blk MCValue{ .stack_offset = off - 8 }; |
| 2707 | }, |
| 2708 | else => return self.fail("TODO implement slice_len for {}", .{operand}), |
| 2709 | } |
| 2773 | 2710 | }; |
| 2774 | | log.debug("airSliceLen(%{d}): {}", .{ inst, result }); |
| 2775 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2711 | |
| 2712 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2776 | 2713 | } |
| 2777 | 2714 | |
| 2778 | 2715 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2779 | 2716 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2780 | | const result: MCValue = result: { |
| 2781 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 2782 | 2717 | |
| 2783 | | const src_ty = self.air.typeOf(ty_op.operand); |
| 2784 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2785 | | const src_reg = switch (src_mcv) { |
| 2786 | | .register => |reg| reg, |
| 2787 | | else => try self.copyToTmpRegister(src_ty, src_mcv), |
| 2788 | | }; |
| 2789 | | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 2790 | | defer self.register_manager.unlockReg(src_lock); |
| 2718 | const src_ty = self.air.typeOf(ty_op.operand); |
| 2719 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2720 | const src_reg = switch (src_mcv) { |
| 2721 | .register => |reg| reg, |
| 2722 | else => try self.copyToTmpRegister(src_ty, src_mcv), |
| 2723 | }; |
| 2724 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 2725 | defer self.register_manager.unlockReg(src_lock); |
| 2791 | 2726 | |
| 2792 | | const dst_ty = self.air.typeOfIndex(inst); |
| 2793 | | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2794 | | src_reg |
| 2795 | | else |
| 2796 | | try self.register_manager.allocReg(inst, gp); |
| 2797 | | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 2798 | | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2727 | const dst_ty = self.air.typeOfIndex(inst); |
| 2728 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2729 | src_reg |
| 2730 | else |
| 2731 | try self.register_manager.allocReg(inst, gp); |
| 2732 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 2733 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 2734 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2799 | 2735 | |
| 2800 | | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 2801 | | try self.asmRegisterMemory( |
| 2802 | | .lea, |
| 2803 | | registerAlias(dst_reg, dst_abi_size), |
| 2804 | | Memory.sib(.qword, .{ |
| 2805 | | .base = src_reg, |
| 2806 | | .disp = @divExact(self.target.cpu.arch.ptrBitWidth(), 8), |
| 2807 | | }), |
| 2808 | | ); |
| 2809 | | break :result .{ .register = dst_reg }; |
| 2810 | | }; |
| 2811 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2736 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 2737 | try self.asmRegisterMemory( |
| 2738 | .lea, |
| 2739 | registerAlias(dst_reg, dst_abi_size), |
| 2740 | Memory.sib(.qword, .{ |
| 2741 | .base = src_reg, |
| 2742 | .disp = @divExact(self.target.cpu.arch.ptrBitWidth(), 8), |
| 2743 | }), |
| 2744 | ); |
| 2745 | |
| 2746 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2812 | 2747 | } |
| 2813 | 2748 | |
| 2814 | 2749 | fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2815 | 2750 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2816 | | const result: MCValue = result: { |
| 2817 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 2818 | 2751 | |
| 2819 | | const dst_ty = self.air.typeOfIndex(inst); |
| 2820 | | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 2752 | const dst_ty = self.air.typeOfIndex(inst); |
| 2753 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 2821 | 2754 | |
| 2822 | | break :result if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) |
| 2823 | | opt_mcv |
| 2824 | | else |
| 2825 | | try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv); |
| 2826 | | }; |
| 2827 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2755 | const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) |
| 2756 | opt_mcv |
| 2757 | else |
| 2758 | try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv); |
| 2759 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2828 | 2760 | } |
| 2829 | 2761 | |
| 2830 | 2762 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| ... | ... | @@ -2892,34 +2824,26 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 2892 | 2824 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2893 | 2825 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2894 | 2826 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 2895 | | const result = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .unreach else result: { |
| 2896 | | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 2897 | | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| 2898 | | const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs); |
| 2899 | | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 2900 | | try self.load(dst_mcv, elem_ptr, slice_ptr_field_type); |
| 2901 | | break :result dst_mcv; |
| 2902 | | }; |
| 2903 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2827 | |
| 2828 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 2829 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| 2830 | const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs); |
| 2831 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 2832 | try self.load(dst_mcv, elem_ptr, slice_ptr_field_type); |
| 2833 | |
| 2834 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2904 | 2835 | } |
| 2905 | 2836 | |
| 2906 | 2837 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2907 | 2838 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2908 | 2839 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2909 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 2910 | | .unreach |
| 2911 | | else |
| 2912 | | try self.genSliceElemPtr(extra.lhs, extra.rhs); |
| 2913 | | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 2840 | const dst_mcv = try self.genSliceElemPtr(extra.lhs, extra.rhs); |
| 2841 | return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); |
| 2914 | 2842 | } |
| 2915 | 2843 | |
| 2916 | 2844 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2917 | 2845 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2918 | 2846 | |
| 2919 | | if (self.liveness.isUnused(inst)) { |
| 2920 | | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2921 | | } |
| 2922 | | |
| 2923 | 2847 | const array_ty = self.air.typeOf(bin_op.lhs); |
| 2924 | 2848 | const array = try self.resolveInst(bin_op.lhs); |
| 2925 | 2849 | const array_lock: ?RegisterLock = switch (array) { |
| ... | ... | @@ -2986,77 +2910,74 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2986 | 2910 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2987 | 2911 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2988 | 2912 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 2989 | | const result = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .unreach else result: { |
| 2990 | | // this is identical to the `airPtrElemPtr` codegen expect here an |
| 2991 | | // additional `mov` is needed at the end to get the actual value |
| 2992 | | |
| 2993 | | const elem_ty = ptr_ty.elemType2(); |
| 2994 | | const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*)); |
| 2995 | | const index_ty = self.air.typeOf(bin_op.rhs); |
| 2996 | | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 2997 | | const index_lock = switch (index_mcv) { |
| 2998 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2999 | | else => null, |
| 3000 | | }; |
| 3001 | | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| 3002 | 2913 | |
| 3003 | | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size); |
| 3004 | | const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 3005 | | defer self.register_manager.unlockReg(offset_lock); |
| 2914 | // this is identical to the `airPtrElemPtr` codegen expect here an |
| 2915 | // additional `mov` is needed at the end to get the actual value |
| 3006 | 2916 | |
| 3007 | | const ptr_mcv = try self.resolveInst(bin_op.lhs); |
| 3008 | | const elem_ptr_reg = if (ptr_mcv.isRegister() and self.liveness.operandDies(inst, 0)) |
| 3009 | | ptr_mcv.register |
| 3010 | | else |
| 3011 | | try self.copyToTmpRegister(ptr_ty, ptr_mcv); |
| 3012 | | const elem_ptr_lock = self.register_manager.lockRegAssumeUnused(elem_ptr_reg); |
| 3013 | | defer self.register_manager.unlockReg(elem_ptr_lock); |
| 3014 | | try self.asmRegisterRegister(.add, elem_ptr_reg, offset_reg); |
| 2917 | const elem_ty = ptr_ty.elemType2(); |
| 2918 | const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*)); |
| 2919 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 2920 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 2921 | const index_lock = switch (index_mcv) { |
| 2922 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2923 | else => null, |
| 2924 | }; |
| 2925 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| 3015 | 2926 | |
| 3016 | | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 3017 | | const dst_lock = switch (dst_mcv) { |
| 3018 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3019 | | else => null, |
| 3020 | | }; |
| 3021 | | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 3022 | | try self.load(dst_mcv, .{ .register = elem_ptr_reg }, ptr_ty); |
| 3023 | | break :result dst_mcv; |
| 2927 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size); |
| 2928 | const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 2929 | defer self.register_manager.unlockReg(offset_lock); |
| 2930 | |
| 2931 | const ptr_mcv = try self.resolveInst(bin_op.lhs); |
| 2932 | const elem_ptr_reg = if (ptr_mcv.isRegister() and self.liveness.operandDies(inst, 0)) |
| 2933 | ptr_mcv.register |
| 2934 | else |
| 2935 | try self.copyToTmpRegister(ptr_ty, ptr_mcv); |
| 2936 | const elem_ptr_lock = self.register_manager.lockRegAssumeUnused(elem_ptr_reg); |
| 2937 | defer self.register_manager.unlockReg(elem_ptr_lock); |
| 2938 | try self.asmRegisterRegister(.add, elem_ptr_reg, offset_reg); |
| 2939 | |
| 2940 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 2941 | const dst_lock = switch (dst_mcv) { |
| 2942 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2943 | else => null, |
| 3024 | 2944 | }; |
| 3025 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2945 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2946 | try self.load(dst_mcv, .{ .register = elem_ptr_reg }, ptr_ty); |
| 2947 | |
| 2948 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 3026 | 2949 | } |
| 3027 | 2950 | |
| 3028 | 2951 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3029 | 2952 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3030 | 2953 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3031 | 2954 | |
| 3032 | | const result = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 3033 | | const ptr_ty = self.air.typeOf(extra.lhs); |
| 3034 | | const ptr = try self.resolveInst(extra.lhs); |
| 3035 | | const ptr_lock: ?RegisterLock = switch (ptr) { |
| 3036 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3037 | | else => null, |
| 3038 | | }; |
| 3039 | | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 2955 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 2956 | const ptr = try self.resolveInst(extra.lhs); |
| 2957 | const ptr_lock: ?RegisterLock = switch (ptr) { |
| 2958 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2959 | else => null, |
| 2960 | }; |
| 2961 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 3040 | 2962 | |
| 3041 | | const elem_ty = ptr_ty.elemType2(); |
| 3042 | | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 3043 | | const index_ty = self.air.typeOf(extra.rhs); |
| 3044 | | const index = try self.resolveInst(extra.rhs); |
| 3045 | | const index_lock: ?RegisterLock = switch (index) { |
| 3046 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3047 | | else => null, |
| 3048 | | }; |
| 3049 | | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| 2963 | const elem_ty = ptr_ty.elemType2(); |
| 2964 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 2965 | const index_ty = self.air.typeOf(extra.rhs); |
| 2966 | const index = try self.resolveInst(extra.rhs); |
| 2967 | const index_lock: ?RegisterLock = switch (index) { |
| 2968 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2969 | else => null, |
| 2970 | }; |
| 2971 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| 2972 | |
| 2973 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 2974 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 2975 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 3050 | 2976 | |
| 3051 | | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 3052 | | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 3053 | | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2977 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| 2978 | try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 3054 | 2979 | |
| 3055 | | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| 3056 | | try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 3057 | | break :result dst_mcv; |
| 3058 | | }; |
| 3059 | | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 2980 | return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); |
| 3060 | 2981 | } |
| 3061 | 2982 | |
| 3062 | 2983 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -3098,9 +3019,6 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 3098 | 3019 | |
| 3099 | 3020 | fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 3100 | 3021 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3101 | | if (self.liveness.isUnused(inst)) { |
| 3102 | | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); |
| 3103 | | } |
| 3104 | 3022 | |
| 3105 | 3023 | const tag_ty = self.air.typeOfIndex(inst); |
| 3106 | 3024 | const union_ty = self.air.typeOf(ty_op.operand); |
| ... | ... | @@ -3152,8 +3070,6 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 3152 | 3070 | fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 3153 | 3071 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3154 | 3072 | const result = result: { |
| 3155 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 3156 | | |
| 3157 | 3073 | const dst_ty = self.air.typeOfIndex(inst); |
| 3158 | 3074 | const src_ty = self.air.typeOf(ty_op.operand); |
| 3159 | 3075 | |
| ... | ... | @@ -3221,8 +3137,6 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 3221 | 3137 | fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 3222 | 3138 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3223 | 3139 | const result = result: { |
| 3224 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 3225 | | |
| 3226 | 3140 | const dst_ty = self.air.typeOfIndex(inst); |
| 3227 | 3141 | const src_ty = self.air.typeOf(ty_op.operand); |
| 3228 | 3142 | const src_bits = src_ty.bitSize(self.target.*); |
| ... | ... | @@ -3279,8 +3193,6 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 3279 | 3193 | fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 3280 | 3194 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3281 | 3195 | const result: MCValue = result: { |
| 3282 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 3283 | | |
| 3284 | 3196 | const src_ty = self.air.typeOf(ty_op.operand); |
| 3285 | 3197 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| 3286 | 3198 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -3449,148 +3361,138 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m |
| 3449 | 3361 | |
| 3450 | 3362 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 3451 | 3363 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3452 | | const result = result: { |
| 3453 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 3454 | 3364 | |
| 3455 | | const src_ty = self.air.typeOf(ty_op.operand); |
| 3456 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3457 | | |
| 3458 | | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, true); |
| 3459 | | switch (self.regExtraBits(src_ty)) { |
| 3460 | | 0 => {}, |
| 3461 | | else => |extra| try self.genBinOpMir( |
| 3462 | | if (src_ty.isSignedInt()) .sar else .shr, |
| 3463 | | src_ty, |
| 3464 | | dst_mcv, |
| 3465 | | .{ .immediate = extra }, |
| 3466 | | ), |
| 3467 | | } |
| 3468 | | break :result dst_mcv; |
| 3469 | | }; |
| 3365 | const src_ty = self.air.typeOf(ty_op.operand); |
| 3366 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3367 | |
| 3368 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, true); |
| 3369 | switch (self.regExtraBits(src_ty)) { |
| 3370 | 0 => {}, |
| 3371 | else => |extra| try self.genBinOpMir( |
| 3372 | if (src_ty.isSignedInt()) .sar else .shr, |
| 3373 | src_ty, |
| 3374 | dst_mcv, |
| 3375 | .{ .immediate = extra }, |
| 3376 | ), |
| 3377 | } |
| 3470 | 3378 | |
| 3471 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3379 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 3472 | 3380 | } |
| 3473 | 3381 | |
| 3474 | 3382 | fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 3475 | 3383 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3476 | | const result = result: { |
| 3477 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 3478 | 3384 | |
| 3479 | | const src_ty = self.air.typeOf(ty_op.operand); |
| 3480 | | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| 3481 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3385 | const src_ty = self.air.typeOf(ty_op.operand); |
| 3386 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| 3387 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3482 | 3388 | |
| 3483 | | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, false); |
| 3484 | | const dst_reg = dst_mcv.register; |
| 3485 | | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 3486 | | defer self.register_manager.unlockReg(dst_lock); |
| 3389 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, false); |
| 3390 | const dst_reg = dst_mcv.register; |
| 3391 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 3392 | defer self.register_manager.unlockReg(dst_lock); |
| 3487 | 3393 | |
| 3488 | | const tmp_reg = try self.register_manager.allocReg(null, gp); |
| 3489 | | const tmp_lock = self.register_manager.lockReg(tmp_reg); |
| 3490 | | defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock); |
| 3394 | const tmp_reg = try self.register_manager.allocReg(null, gp); |
| 3395 | const tmp_lock = self.register_manager.lockReg(tmp_reg); |
| 3396 | defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock); |
| 3491 | 3397 | |
| 3492 | | { |
| 3493 | | const dst = registerAlias(dst_reg, src_abi_size); |
| 3494 | | const tmp = registerAlias(tmp_reg, src_abi_size); |
| 3495 | | const imm = if (src_abi_size > 4) |
| 3496 | | try self.register_manager.allocReg(null, gp) |
| 3497 | | else |
| 3498 | | undefined; |
| 3398 | { |
| 3399 | const dst = registerAlias(dst_reg, src_abi_size); |
| 3400 | const tmp = registerAlias(tmp_reg, src_abi_size); |
| 3401 | const imm = if (src_abi_size > 4) |
| 3402 | try self.register_manager.allocReg(null, gp) |
| 3403 | else |
| 3404 | undefined; |
| 3499 | 3405 | |
| 3500 | | const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - src_abi_size * 8); |
| 3501 | | const imm_0000_1111 = Immediate.u(mask / 0b0001_0001); |
| 3502 | | const imm_00_11 = Immediate.u(mask / 0b01_01); |
| 3503 | | const imm_0_1 = Immediate.u(mask / 0b1_1); |
| 3406 | const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - src_abi_size * 8); |
| 3407 | const imm_0000_1111 = Immediate.u(mask / 0b0001_0001); |
| 3408 | const imm_00_11 = Immediate.u(mask / 0b01_01); |
| 3409 | const imm_0_1 = Immediate.u(mask / 0b1_1); |
| 3504 | 3410 | |
| 3505 | | // dst = temp1 = bswap(operand) |
| 3506 | | try self.asmRegisterRegister(.mov, tmp, dst); |
| 3507 | | // tmp = temp1 |
| 3508 | | try self.asmRegisterImmediate(.shr, dst, Immediate.u(4)); |
| 3509 | | // dst = temp1 >> 4 |
| 3510 | | if (src_abi_size > 4) { |
| 3511 | | try self.asmRegisterImmediate(.mov, imm, imm_0000_1111); |
| 3512 | | try self.asmRegisterRegister(.@"and", tmp, imm); |
| 3513 | | try self.asmRegisterRegister(.@"and", dst, imm); |
| 3514 | | } else { |
| 3515 | | try self.asmRegisterImmediate(.@"and", tmp, imm_0000_1111); |
| 3516 | | try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111); |
| 3517 | | } |
| 3518 | | // tmp = temp1 & 0x0F...0F |
| 3519 | | // dst = (temp1 >> 4) & 0x0F...0F |
| 3520 | | try self.asmRegisterImmediate(.shl, tmp, Immediate.u(4)); |
| 3521 | | // tmp = (temp1 & 0x0F...0F) << 4 |
| 3522 | | try self.asmRegisterRegister(.@"or", dst, tmp); |
| 3523 | | // dst = temp2 = ((temp1 >> 4) & 0x0F...0F) | ((temp1 & 0x0F...0F) << 4) |
| 3524 | | try self.asmRegisterRegister(.mov, tmp, dst); |
| 3525 | | // tmp = temp2 |
| 3526 | | try self.asmRegisterImmediate(.shr, dst, Immediate.u(2)); |
| 3527 | | // dst = temp2 >> 2 |
| 3528 | | if (src_abi_size > 4) { |
| 3529 | | try self.asmRegisterImmediate(.mov, imm, imm_00_11); |
| 3530 | | try self.asmRegisterRegister(.@"and", tmp, imm); |
| 3531 | | try self.asmRegisterRegister(.@"and", dst, imm); |
| 3532 | | } else { |
| 3533 | | try self.asmRegisterImmediate(.@"and", tmp, imm_00_11); |
| 3534 | | try self.asmRegisterImmediate(.@"and", dst, imm_00_11); |
| 3535 | | } |
| 3536 | | // tmp = temp2 & 0x33...33 |
| 3537 | | // dst = (temp2 >> 2) & 0x33...33 |
| 3538 | | try self.asmRegisterMemory( |
| 3539 | | .lea, |
| 3540 | | if (src_abi_size > 4) tmp.to64() else tmp.to32(), |
| 3541 | | Memory.sib(.qword, .{ |
| 3542 | | .base = dst.to64(), |
| 3543 | | .scale_index = .{ .index = tmp.to64(), .scale = 1 << 2 }, |
| 3544 | | }), |
| 3545 | | ); |
| 3546 | | // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2) |
| 3547 | | try self.asmRegisterRegister(.mov, dst, tmp); |
| 3548 | | // dst = temp3 |
| 3549 | | try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1)); |
| 3550 | | // tmp = temp3 >> 1 |
| 3551 | | if (src_abi_size > 4) { |
| 3552 | | try self.asmRegisterImmediate(.mov, imm, imm_0_1); |
| 3553 | | try self.asmRegisterRegister(.@"and", dst, imm); |
| 3554 | | try self.asmRegisterRegister(.@"and", tmp, imm); |
| 3555 | | } else { |
| 3556 | | try self.asmRegisterImmediate(.@"and", dst, imm_0_1); |
| 3557 | | try self.asmRegisterImmediate(.@"and", tmp, imm_0_1); |
| 3558 | | } |
| 3559 | | // dst = temp3 & 0x55...55 |
| 3560 | | // tmp = (temp3 >> 1) & 0x55...55 |
| 3561 | | try self.asmRegisterMemory( |
| 3562 | | .lea, |
| 3563 | | if (src_abi_size > 4) dst.to64() else dst.to32(), |
| 3564 | | Memory.sib(.qword, .{ |
| 3565 | | .base = tmp.to64(), |
| 3566 | | .scale_index = .{ .index = dst.to64(), .scale = 1 << 1 }, |
| 3567 | | }), |
| 3568 | | ); |
| 3569 | | // dst = ((temp3 >> 1) & 0x55...55) + ((temp3 & 0x55...55) << 1) |
| 3411 | // dst = temp1 = bswap(operand) |
| 3412 | try self.asmRegisterRegister(.mov, tmp, dst); |
| 3413 | // tmp = temp1 |
| 3414 | try self.asmRegisterImmediate(.shr, dst, Immediate.u(4)); |
| 3415 | // dst = temp1 >> 4 |
| 3416 | if (src_abi_size > 4) { |
| 3417 | try self.asmRegisterImmediate(.mov, imm, imm_0000_1111); |
| 3418 | try self.asmRegisterRegister(.@"and", tmp, imm); |
| 3419 | try self.asmRegisterRegister(.@"and", dst, imm); |
| 3420 | } else { |
| 3421 | try self.asmRegisterImmediate(.@"and", tmp, imm_0000_1111); |
| 3422 | try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111); |
| 3423 | } |
| 3424 | // tmp = temp1 & 0x0F...0F |
| 3425 | // dst = (temp1 >> 4) & 0x0F...0F |
| 3426 | try self.asmRegisterImmediate(.shl, tmp, Immediate.u(4)); |
| 3427 | // tmp = (temp1 & 0x0F...0F) << 4 |
| 3428 | try self.asmRegisterRegister(.@"or", dst, tmp); |
| 3429 | // dst = temp2 = ((temp1 >> 4) & 0x0F...0F) | ((temp1 & 0x0F...0F) << 4) |
| 3430 | try self.asmRegisterRegister(.mov, tmp, dst); |
| 3431 | // tmp = temp2 |
| 3432 | try self.asmRegisterImmediate(.shr, dst, Immediate.u(2)); |
| 3433 | // dst = temp2 >> 2 |
| 3434 | if (src_abi_size > 4) { |
| 3435 | try self.asmRegisterImmediate(.mov, imm, imm_00_11); |
| 3436 | try self.asmRegisterRegister(.@"and", tmp, imm); |
| 3437 | try self.asmRegisterRegister(.@"and", dst, imm); |
| 3438 | } else { |
| 3439 | try self.asmRegisterImmediate(.@"and", tmp, imm_00_11); |
| 3440 | try self.asmRegisterImmediate(.@"and", dst, imm_00_11); |
| 3570 | 3441 | } |
| 3442 | // tmp = temp2 & 0x33...33 |
| 3443 | // dst = (temp2 >> 2) & 0x33...33 |
| 3444 | try self.asmRegisterMemory( |
| 3445 | .lea, |
| 3446 | if (src_abi_size > 4) tmp.to64() else tmp.to32(), |
| 3447 | Memory.sib(.qword, .{ |
| 3448 | .base = dst.to64(), |
| 3449 | .scale_index = .{ .index = tmp.to64(), .scale = 1 << 2 }, |
| 3450 | }), |
| 3451 | ); |
| 3452 | // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2) |
| 3453 | try self.asmRegisterRegister(.mov, dst, tmp); |
| 3454 | // dst = temp3 |
| 3455 | try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1)); |
| 3456 | // tmp = temp3 >> 1 |
| 3457 | if (src_abi_size > 4) { |
| 3458 | try self.asmRegisterImmediate(.mov, imm, imm_0_1); |
| 3459 | try self.asmRegisterRegister(.@"and", dst, imm); |
| 3460 | try self.asmRegisterRegister(.@"and", tmp, imm); |
| 3461 | } else { |
| 3462 | try self.asmRegisterImmediate(.@"and", dst, imm_0_1); |
| 3463 | try self.asmRegisterImmediate(.@"and", tmp, imm_0_1); |
| 3464 | } |
| 3465 | // dst = temp3 & 0x55...55 |
| 3466 | // tmp = (temp3 >> 1) & 0x55...55 |
| 3467 | try self.asmRegisterMemory( |
| 3468 | .lea, |
| 3469 | if (src_abi_size > 4) dst.to64() else dst.to32(), |
| 3470 | Memory.sib(.qword, .{ |
| 3471 | .base = tmp.to64(), |
| 3472 | .scale_index = .{ .index = dst.to64(), .scale = 1 << 1 }, |
| 3473 | }), |
| 3474 | ); |
| 3475 | // dst = ((temp3 >> 1) & 0x55...55) + ((temp3 & 0x55...55) << 1) |
| 3476 | } |
| 3571 | 3477 | |
| 3572 | | switch (self.regExtraBits(src_ty)) { |
| 3573 | | 0 => {}, |
| 3574 | | else => |extra| try self.genBinOpMir( |
| 3575 | | if (src_ty.isSignedInt()) .sar else .shr, |
| 3576 | | src_ty, |
| 3577 | | dst_mcv, |
| 3578 | | .{ .immediate = extra }, |
| 3579 | | ), |
| 3580 | | } |
| 3581 | | break :result dst_mcv; |
| 3582 | | }; |
| 3478 | switch (self.regExtraBits(src_ty)) { |
| 3479 | 0 => {}, |
| 3480 | else => |extra| try self.genBinOpMir( |
| 3481 | if (src_ty.isSignedInt()) .sar else .shr, |
| 3482 | src_ty, |
| 3483 | dst_mcv, |
| 3484 | .{ .immediate = extra }, |
| 3485 | ), |
| 3486 | } |
| 3583 | 3487 | |
| 3584 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3488 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 3585 | 3489 | } |
| 3586 | 3490 | |
| 3587 | 3491 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { |
| 3588 | 3492 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 3589 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 3590 | | .unreach |
| 3591 | | else |
| 3592 | | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); |
| 3593 | | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 3493 | _ = un_op; |
| 3494 | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); |
| 3495 | //return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 3594 | 3496 | } |
| 3595 | 3497 | |
| 3596 | 3498 | fn reuseOperand( |
| ... | ... | @@ -3763,9 +3665,6 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3763 | 3665 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 3764 | 3666 | |
| 3765 | 3667 | const ptr = try self.resolveInst(ty_op.operand); |
| 3766 | | const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr(); |
| 3767 | | if (self.liveness.isUnused(inst) and !is_volatile) break :result .unreach; |
| 3768 | | |
| 3769 | 3668 | const dst_mcv: MCValue = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) |
| 3770 | 3669 | // The MCValue that holds the pointer can be re-used as the value. |
| 3771 | 3670 | ptr |
| ... | ... | @@ -4062,10 +3961,6 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 4062 | 3961 | } |
| 4063 | 3962 | |
| 4064 | 3963 | fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 4065 | | if (self.liveness.isUnused(inst)) { |
| 4066 | | return MCValue.unreach; |
| 4067 | | } |
| 4068 | | |
| 4069 | 3964 | const mcv = try self.resolveInst(operand); |
| 4070 | 3965 | const ptr_ty = self.air.typeOf(operand); |
| 4071 | 3966 | const container_ty = ptr_ty.childType(); |
| ... | ... | @@ -4132,7 +4027,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 |
| 4132 | 4027 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4133 | 4028 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 4134 | 4029 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 4135 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 4030 | const result: MCValue = result: { |
| 4136 | 4031 | const operand = extra.struct_operand; |
| 4137 | 4032 | const index = extra.field_index; |
| 4138 | 4033 | |
| ... | ... | @@ -4280,11 +4175,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4280 | 4175 | |
| 4281 | 4176 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4282 | 4177 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4283 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 4284 | | .unreach |
| 4285 | | else |
| 4286 | | return self.fail("TODO implement airFieldParentPtr for {}", .{self.target.cpu.arch}); |
| 4287 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 4178 | _ = ty_op; |
| 4179 | return self.fail("TODO implement airFieldParentPtr for {}", .{self.target.cpu.arch}); |
| 4180 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 4288 | 4181 | } |
| 4289 | 4182 | |
| 4290 | 4183 | fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { |
| ... | ... | @@ -5503,9 +5396,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 5503 | 5396 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 5504 | 5397 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index); |
| 5505 | 5398 | |
| 5506 | | const result: MCValue = result: { |
| 5507 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 5508 | | |
| 5399 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 5509 | 5400 | const dst_mcv: MCValue = switch (mcv) { |
| 5510 | 5401 | .register => |reg| blk: { |
| 5511 | 5402 | self.register_manager.getRegAssumeFree(reg.to64(), inst); |
| ... | ... | @@ -5596,23 +5487,17 @@ fn airBreakpoint(self: *Self) !void { |
| 5596 | 5487 | } |
| 5597 | 5488 | |
| 5598 | 5489 | fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void { |
| 5599 | | const result = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 5600 | | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 5601 | | try self.setRegOrMem(Type.usize, dst_mcv, .{ |
| 5602 | | .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)), |
| 5603 | | }); |
| 5604 | | break :result dst_mcv; |
| 5605 | | }; |
| 5606 | | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 5490 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 5491 | try self.setRegOrMem(Type.usize, dst_mcv, .{ |
| 5492 | .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)), |
| 5493 | }); |
| 5494 | return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); |
| 5607 | 5495 | } |
| 5608 | 5496 | |
| 5609 | 5497 | fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void { |
| 5610 | | const result = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 5611 | | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 5612 | | try self.setRegOrMem(Type.usize, dst_mcv, .{ .register = .rbp }); |
| 5613 | | break :result dst_mcv; |
| 5614 | | }; |
| 5615 | | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 5498 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 5499 | try self.setRegOrMem(Type.usize, dst_mcv, .{ .register = .rbp }); |
| 5500 | return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); |
| 5616 | 5501 | } |
| 5617 | 5502 | |
| 5618 | 5503 | fn airFence(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -5892,60 +5777,58 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 5892 | 5777 | |
| 5893 | 5778 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 5894 | 5779 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5895 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 5896 | | const ty = self.air.typeOf(bin_op.lhs); |
| 5897 | | const ty_abi_size = ty.abiSize(self.target.*); |
| 5898 | | const can_reuse = ty_abi_size <= 8; |
| 5780 | const ty = self.air.typeOf(bin_op.lhs); |
| 5781 | const ty_abi_size = ty.abiSize(self.target.*); |
| 5782 | const can_reuse = ty_abi_size <= 8; |
| 5899 | 5783 | |
| 5900 | | try self.spillEflagsIfOccupied(); |
| 5901 | | self.eflags_inst = inst; |
| 5784 | try self.spillEflagsIfOccupied(); |
| 5785 | self.eflags_inst = inst; |
| 5902 | 5786 | |
| 5903 | | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 5904 | | const lhs_lock = switch (lhs_mcv) { |
| 5905 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5906 | | else => null, |
| 5907 | | }; |
| 5908 | | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 5787 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 5788 | const lhs_lock = switch (lhs_mcv) { |
| 5789 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5790 | else => null, |
| 5791 | }; |
| 5792 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 5909 | 5793 | |
| 5910 | | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 5911 | | const rhs_lock = switch (rhs_mcv) { |
| 5912 | | .register => |reg| self.register_manager.lockReg(reg), |
| 5913 | | else => null, |
| 5914 | | }; |
| 5915 | | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 5916 | | |
| 5917 | | const dst_mem_ok = !ty.isRuntimeFloat(); |
| 5918 | | var flipped = false; |
| 5919 | | const dst_mcv: MCValue = if (can_reuse and !lhs_mcv.isImmediate() and |
| 5920 | | (dst_mem_ok or lhs_mcv.isRegister()) and self.liveness.operandDies(inst, 0)) |
| 5921 | | lhs_mcv |
| 5922 | | else if (can_reuse and !rhs_mcv.isImmediate() and |
| 5923 | | (dst_mem_ok or rhs_mcv.isRegister()) and self.liveness.operandDies(inst, 1)) |
| 5924 | | dst: { |
| 5925 | | flipped = true; |
| 5926 | | break :dst rhs_mcv; |
| 5927 | | } else if (dst_mem_ok) dst: { |
| 5928 | | const dst_mcv = try self.allocTempRegOrMem(ty, true); |
| 5929 | | try self.setRegOrMem(ty, dst_mcv, lhs_mcv); |
| 5930 | | break :dst dst_mcv; |
| 5931 | | } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) }; |
| 5932 | | const dst_lock = switch (dst_mcv) { |
| 5933 | | .register => |reg| self.register_manager.lockReg(reg), |
| 5934 | | else => null, |
| 5935 | | }; |
| 5936 | | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5794 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 5795 | const rhs_lock = switch (rhs_mcv) { |
| 5796 | .register => |reg| self.register_manager.lockReg(reg), |
| 5797 | else => null, |
| 5798 | }; |
| 5799 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 5800 | |
| 5801 | const dst_mem_ok = !ty.isRuntimeFloat(); |
| 5802 | var flipped = false; |
| 5803 | const dst_mcv: MCValue = if (can_reuse and !lhs_mcv.isImmediate() and |
| 5804 | (dst_mem_ok or lhs_mcv.isRegister()) and self.liveness.operandDies(inst, 0)) |
| 5805 | lhs_mcv |
| 5806 | else if (can_reuse and !rhs_mcv.isImmediate() and |
| 5807 | (dst_mem_ok or rhs_mcv.isRegister()) and self.liveness.operandDies(inst, 1)) |
| 5808 | dst: { |
| 5809 | flipped = true; |
| 5810 | break :dst rhs_mcv; |
| 5811 | } else if (dst_mem_ok) dst: { |
| 5812 | const dst_mcv = try self.allocTempRegOrMem(ty, true); |
| 5813 | try self.setRegOrMem(ty, dst_mcv, lhs_mcv); |
| 5814 | break :dst dst_mcv; |
| 5815 | } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) }; |
| 5816 | const dst_lock = switch (dst_mcv) { |
| 5817 | .register => |reg| self.register_manager.lockReg(reg), |
| 5818 | else => null, |
| 5819 | }; |
| 5820 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5937 | 5821 | |
| 5938 | | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; |
| 5939 | | try self.genBinOpMir(switch (ty.tag()) { |
| 5940 | | else => .cmp, |
| 5941 | | .f32 => .ucomiss, |
| 5942 | | .f64 => .ucomisd, |
| 5943 | | }, ty, dst_mcv, src_mcv); |
| 5822 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; |
| 5823 | try self.genBinOpMir(switch (ty.tag()) { |
| 5824 | else => .cmp, |
| 5825 | .f32 => .ucomiss, |
| 5826 | .f64 => .ucomisd, |
| 5827 | }, ty, dst_mcv, src_mcv); |
| 5944 | 5828 | |
| 5945 | | const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned; |
| 5946 | | break :result .{ |
| 5947 | | .eflags = Condition.fromCompareOperator(signedness, if (flipped) op.reverse() else op), |
| 5948 | | }; |
| 5829 | const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned; |
| 5830 | const result = MCValue{ |
| 5831 | .eflags = Condition.fromCompareOperator(signedness, if (flipped) op.reverse() else op), |
| 5949 | 5832 | }; |
| 5950 | 5833 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 5951 | 5834 | } |
| ... | ... | @@ -5957,56 +5840,55 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { |
| 5957 | 5840 | |
| 5958 | 5841 | fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 5959 | 5842 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5960 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 5961 | | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 5962 | | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 5963 | | defer self.register_manager.unlockReg(addr_lock); |
| 5964 | | |
| 5965 | | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 5966 | | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( |
| 5967 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 5968 | | 4, // dword alignment |
| 5969 | | ); |
| 5970 | | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); |
| 5971 | | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ |
| 5972 | | .base = .ds, |
| 5973 | | .disp = @intCast(i32, got_addr), |
| 5974 | | })); |
| 5975 | | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 5976 | | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( |
| 5977 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 5978 | | 4, // dword alignment |
| 5979 | | ); |
| 5980 | | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 5981 | | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| 5982 | | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 5983 | | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( |
| 5984 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 5985 | | 4, // dword alignment |
| 5986 | | ); |
| 5987 | | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 5988 | | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| 5989 | | } else { |
| 5990 | | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); |
| 5991 | | } |
| 5992 | 5843 | |
| 5993 | | try self.spillEflagsIfOccupied(); |
| 5994 | | self.eflags_inst = inst; |
| 5844 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 5845 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 5846 | defer self.register_manager.unlockReg(addr_lock); |
| 5995 | 5847 | |
| 5996 | | const op_ty = self.air.typeOf(un_op); |
| 5997 | | const op_abi_size = @intCast(u32, op_ty.abiSize(self.target.*)); |
| 5998 | | const op_mcv = try self.resolveInst(un_op); |
| 5999 | | const dst_reg = switch (op_mcv) { |
| 6000 | | .register => |reg| reg, |
| 6001 | | else => try self.copyToTmpRegister(op_ty, op_mcv), |
| 6002 | | }; |
| 6003 | | try self.asmRegisterMemory( |
| 6004 | | .cmp, |
| 6005 | | registerAlias(dst_reg, op_abi_size), |
| 6006 | | Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = addr_reg }), |
| 5848 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 5849 | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( |
| 5850 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 5851 | 4, // dword alignment |
| 5852 | ); |
| 5853 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); |
| 5854 | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ |
| 5855 | .base = .ds, |
| 5856 | .disp = @intCast(i32, got_addr), |
| 5857 | })); |
| 5858 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 5859 | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( |
| 5860 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 5861 | 4, // dword alignment |
| 6007 | 5862 | ); |
| 6008 | | break :result .{ .eflags = .b }; |
| 5863 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 5864 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| 5865 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 5866 | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( |
| 5867 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 5868 | 4, // dword alignment |
| 5869 | ); |
| 5870 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 5871 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| 5872 | } else { |
| 5873 | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); |
| 5874 | } |
| 5875 | |
| 5876 | try self.spillEflagsIfOccupied(); |
| 5877 | self.eflags_inst = inst; |
| 5878 | |
| 5879 | const op_ty = self.air.typeOf(un_op); |
| 5880 | const op_abi_size = @intCast(u32, op_ty.abiSize(self.target.*)); |
| 5881 | const op_mcv = try self.resolveInst(un_op); |
| 5882 | const dst_reg = switch (op_mcv) { |
| 5883 | .register => |reg| reg, |
| 5884 | else => try self.copyToTmpRegister(op_ty, op_mcv), |
| 6009 | 5885 | }; |
| 5886 | try self.asmRegisterMemory( |
| 5887 | .cmp, |
| 5888 | registerAlias(dst_reg, op_abi_size), |
| 5889 | Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = addr_reg }), |
| 5890 | ); |
| 5891 | const result = MCValue{ .eflags = .b }; |
| 6010 | 5892 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6011 | 5893 | } |
| 6012 | 5894 | |
| ... | ... | @@ -6365,67 +6247,53 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCVa |
| 6365 | 6247 | |
| 6366 | 6248 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 6367 | 6249 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6368 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 6369 | | const operand = try self.resolveInst(un_op); |
| 6370 | | const ty = self.air.typeOf(un_op); |
| 6371 | | break :result try self.isNull(inst, ty, operand); |
| 6372 | | }; |
| 6250 | const operand = try self.resolveInst(un_op); |
| 6251 | const ty = self.air.typeOf(un_op); |
| 6252 | const result = try self.isNull(inst, ty, operand); |
| 6373 | 6253 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6374 | 6254 | } |
| 6375 | 6255 | |
| 6376 | 6256 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6377 | 6257 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6378 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 6379 | | const operand = try self.resolveInst(un_op); |
| 6380 | | const ty = self.air.typeOf(un_op); |
| 6381 | | break :result try self.isNullPtr(inst, ty, operand); |
| 6382 | | }; |
| 6258 | const operand = try self.resolveInst(un_op); |
| 6259 | const ty = self.air.typeOf(un_op); |
| 6260 | const result = try self.isNullPtr(inst, ty, operand); |
| 6383 | 6261 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6384 | 6262 | } |
| 6385 | 6263 | |
| 6386 | 6264 | fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 6387 | 6265 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6388 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 6389 | | const operand = try self.resolveInst(un_op); |
| 6390 | | const ty = self.air.typeOf(un_op); |
| 6391 | | break :result switch (try self.isNull(inst, ty, operand)) { |
| 6392 | | .eflags => |cc| .{ .eflags = cc.negate() }, |
| 6393 | | else => unreachable, |
| 6394 | | }; |
| 6266 | const operand = try self.resolveInst(un_op); |
| 6267 | const ty = self.air.typeOf(un_op); |
| 6268 | const result = switch (try self.isNull(inst, ty, operand)) { |
| 6269 | .eflags => |cc| .{ .eflags = cc.negate() }, |
| 6270 | else => unreachable, |
| 6395 | 6271 | }; |
| 6396 | 6272 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6397 | 6273 | } |
| 6398 | 6274 | |
| 6399 | 6275 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6400 | 6276 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6401 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 6402 | | const operand = try self.resolveInst(un_op); |
| 6403 | | const ty = self.air.typeOf(un_op); |
| 6404 | | break :result switch (try self.isNullPtr(inst, ty, operand)) { |
| 6405 | | .eflags => |cc| .{ .eflags = cc.negate() }, |
| 6406 | | else => unreachable, |
| 6407 | | }; |
| 6277 | const operand = try self.resolveInst(un_op); |
| 6278 | const ty = self.air.typeOf(un_op); |
| 6279 | const result = switch (try self.isNullPtr(inst, ty, operand)) { |
| 6280 | .eflags => |cc| .{ .eflags = cc.negate() }, |
| 6281 | else => unreachable, |
| 6408 | 6282 | }; |
| 6409 | 6283 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6410 | 6284 | } |
| 6411 | 6285 | |
| 6412 | 6286 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 6413 | 6287 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6414 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 6415 | | const operand = try self.resolveInst(un_op); |
| 6416 | | const ty = self.air.typeOf(un_op); |
| 6417 | | break :result try self.isErr(inst, ty, operand); |
| 6418 | | }; |
| 6288 | const operand = try self.resolveInst(un_op); |
| 6289 | const ty = self.air.typeOf(un_op); |
| 6290 | const result = try self.isErr(inst, ty, operand); |
| 6419 | 6291 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6420 | 6292 | } |
| 6421 | 6293 | |
| 6422 | 6294 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6423 | 6295 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6424 | 6296 | |
| 6425 | | if (self.liveness.isUnused(inst)) { |
| 6426 | | return self.finishAir(inst, .unreach, .{ un_op, .none, .none }); |
| 6427 | | } |
| 6428 | | |
| 6429 | 6297 | const operand_ptr = try self.resolveInst(un_op); |
| 6430 | 6298 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 6431 | 6299 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -6451,21 +6319,15 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6451 | 6319 | |
| 6452 | 6320 | fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 6453 | 6321 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6454 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 6455 | | const operand = try self.resolveInst(un_op); |
| 6456 | | const ty = self.air.typeOf(un_op); |
| 6457 | | break :result try self.isNonErr(inst, ty, operand); |
| 6458 | | }; |
| 6322 | const operand = try self.resolveInst(un_op); |
| 6323 | const ty = self.air.typeOf(un_op); |
| 6324 | const result = try self.isNonErr(inst, ty, operand); |
| 6459 | 6325 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 6460 | 6326 | } |
| 6461 | 6327 | |
| 6462 | 6328 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6463 | 6329 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6464 | 6330 | |
| 6465 | | if (self.liveness.isUnused(inst)) { |
| 6466 | | return self.finishAir(inst, .unreach, .{ un_op, .none, .none }); |
| 6467 | | } |
| 6468 | | |
| 6469 | 6331 | const operand_ptr = try self.resolveInst(un_op); |
| 6470 | 6332 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 6471 | 6333 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -6691,7 +6553,6 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 6691 | 6553 | fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 6692 | 6554 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 6693 | 6555 | const extra = self.air.extraData(Air.Asm, ty_pl.payload); |
| 6694 | | const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0; |
| 6695 | 6556 | const clobbers_len = @truncate(u31, extra.data.flags); |
| 6696 | 6557 | var extra_i: usize = extra.end; |
| 6697 | 6558 | const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); |
| ... | ... | @@ -6700,216 +6561,214 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 6700 | 6561 | extra_i += inputs.len; |
| 6701 | 6562 | |
| 6702 | 6563 | var result: MCValue = .none; |
| 6703 | | if (!is_volatile and self.liveness.isUnused(inst)) result = .unreach else { |
| 6704 | | var args = std.StringArrayHashMap(MCValue).init(self.gpa); |
| 6705 | | try args.ensureTotalCapacity(outputs.len + inputs.len + clobbers_len); |
| 6706 | | defer { |
| 6707 | | for (args.values()) |arg| switch (arg) { |
| 6708 | | .register => |reg| self.register_manager.unlockReg(.{ .register = reg }), |
| 6709 | | else => {}, |
| 6710 | | }; |
| 6711 | | args.deinit(); |
| 6712 | | } |
| 6564 | var args = std.StringArrayHashMap(MCValue).init(self.gpa); |
| 6565 | try args.ensureTotalCapacity(outputs.len + inputs.len + clobbers_len); |
| 6566 | defer { |
| 6567 | for (args.values()) |arg| switch (arg) { |
| 6568 | .register => |reg| self.register_manager.unlockReg(.{ .register = reg }), |
| 6569 | else => {}, |
| 6570 | }; |
| 6571 | args.deinit(); |
| 6572 | } |
| 6573 | |
| 6574 | if (outputs.len > 1) { |
| 6575 | return self.fail("TODO implement codegen for asm with more than 1 output", .{}); |
| 6576 | } |
| 6713 | 6577 | |
| 6714 | | if (outputs.len > 1) { |
| 6715 | | return self.fail("TODO implement codegen for asm with more than 1 output", .{}); |
| 6578 | for (outputs) |output| { |
| 6579 | if (output != .none) { |
| 6580 | return self.fail("TODO implement codegen for non-expr asm", .{}); |
| 6581 | } |
| 6582 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 6583 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 6584 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 6585 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 6586 | // for the string, we still use the next u32 for the null terminator. |
| 6587 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 6588 | |
| 6589 | const mcv: MCValue = if (mem.eql(u8, constraint, "=r")) |
| 6590 | .{ .register = self.register_manager.tryAllocReg(inst, gp) orelse |
| 6591 | return self.fail("ran out of registers lowering inline asm", .{}) } |
| 6592 | else if (mem.startsWith(u8, constraint, "={") and mem.endsWith(u8, constraint, "}")) |
| 6593 | .{ .register = parseRegName(constraint["={".len .. constraint.len - "}".len]) orelse |
| 6594 | return self.fail("unrecognized register constraint: '{s}'", .{constraint}) } |
| 6595 | else |
| 6596 | return self.fail("unrecognized constraint: '{s}'", .{constraint}); |
| 6597 | args.putAssumeCapacity(name, mcv); |
| 6598 | switch (mcv) { |
| 6599 | .register => |reg| _ = if (RegisterManager.indexOfRegIntoTracked(reg)) |_| |
| 6600 | self.register_manager.lockRegAssumeUnused(reg), |
| 6601 | else => {}, |
| 6716 | 6602 | } |
| 6603 | if (output == .none) result = mcv; |
| 6604 | } |
| 6717 | 6605 | |
| 6718 | | for (outputs) |output| { |
| 6719 | | if (output != .none) { |
| 6720 | | return self.fail("TODO implement codegen for non-expr asm", .{}); |
| 6721 | | } |
| 6722 | | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 6723 | | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 6724 | | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 6725 | | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 6726 | | // for the string, we still use the next u32 for the null terminator. |
| 6727 | | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 6728 | | |
| 6729 | | const mcv: MCValue = if (mem.eql(u8, constraint, "=r")) |
| 6730 | | .{ .register = self.register_manager.tryAllocReg(inst, gp) orelse |
| 6731 | | return self.fail("ran out of registers lowering inline asm", .{}) } |
| 6732 | | else if (mem.startsWith(u8, constraint, "={") and mem.endsWith(u8, constraint, "}")) |
| 6733 | | .{ .register = parseRegName(constraint["={".len .. constraint.len - "}".len]) orelse |
| 6734 | | return self.fail("unrecognized register constraint: '{s}'", .{constraint}) } |
| 6735 | | else |
| 6736 | | return self.fail("unrecognized constraint: '{s}'", .{constraint}); |
| 6737 | | args.putAssumeCapacity(name, mcv); |
| 6738 | | switch (mcv) { |
| 6739 | | .register => |reg| _ = if (RegisterManager.indexOfRegIntoTracked(reg)) |_| |
| 6740 | | self.register_manager.lockRegAssumeUnused(reg), |
| 6741 | | else => {}, |
| 6742 | | } |
| 6743 | | if (output == .none) result = mcv; |
| 6606 | for (inputs) |input| { |
| 6607 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 6608 | const constraint = std.mem.sliceTo(input_bytes, 0); |
| 6609 | const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); |
| 6610 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 6611 | // for the string, we still use the next u32 for the null terminator. |
| 6612 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 6613 | |
| 6614 | if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { |
| 6615 | return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); |
| 6744 | 6616 | } |
| 6617 | const reg_name = constraint[1 .. constraint.len - 1]; |
| 6618 | const reg = parseRegName(reg_name) orelse |
| 6619 | return self.fail("unrecognized register: '{s}'", .{reg_name}); |
| 6745 | 6620 | |
| 6746 | | for (inputs) |input| { |
| 6747 | | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 6748 | | const constraint = std.mem.sliceTo(input_bytes, 0); |
| 6749 | | const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); |
| 6621 | const arg_mcv = try self.resolveInst(input); |
| 6622 | try self.register_manager.getReg(reg, null); |
| 6623 | try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); |
| 6624 | } |
| 6625 | |
| 6626 | { |
| 6627 | var clobber_i: u32 = 0; |
| 6628 | while (clobber_i < clobbers_len) : (clobber_i += 1) { |
| 6629 | const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 6750 | 6630 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 6751 | 6631 | // for the string, we still use the next u32 for the null terminator. |
| 6752 | | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 6632 | extra_i += clobber.len / 4 + 1; |
| 6753 | 6633 | |
| 6754 | | if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { |
| 6755 | | return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); |
| 6756 | | } |
| 6757 | | const reg_name = constraint[1 .. constraint.len - 1]; |
| 6758 | | const reg = parseRegName(reg_name) orelse |
| 6759 | | return self.fail("unrecognized register: '{s}'", .{reg_name}); |
| 6760 | | |
| 6761 | | const arg_mcv = try self.resolveInst(input); |
| 6762 | | try self.register_manager.getReg(reg, null); |
| 6763 | | try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); |
| 6764 | | } |
| 6765 | | |
| 6766 | | { |
| 6767 | | var clobber_i: u32 = 0; |
| 6768 | | while (clobber_i < clobbers_len) : (clobber_i += 1) { |
| 6769 | | const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 6770 | | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 6771 | | // for the string, we still use the next u32 for the null terminator. |
| 6772 | | extra_i += clobber.len / 4 + 1; |
| 6773 | | |
| 6774 | | // TODO honor these |
| 6775 | | } |
| 6634 | // TODO honor these |
| 6776 | 6635 | } |
| 6636 | } |
| 6777 | 6637 | |
| 6778 | | const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; |
| 6779 | | var line_it = mem.tokenize(u8, asm_source, "\n\r;"); |
| 6780 | | while (line_it.next()) |line| { |
| 6781 | | var mnem_it = mem.tokenize(u8, line, " \t"); |
| 6782 | | const mnem_str = mnem_it.next() orelse continue; |
| 6783 | | if (mem.startsWith(u8, mnem_str, "#")) continue; |
| 6784 | | |
| 6785 | | const mnem_size: ?Memory.PtrSize = if (mem.endsWith(u8, mnem_str, "b")) |
| 6786 | | .byte |
| 6787 | | else if (mem.endsWith(u8, mnem_str, "w")) |
| 6788 | | .word |
| 6789 | | else if (mem.endsWith(u8, mnem_str, "l")) |
| 6790 | | .dword |
| 6791 | | else if (mem.endsWith(u8, mnem_str, "q")) |
| 6792 | | .qword |
| 6793 | | else |
| 6794 | | null; |
| 6795 | | const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse |
| 6796 | | (if (mnem_size) |_| |
| 6797 | | std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1]) |
| 6798 | | else |
| 6799 | | null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); |
| 6800 | | |
| 6801 | | var op_it = mem.tokenize(u8, mnem_it.rest(), ","); |
| 6802 | | var ops = [1]encoder.Instruction.Operand{.none} ** 4; |
| 6803 | | for (&ops) |*op| { |
| 6804 | | const op_str = mem.trim(u8, op_it.next() orelse break, " \t"); |
| 6805 | | if (mem.startsWith(u8, op_str, "#")) break; |
| 6806 | | if (mem.startsWith(u8, op_str, "%%")) { |
| 6807 | | const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':'); |
| 6808 | | const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse |
| 6809 | | return self.fail("Invalid register: '{s}'", .{op_str}); |
| 6810 | | if (colon) |colon_pos| { |
| 6811 | | const disp = std.fmt.parseInt(i32, op_str[colon_pos + 1 ..], 0) catch |
| 6812 | | return self.fail("Invalid displacement: '{s}'", .{op_str}); |
| 6813 | | op.* = .{ .mem = Memory.sib( |
| 6814 | | mnem_size orelse return self.fail("Unknown size: '{s}'", .{op_str}), |
| 6815 | | .{ .base = reg, .disp = disp }, |
| 6816 | | ) }; |
| 6817 | | } else { |
| 6818 | | if (mnem_size) |size| if (reg.bitSize() != size.bitSize()) |
| 6819 | | return self.fail("Invalid register size: '{s}'", .{op_str}); |
| 6820 | | op.* = .{ .reg = reg }; |
| 6638 | const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; |
| 6639 | var line_it = mem.tokenize(u8, asm_source, "\n\r;"); |
| 6640 | while (line_it.next()) |line| { |
| 6641 | var mnem_it = mem.tokenize(u8, line, " \t"); |
| 6642 | const mnem_str = mnem_it.next() orelse continue; |
| 6643 | if (mem.startsWith(u8, mnem_str, "#")) continue; |
| 6644 | |
| 6645 | const mnem_size: ?Memory.PtrSize = if (mem.endsWith(u8, mnem_str, "b")) |
| 6646 | .byte |
| 6647 | else if (mem.endsWith(u8, mnem_str, "w")) |
| 6648 | .word |
| 6649 | else if (mem.endsWith(u8, mnem_str, "l")) |
| 6650 | .dword |
| 6651 | else if (mem.endsWith(u8, mnem_str, "q")) |
| 6652 | .qword |
| 6653 | else |
| 6654 | null; |
| 6655 | const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse |
| 6656 | (if (mnem_size) |_| |
| 6657 | std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1]) |
| 6658 | else |
| 6659 | null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); |
| 6660 | |
| 6661 | var op_it = mem.tokenize(u8, mnem_it.rest(), ","); |
| 6662 | var ops = [1]encoder.Instruction.Operand{.none} ** 4; |
| 6663 | for (&ops) |*op| { |
| 6664 | const op_str = mem.trim(u8, op_it.next() orelse break, " \t"); |
| 6665 | if (mem.startsWith(u8, op_str, "#")) break; |
| 6666 | if (mem.startsWith(u8, op_str, "%%")) { |
| 6667 | const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':'); |
| 6668 | const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse |
| 6669 | return self.fail("Invalid register: '{s}'", .{op_str}); |
| 6670 | if (colon) |colon_pos| { |
| 6671 | const disp = std.fmt.parseInt(i32, op_str[colon_pos + 1 ..], 0) catch |
| 6672 | return self.fail("Invalid displacement: '{s}'", .{op_str}); |
| 6673 | op.* = .{ .mem = Memory.sib( |
| 6674 | mnem_size orelse return self.fail("Unknown size: '{s}'", .{op_str}), |
| 6675 | .{ .base = reg, .disp = disp }, |
| 6676 | ) }; |
| 6677 | } else { |
| 6678 | if (mnem_size) |size| if (reg.bitSize() != size.bitSize()) |
| 6679 | return self.fail("Invalid register size: '{s}'", .{op_str}); |
| 6680 | op.* = .{ .reg = reg }; |
| 6681 | } |
| 6682 | } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) { |
| 6683 | switch (args.get(op_str["%[".len .. op_str.len - "]".len]) orelse |
| 6684 | return self.fail("No matching constraint: '{s}'", .{op_str})) { |
| 6685 | .register => |reg| op.* = .{ .reg = reg }, |
| 6686 | else => return self.fail("Invalid constraint: '{s}'", .{op_str}), |
| 6687 | } |
| 6688 | } else if (mem.startsWith(u8, op_str, "$")) { |
| 6689 | if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s| { |
| 6690 | if (mnem_size) |size| { |
| 6691 | const max = @as(u64, math.maxInt(u64)) >> |
| 6692 | @intCast(u6, 64 - (size.bitSize() - 1)); |
| 6693 | if ((if (s < 0) ~s else s) > max) |
| 6694 | return self.fail("Invalid immediate size: '{s}'", .{op_str}); |
| 6821 | 6695 | } |
| 6822 | | } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) { |
| 6823 | | switch (args.get(op_str["%[".len .. op_str.len - "]".len]) orelse |
| 6824 | | return self.fail("No matching constraint: '{s}'", .{op_str})) { |
| 6825 | | .register => |reg| op.* = .{ .reg = reg }, |
| 6826 | | else => return self.fail("Invalid constraint: '{s}'", .{op_str}), |
| 6696 | op.* = .{ .imm = Immediate.s(s) }; |
| 6697 | } else |_| if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u| { |
| 6698 | if (mnem_size) |size| { |
| 6699 | const max = @as(u64, math.maxInt(u64)) >> |
| 6700 | @intCast(u6, 64 - size.bitSize()); |
| 6701 | if (u > max) |
| 6702 | return self.fail("Invalid immediate size: '{s}'", .{op_str}); |
| 6827 | 6703 | } |
| 6828 | | } else if (mem.startsWith(u8, op_str, "$")) { |
| 6829 | | if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s| { |
| 6830 | | if (mnem_size) |size| { |
| 6831 | | const max = @as(u64, math.maxInt(u64)) >> |
| 6832 | | @intCast(u6, 64 - (size.bitSize() - 1)); |
| 6833 | | if ((if (s < 0) ~s else s) > max) |
| 6834 | | return self.fail("Invalid immediate size: '{s}'", .{op_str}); |
| 6835 | | } |
| 6836 | | op.* = .{ .imm = Immediate.s(s) }; |
| 6837 | | } else |_| if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u| { |
| 6838 | | if (mnem_size) |size| { |
| 6839 | | const max = @as(u64, math.maxInt(u64)) >> |
| 6840 | | @intCast(u6, 64 - size.bitSize()); |
| 6841 | | if (u > max) |
| 6842 | | return self.fail("Invalid immediate size: '{s}'", .{op_str}); |
| 6843 | | } |
| 6844 | | op.* = .{ .imm = Immediate.u(u) }; |
| 6845 | | } else |_| return self.fail("Invalid immediate: '{s}'", .{op_str}); |
| 6846 | | } else return self.fail("Invalid operand: '{s}'", .{op_str}); |
| 6847 | | } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str}); |
| 6848 | | |
| 6849 | | (switch (ops[0]) { |
| 6850 | | .none => self.asmOpOnly(mnem), |
| 6851 | | .reg => |reg0| switch (ops[1]) { |
| 6852 | | .none => self.asmRegister(mnem, reg0), |
| 6853 | | .reg => |reg1| switch (ops[2]) { |
| 6854 | | .none => self.asmRegisterRegister(mnem, reg1, reg0), |
| 6855 | | .reg => |reg2| switch (ops[3]) { |
| 6856 | | .none => self.asmRegisterRegisterRegister(mnem, reg2, reg1, reg0), |
| 6857 | | else => error.InvalidInstruction, |
| 6858 | | }, |
| 6859 | | .mem => |mem2| switch (ops[3]) { |
| 6860 | | .none => self.asmMemoryRegisterRegister(mnem, mem2, reg1, reg0), |
| 6861 | | else => error.InvalidInstruction, |
| 6862 | | }, |
| 6704 | op.* = .{ .imm = Immediate.u(u) }; |
| 6705 | } else |_| return self.fail("Invalid immediate: '{s}'", .{op_str}); |
| 6706 | } else return self.fail("Invalid operand: '{s}'", .{op_str}); |
| 6707 | } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str}); |
| 6708 | |
| 6709 | (switch (ops[0]) { |
| 6710 | .none => self.asmOpOnly(mnem), |
| 6711 | .reg => |reg0| switch (ops[1]) { |
| 6712 | .none => self.asmRegister(mnem, reg0), |
| 6713 | .reg => |reg1| switch (ops[2]) { |
| 6714 | .none => self.asmRegisterRegister(mnem, reg1, reg0), |
| 6715 | .reg => |reg2| switch (ops[3]) { |
| 6716 | .none => self.asmRegisterRegisterRegister(mnem, reg2, reg1, reg0), |
| 6863 | 6717 | else => error.InvalidInstruction, |
| 6864 | 6718 | }, |
| 6865 | | .mem => |mem1| switch (ops[2]) { |
| 6866 | | .none => self.asmMemoryRegister(mnem, mem1, reg0), |
| 6719 | .mem => |mem2| switch (ops[3]) { |
| 6720 | .none => self.asmMemoryRegisterRegister(mnem, mem2, reg1, reg0), |
| 6867 | 6721 | else => error.InvalidInstruction, |
| 6868 | 6722 | }, |
| 6869 | 6723 | else => error.InvalidInstruction, |
| 6870 | 6724 | }, |
| 6871 | | .mem => |mem0| switch (ops[1]) { |
| 6872 | | .none => self.asmMemory(mnem, mem0), |
| 6873 | | .reg => |reg1| switch (ops[2]) { |
| 6874 | | .none => self.asmRegisterMemory(mnem, reg1, mem0), |
| 6875 | | else => error.InvalidInstruction, |
| 6876 | | }, |
| 6725 | .mem => |mem1| switch (ops[2]) { |
| 6726 | .none => self.asmMemoryRegister(mnem, mem1, reg0), |
| 6877 | 6727 | else => error.InvalidInstruction, |
| 6878 | 6728 | }, |
| 6879 | | .imm => |imm0| switch (ops[1]) { |
| 6880 | | .none => self.asmImmediate(mnem, imm0), |
| 6881 | | .reg => |reg1| switch (ops[2]) { |
| 6882 | | .none => self.asmRegisterImmediate(mnem, reg1, imm0), |
| 6883 | | .reg => |reg2| switch (ops[3]) { |
| 6884 | | .none => self.asmRegisterRegisterImmediate(mnem, reg2, reg1, imm0), |
| 6885 | | else => error.InvalidInstruction, |
| 6886 | | }, |
| 6887 | | .mem => |mem2| switch (ops[3]) { |
| 6888 | | .none => self.asmMemoryRegisterImmediate(mnem, mem2, reg1, imm0), |
| 6889 | | else => error.InvalidInstruction, |
| 6890 | | }, |
| 6729 | else => error.InvalidInstruction, |
| 6730 | }, |
| 6731 | .mem => |mem0| switch (ops[1]) { |
| 6732 | .none => self.asmMemory(mnem, mem0), |
| 6733 | .reg => |reg1| switch (ops[2]) { |
| 6734 | .none => self.asmRegisterMemory(mnem, reg1, mem0), |
| 6735 | else => error.InvalidInstruction, |
| 6736 | }, |
| 6737 | else => error.InvalidInstruction, |
| 6738 | }, |
| 6739 | .imm => |imm0| switch (ops[1]) { |
| 6740 | .none => self.asmImmediate(mnem, imm0), |
| 6741 | .reg => |reg1| switch (ops[2]) { |
| 6742 | .none => self.asmRegisterImmediate(mnem, reg1, imm0), |
| 6743 | .reg => |reg2| switch (ops[3]) { |
| 6744 | .none => self.asmRegisterRegisterImmediate(mnem, reg2, reg1, imm0), |
| 6891 | 6745 | else => error.InvalidInstruction, |
| 6892 | 6746 | }, |
| 6893 | | .mem => |mem1| switch (ops[2]) { |
| 6894 | | .none => self.asmMemoryImmediate(mnem, mem1, imm0), |
| 6747 | .mem => |mem2| switch (ops[3]) { |
| 6748 | .none => self.asmMemoryRegisterImmediate(mnem, mem2, reg1, imm0), |
| 6895 | 6749 | else => error.InvalidInstruction, |
| 6896 | 6750 | }, |
| 6897 | 6751 | else => error.InvalidInstruction, |
| 6898 | 6752 | }, |
| 6899 | | }) catch |err| switch (err) { |
| 6900 | | error.InvalidInstruction => return self.fail( |
| 6901 | | "Invalid instruction: '{s} {s} {s} {s} {s}'", |
| 6902 | | .{ |
| 6903 | | @tagName(mnem), |
| 6904 | | @tagName(ops[0]), |
| 6905 | | @tagName(ops[1]), |
| 6906 | | @tagName(ops[2]), |
| 6907 | | @tagName(ops[3]), |
| 6908 | | }, |
| 6909 | | ), |
| 6910 | | else => |e| return e, |
| 6911 | | }; |
| 6912 | | } |
| 6753 | .mem => |mem1| switch (ops[2]) { |
| 6754 | .none => self.asmMemoryImmediate(mnem, mem1, imm0), |
| 6755 | else => error.InvalidInstruction, |
| 6756 | }, |
| 6757 | else => error.InvalidInstruction, |
| 6758 | }, |
| 6759 | }) catch |err| switch (err) { |
| 6760 | error.InvalidInstruction => return self.fail( |
| 6761 | "Invalid instruction: '{s} {s} {s} {s} {s}'", |
| 6762 | .{ |
| 6763 | @tagName(mnem), |
| 6764 | @tagName(ops[0]), |
| 6765 | @tagName(ops[1]), |
| 6766 | @tagName(ops[2]), |
| 6767 | @tagName(ops[3]), |
| 6768 | }, |
| 6769 | ), |
| 6770 | else => |e| return e, |
| 6771 | }; |
| 6913 | 6772 | } |
| 6914 | 6773 | |
| 6915 | 6774 | simple: { |
| ... | ... | @@ -7811,7 +7670,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7811 | 7670 | |
| 7812 | 7671 | fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 7813 | 7672 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 7814 | | const result = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 7673 | const result = result: { |
| 7815 | 7674 | const src_mcv = try self.resolveInst(un_op); |
| 7816 | 7675 | if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv; |
| 7817 | 7676 | |
| ... | ... | @@ -7825,7 +7684,7 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 7825 | 7684 | |
| 7826 | 7685 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 7827 | 7686 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7828 | | const result = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 7687 | const result = result: { |
| 7829 | 7688 | const operand = try self.resolveInst(ty_op.operand); |
| 7830 | 7689 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; |
| 7831 | 7690 | |
| ... | ... | @@ -7850,28 +7709,24 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 7850 | 7709 | const ptr = try self.resolveInst(ty_op.operand); |
| 7851 | 7710 | const array_ty = ptr_ty.childType(); |
| 7852 | 7711 | const array_len = array_ty.arrayLen(); |
| 7853 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else blk: { |
| 7854 | | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); |
| 7855 | | try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); |
| 7856 | | try self.genSetStack(Type.u64, stack_offset - 8, .{ .immediate = array_len }, .{}); |
| 7857 | | break :blk .{ .stack_offset = stack_offset }; |
| 7858 | | }; |
| 7712 | |
| 7713 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); |
| 7714 | try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); |
| 7715 | try self.genSetStack(Type.u64, stack_offset - 8, .{ .immediate = array_len }, .{}); |
| 7716 | |
| 7717 | const result = MCValue{ .stack_offset = stack_offset }; |
| 7859 | 7718 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 7860 | 7719 | } |
| 7861 | 7720 | |
| 7862 | 7721 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 7863 | 7722 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7864 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 7865 | | .unreach |
| 7866 | | else |
| 7867 | | return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch}); |
| 7868 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 7723 | _ = ty_op; |
| 7724 | return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch}); |
| 7725 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 7869 | 7726 | } |
| 7870 | 7727 | |
| 7871 | 7728 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 7872 | 7729 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7873 | | if (self.liveness.isUnused(inst)) |
| 7874 | | return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); |
| 7875 | 7730 | |
| 7876 | 7731 | const src_ty = self.air.typeOf(ty_op.operand); |
| 7877 | 7732 | const dst_ty = self.air.typeOfIndex(inst); |
| ... | ... | @@ -8255,27 +8110,22 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { |
| 8255 | 8110 | fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 8256 | 8111 | const atomic_load = self.air.instructions.items(.data)[inst].atomic_load; |
| 8257 | 8112 | |
| 8258 | | const result: MCValue = result: { |
| 8259 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 8260 | | |
| 8261 | | const ptr_ty = self.air.typeOf(atomic_load.ptr); |
| 8262 | | const ptr_mcv = try self.resolveInst(atomic_load.ptr); |
| 8263 | | const ptr_lock = switch (ptr_mcv) { |
| 8264 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 8265 | | else => null, |
| 8266 | | }; |
| 8267 | | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 8113 | const ptr_ty = self.air.typeOf(atomic_load.ptr); |
| 8114 | const ptr_mcv = try self.resolveInst(atomic_load.ptr); |
| 8115 | const ptr_lock = switch (ptr_mcv) { |
| 8116 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 8117 | else => null, |
| 8118 | }; |
| 8119 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 8268 | 8120 | |
| 8269 | | const dst_mcv = |
| 8270 | | if (self.reuseOperand(inst, atomic_load.ptr, 0, ptr_mcv)) |
| 8271 | | ptr_mcv |
| 8272 | | else |
| 8273 | | try self.allocRegOrMem(inst, true); |
| 8121 | const dst_mcv = |
| 8122 | if (self.reuseOperand(inst, atomic_load.ptr, 0, ptr_mcv)) |
| 8123 | ptr_mcv |
| 8124 | else |
| 8125 | try self.allocRegOrMem(inst, true); |
| 8274 | 8126 | |
| 8275 | | try self.load(dst_mcv, ptr_mcv, ptr_ty); |
| 8276 | | break :result dst_mcv; |
| 8277 | | }; |
| 8278 | | return self.finishAir(inst, result, .{ atomic_load.ptr, .none, .none }); |
| 8127 | try self.load(dst_mcv, ptr_mcv, ptr_ty); |
| 8128 | return self.finishAir(inst, dst_mcv, .{ atomic_load.ptr, .none, .none }); |
| 8279 | 8129 | } |
| 8280 | 8130 | |
| 8281 | 8131 | fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void { |
| ... | ... | @@ -8354,122 +8204,123 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 8354 | 8204 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 8355 | 8205 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8356 | 8206 | const operand = try self.resolveInst(un_op); |
| 8357 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else { |
| 8358 | | _ = operand; |
| 8359 | | return self.fail("TODO implement airTagName for x86_64", .{}); |
| 8360 | | }; |
| 8361 | | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8207 | _ = operand; |
| 8208 | return self.fail("TODO implement airTagName for x86_64", .{}); |
| 8209 | //return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8362 | 8210 | } |
| 8363 | 8211 | |
| 8364 | 8212 | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 8365 | 8213 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8366 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 8367 | | const err_ty = self.air.typeOf(un_op); |
| 8368 | | const err_mcv = try self.resolveInst(un_op); |
| 8369 | | const err_reg = try self.copyToTmpRegister(err_ty, err_mcv); |
| 8370 | | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); |
| 8371 | | defer self.register_manager.unlockReg(err_lock); |
| 8372 | | |
| 8373 | | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 8374 | | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 8375 | | defer self.register_manager.unlockReg(addr_lock); |
| 8376 | | |
| 8377 | | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 8378 | | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( |
| 8379 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 8380 | | 4, // dword alignment |
| 8381 | | ); |
| 8382 | | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); |
| 8383 | | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ |
| 8384 | | .base = .ds, |
| 8385 | | .disp = @intCast(i32, got_addr), |
| 8386 | | })); |
| 8387 | | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 8388 | | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( |
| 8389 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 8390 | | 4, // dword alignment |
| 8391 | | ); |
| 8392 | | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 8393 | | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| 8394 | | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 8395 | | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( |
| 8396 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 8397 | | 4, // dword alignment |
| 8398 | | ); |
| 8399 | | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 8400 | | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| 8401 | | } else { |
| 8402 | | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); |
| 8403 | | } |
| 8404 | | |
| 8405 | | const start_reg = try self.register_manager.allocReg(null, gp); |
| 8406 | | const start_lock = self.register_manager.lockRegAssumeUnused(start_reg); |
| 8407 | | defer self.register_manager.unlockReg(start_lock); |
| 8408 | 8214 | |
| 8409 | | const end_reg = try self.register_manager.allocReg(null, gp); |
| 8410 | | const end_lock = self.register_manager.lockRegAssumeUnused(end_reg); |
| 8411 | | defer self.register_manager.unlockReg(end_lock); |
| 8215 | const err_ty = self.air.typeOf(un_op); |
| 8216 | const err_mcv = try self.resolveInst(un_op); |
| 8217 | const err_reg = try self.copyToTmpRegister(err_ty, err_mcv); |
| 8218 | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); |
| 8219 | defer self.register_manager.unlockReg(err_lock); |
| 8412 | 8220 | |
| 8413 | | try self.truncateRegister(err_ty, err_reg.to32()); |
| 8221 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 8222 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 8223 | defer self.register_manager.unlockReg(addr_lock); |
| 8414 | 8224 | |
| 8415 | | try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{ |
| 8416 | | .base = addr_reg.to64(), |
| 8417 | | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, |
| 8418 | | .disp = 4, |
| 8419 | | })); |
| 8420 | | try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{ |
| 8421 | | .base = addr_reg.to64(), |
| 8422 | | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, |
| 8423 | | .disp = 8, |
| 8424 | | })); |
| 8425 | | try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32()); |
| 8426 | | try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{ |
| 8427 | | .base = addr_reg.to64(), |
| 8428 | | .scale_index = .{ .scale = 1, .index = start_reg.to64() }, |
| 8429 | | .disp = 0, |
| 8430 | | })); |
| 8431 | | try self.asmRegisterMemory(.lea, end_reg.to32(), Memory.sib(.byte, .{ |
| 8432 | | .base = end_reg.to64(), |
| 8433 | | .disp = -1, |
| 8225 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 8226 | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( |
| 8227 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 8228 | 4, // dword alignment |
| 8229 | ); |
| 8230 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); |
| 8231 | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ |
| 8232 | .base = .ds, |
| 8233 | .disp = @intCast(i32, got_addr), |
| 8434 | 8234 | })); |
| 8235 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 8236 | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( |
| 8237 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 8238 | 4, // dword alignment |
| 8239 | ); |
| 8240 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 8241 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| 8242 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 8243 | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( |
| 8244 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 8245 | 4, // dword alignment |
| 8246 | ); |
| 8247 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 8248 | try self.genSetReg(Type.usize, addr_reg, .{ .load_got = sym_index }); |
| 8249 | } else { |
| 8250 | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); |
| 8251 | } |
| 8435 | 8252 | |
| 8436 | | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 8437 | | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ |
| 8438 | | .base = .rbp, |
| 8439 | | .disp = 0 - dst_mcv.stack_offset, |
| 8440 | | }), start_reg.to64()); |
| 8441 | | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ |
| 8442 | | .base = .rbp, |
| 8443 | | .disp = 8 - dst_mcv.stack_offset, |
| 8444 | | }), end_reg.to64()); |
| 8445 | | break :result dst_mcv; |
| 8446 | | }; |
| 8447 | | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8253 | const start_reg = try self.register_manager.allocReg(null, gp); |
| 8254 | const start_lock = self.register_manager.lockRegAssumeUnused(start_reg); |
| 8255 | defer self.register_manager.unlockReg(start_lock); |
| 8256 | |
| 8257 | const end_reg = try self.register_manager.allocReg(null, gp); |
| 8258 | const end_lock = self.register_manager.lockRegAssumeUnused(end_reg); |
| 8259 | defer self.register_manager.unlockReg(end_lock); |
| 8260 | |
| 8261 | try self.truncateRegister(err_ty, err_reg.to32()); |
| 8262 | |
| 8263 | try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{ |
| 8264 | .base = addr_reg.to64(), |
| 8265 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, |
| 8266 | .disp = 4, |
| 8267 | })); |
| 8268 | try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{ |
| 8269 | .base = addr_reg.to64(), |
| 8270 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, |
| 8271 | .disp = 8, |
| 8272 | })); |
| 8273 | try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32()); |
| 8274 | try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{ |
| 8275 | .base = addr_reg.to64(), |
| 8276 | .scale_index = .{ .scale = 1, .index = start_reg.to64() }, |
| 8277 | .disp = 0, |
| 8278 | })); |
| 8279 | try self.asmRegisterMemory(.lea, end_reg.to32(), Memory.sib(.byte, .{ |
| 8280 | .base = end_reg.to64(), |
| 8281 | .disp = -1, |
| 8282 | })); |
| 8283 | |
| 8284 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 8285 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ |
| 8286 | .base = .rbp, |
| 8287 | .disp = 0 - dst_mcv.stack_offset, |
| 8288 | }), start_reg.to64()); |
| 8289 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ |
| 8290 | .base = .rbp, |
| 8291 | .disp = 8 - dst_mcv.stack_offset, |
| 8292 | }), end_reg.to64()); |
| 8293 | |
| 8294 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 8448 | 8295 | } |
| 8449 | 8296 | |
| 8450 | 8297 | fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 8451 | 8298 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8452 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airSplat for x86_64", .{}); |
| 8453 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 8299 | _ = ty_op; |
| 8300 | return self.fail("TODO implement airSplat for x86_64", .{}); |
| 8301 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 8454 | 8302 | } |
| 8455 | 8303 | |
| 8456 | 8304 | fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 8457 | 8305 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8458 | 8306 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 8459 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airSelect for x86_64", .{}); |
| 8460 | | return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs }); |
| 8307 | _ = extra; |
| 8308 | return self.fail("TODO implement airSelect for x86_64", .{}); |
| 8309 | //return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs }); |
| 8461 | 8310 | } |
| 8462 | 8311 | |
| 8463 | 8312 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 8464 | 8313 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8465 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airShuffle for x86_64", .{}); |
| 8466 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 8314 | _ = ty_op; |
| 8315 | return self.fail("TODO implement airShuffle for x86_64", .{}); |
| 8316 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 8467 | 8317 | } |
| 8468 | 8318 | |
| 8469 | 8319 | fn airReduce(self: *Self, inst: Air.Inst.Index) !void { |
| 8470 | 8320 | const reduce = self.air.instructions.items(.data)[inst].reduce; |
| 8471 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airReduce for x86_64", .{}); |
| 8472 | | return self.finishAir(inst, result, .{ reduce.operand, .none, .none }); |
| 8321 | _ = reduce; |
| 8322 | return self.fail("TODO implement airReduce for x86_64", .{}); |
| 8323 | //return self.finishAir(inst, result, .{ reduce.operand, .none, .none }); |
| 8473 | 8324 | } |
| 8474 | 8325 | |
| 8475 | 8326 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -8479,8 +8330,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 8479 | 8330 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 8480 | 8331 | const abi_size = @intCast(u32, result_ty.abiSize(self.target.*)); |
| 8481 | 8332 | const abi_align = result_ty.abiAlignment(self.target.*); |
| 8482 | | const result: MCValue = res: { |
| 8483 | | if (self.liveness.isUnused(inst)) break :res MCValue.unreach; |
| 8333 | const result: MCValue = result: { |
| 8484 | 8334 | switch (result_ty.zigTypeTag()) { |
| 8485 | 8335 | .Struct => { |
| 8486 | 8336 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); |
| ... | ... | @@ -8571,7 +8421,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 8571 | 8421 | }; |
| 8572 | 8422 | try self.genSetStack(elem_ty, stack_offset - elem_off, mat_elem_mcv, .{}); |
| 8573 | 8423 | } |
| 8574 | | break :res .{ .stack_offset = stack_offset }; |
| 8424 | break :result .{ .stack_offset = stack_offset }; |
| 8575 | 8425 | }, |
| 8576 | 8426 | .Array => { |
| 8577 | 8427 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); |
| ... | ... | @@ -8587,7 +8437,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 8587 | 8437 | const elem_off = @intCast(i32, elem_size * elem_i); |
| 8588 | 8438 | try self.genSetStack(elem_ty, stack_offset - elem_off, mat_elem_mcv, .{}); |
| 8589 | 8439 | } |
| 8590 | | break :res MCValue{ .stack_offset = stack_offset }; |
| 8440 | break :result MCValue{ .stack_offset = stack_offset }; |
| 8591 | 8441 | }, |
| 8592 | 8442 | .Vector => return self.fail("TODO implement aggregate_init for vectors", .{}), |
| 8593 | 8443 | else => unreachable, |
| ... | ... | @@ -8607,11 +8457,9 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 8607 | 8457 | fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 8608 | 8458 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 8609 | 8459 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 8610 | | const result: MCValue = res: { |
| 8611 | | if (self.liveness.isUnused(inst)) break :res MCValue.unreach; |
| 8612 | | return self.fail("TODO implement airAggregateInit for x86_64", .{}); |
| 8613 | | }; |
| 8614 | | return self.finishAir(inst, result, .{ extra.init, .none, .none }); |
| 8460 | _ = extra; |
| 8461 | return self.fail("TODO implement airAggregateInit for x86_64", .{}); |
| 8462 | //return self.finishAir(inst, result, .{ extra.init, .none, .none }); |
| 8615 | 8463 | } |
| 8616 | 8464 | |
| 8617 | 8465 | fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -8622,10 +8470,9 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { |
| 8622 | 8470 | fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 8623 | 8471 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8624 | 8472 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 8625 | | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else { |
| 8626 | | return self.fail("TODO implement airMulAdd for x86_64", .{}); |
| 8627 | | }; |
| 8628 | | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); |
| 8473 | _ = extra; |
| 8474 | return self.fail("TODO implement airMulAdd for x86_64", .{}); |
| 8475 | //return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); |
| 8629 | 8476 | } |
| 8630 | 8477 | |
| 8631 | 8478 | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { |