authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-15 19:09:57-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-04-20 20:49:35+01:00
log9f1409cabc6545d977defa4f22967eb5f1a202a0
tree0e96b813bbe0cf1c9271e17d571d03178ce3cc62
parentd5879ad1d00799a644741bfc207f31f944b3ce86
signature Commit is signed but in an unrecognized format.

x86_64: adapt to new isUnused liveness change


1 files changed, 970 insertions(+), 1123 deletions(-)

src/arch/x86_64/CodeGen.zig+970-1123
......@@ -917,17 +917,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
917917 const air_tags = self.air.instructions.items(.tag);
918918
919919 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);
927920 if (builtin.mode == .Debug) {
928921 const mir_inst = @intCast(Mir.Inst.Index, self.mir_instructions.len);
929922 try self.mir_to_air_map.put(self.gpa, mir_inst, inst);
930923 }
924
925 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue;
931926 if (debug_wip_mir) @import("../../print_air.zig").dumpInst(
932927 inst,
933928 self.bin_file.options.module.?,
......@@ -935,6 +930,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
935930 self.liveness,
936931 );
937932
933 const old_air_bookkeeping = self.air_bookkeeping;
934 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);
938935 switch (air_tags[inst]) {
939936 // zig fmt: off
940937 .not,
......@@ -1505,22 +1502,14 @@ fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Ty
15051502}
15061503
15071504fn 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) };
15141507 return self.finishAir(inst, result, .{ .none, .none, .none });
15151508}
15161509
15171510fn 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) };
15241513 return self.finishAir(inst, result, .{ .none, .none, .none });
15251514}
15261515
......@@ -1540,126 +1529,125 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
15401529
15411530fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
15421531 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);
15621532
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,
16151540 };
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 });
16171604}
16181605
16191606fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
16201607 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);
16341608
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 }
16391614
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,
16441619 };
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 });
16461632}
16471633
16481634fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
16491635 const un_op = self.air.instructions.items(.data)[inst].un_op;
1636 const ty = self.air.typeOfIndex(inst);
1637
16501638 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 });
16531645}
16541646
16551647fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
16561648 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
16571649 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
16581650
1659 if (self.liveness.isUnused(inst)) {
1660 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
1661 }
1662
16631651 const ptr = try self.resolveInst(bin_op.lhs);
16641652 const ptr_ty = self.air.typeOf(bin_op.lhs);
16651653 const len = try self.resolveInst(bin_op.rhs);
......@@ -1675,33 +1663,21 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
16751663
16761664fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
16771665 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 });
16841668}
16851669
16861670fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
16871671 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 });
16941674}
16951675
16961676fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
16971677 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
16981678 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 });
17051681}
17061682
17071683fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 {
......@@ -1741,7 +1717,7 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 {
17411717
17421718fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
17431719 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: {
17451721 const tag = self.air.instructions.items(.tag)[inst];
17461722 const dst_ty = self.air.typeOfIndex(inst);
17471723 if (dst_ty.zigTypeTag() == .Float)
......@@ -1772,168 +1748,162 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
17721748
17731749fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
17741750 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);
17771752
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);
17861761
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);
18141768
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;
18221787 };
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 });
18241798}
18251799
18261800fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
18271801 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);
18391803
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);
18651812
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,
18731817 };
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 });
18751847}
18761848
18771849fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
18781850 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);
18811852
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);
18851856
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);
18921863
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);
19201870
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;
19291890 };
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 });
19311901}
19321902
19331903fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
19341904 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
19351905 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: {
19371907 const tag = self.air.instructions.items(.tag)[inst];
19381908 const ty = self.air.typeOf(bin_op.lhs);
19391909 switch (ty.zigTypeTag()) {
......@@ -1992,7 +1962,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
19921962fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
19931963 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
19941964 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: {
19961966 const lhs_ty = self.air.typeOf(bin_op.lhs);
19971967 const rhs_ty = self.air.typeOf(bin_op.rhs);
19981968 switch (lhs_ty.zigTypeTag()) {
......@@ -2114,7 +2084,7 @@ fn genSetStackTruncatedOverflowCompare(
21142084fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21152085 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
21162086 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: {
21182088 const dst_ty = self.air.typeOf(bin_op.lhs);
21192089 switch (dst_ty.zigTypeTag()) {
21202090 .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
23032273fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
23042274 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
23052275
2306 if (self.liveness.isUnused(inst)) {
2307 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
2308 }
2309
23102276 try self.spillRegisters(&.{.rcx});
23112277
23122278 const tag = self.air.instructions.items(.tag)[inst];
......@@ -2323,18 +2289,14 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
23232289
23242290fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
23252291 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 });
23312295}
23322296
23332297fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
23342298 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
23352299 const result: MCValue = result: {
2336 if (self.liveness.isUnused(inst)) break :result .unreach;
2337
23382300 const pl_ty = self.air.typeOfIndex(inst);
23392301 const opt_mcv = try self.resolveInst(ty_op.operand);
23402302
......@@ -2359,18 +2321,15 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
23592321
23602322fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
23612323 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;
23642324
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);
23672327
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 });
23742333}
23752334
23762335fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
......@@ -2409,9 +2368,6 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
24092368
24102369fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
24112370 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 }
24152371 const err_union_ty = self.air.typeOf(ty_op.operand);
24162372 const err_ty = err_union_ty.errorUnionSet();
24172373 const payload_ty = err_union_ty.errorUnionPayload();
......@@ -2454,9 +2410,6 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
24542410
24552411fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
24562412 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 }
24602413 const err_union_ty = self.air.typeOf(ty_op.operand);
24612414 const operand = try self.resolveInst(ty_op.operand);
24622415 const result = try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, operand);
......@@ -2507,72 +2460,68 @@ fn genUnwrapErrorUnionPayloadMir(
25072460// *(E!T) -> E
25082461fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {
25092462 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;
25122463
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);
25212472
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);
25252477
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 });
25392490}
25402491
25412492// *(E!T) -> *T
25422493fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
25432494 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;
25462495
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);
25552504
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);
25632513
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 });
25762525}
25772526
25782527fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
......@@ -2621,11 +2570,9 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
26212570}
26222571
26232572fn 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 });
26292576}
26302577
26312578fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
......@@ -2641,8 +2588,6 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void {
26412588fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
26422589 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
26432590 const result: MCValue = result: {
2644 if (self.liveness.isUnused(inst)) break :result .unreach;
2645
26462591 const pl_ty = self.air.typeOf(ty_op.operand);
26472592 if (!pl_ty.hasRuntimeBits()) break :result .{ .immediate = 1 };
26482593
......@@ -2687,10 +2632,6 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
26872632fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
26882633 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
26892634
2690 if (self.liveness.isUnused(inst)) {
2691 return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none });
2692 }
2693
26942635 const error_union_ty = self.air.getRefType(ty_op.ty);
26952636 const payload_ty = error_union_ty.errorUnionPayload();
26962637 const operand = try self.resolveInst(ty_op.operand);
......@@ -2717,9 +2658,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
27172658/// E to E!T
27182659fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
27192660 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
27232662 const error_union_ty = self.air.getRefType(ty_op.ty);
27242663 const payload_ty = error_union_ty.errorUnionPayload();
27252664 const operand = try self.resolveInst(ty_op.operand);
......@@ -2745,7 +2684,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
27452684
27462685fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
27472686 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: {
27492688 const src_mcv = try self.resolveInst(ty_op.operand);
27502689 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
27512690
......@@ -2759,72 +2698,65 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
27592698
27602699fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
27612700 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 }
27732710 };
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 });
27762713}
27772714
27782715fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
27792716 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;
27822717
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);
27912726
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);
27992735
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 });
28122747}
28132748
28142749fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
28152750 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;
28182751
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);
28212754
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 });
28282760}
28292761
28302762fn 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 {
28922824fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
28932825 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
28942826 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 });
29042835}
29052836
29062837fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
29072838 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
29082839 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 });
29142842}
29152843
29162844fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
29172845 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
29182846
2919 if (self.liveness.isUnused(inst)) {
2920 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
2921 }
2922
29232847 const array_ty = self.air.typeOf(bin_op.lhs);
29242848 const array = try self.resolveInst(bin_op.lhs);
29252849 const array_lock: ?RegisterLock = switch (array) {
......@@ -2986,77 +2910,74 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
29862910fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
29872911 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
29882912 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);
30022913
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
30062916
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);
30152926
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,
30242944 };
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 });
30262949}
30272950
30282951fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
30292952 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
30302953 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
30312954
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);
30402962
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);
30502976
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 });
30542979
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 });
30602981}
30612982
30622983fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
......@@ -3098,9 +3019,6 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
30983019
30993020fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
31003021 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 }
31043022
31053023 const tag_ty = self.air.typeOfIndex(inst);
31063024 const union_ty = self.air.typeOf(ty_op.operand);
......@@ -3152,8 +3070,6 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
31523070fn airClz(self: *Self, inst: Air.Inst.Index) !void {
31533071 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
31543072 const result = result: {
3155 if (self.liveness.isUnused(inst)) break :result .unreach;
3156
31573073 const dst_ty = self.air.typeOfIndex(inst);
31583074 const src_ty = self.air.typeOf(ty_op.operand);
31593075
......@@ -3221,8 +3137,6 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
32213137fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
32223138 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
32233139 const result = result: {
3224 if (self.liveness.isUnused(inst)) break :result .unreach;
3225
32263140 const dst_ty = self.air.typeOfIndex(inst);
32273141 const src_ty = self.air.typeOf(ty_op.operand);
32283142 const src_bits = src_ty.bitSize(self.target.*);
......@@ -3279,8 +3193,6 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
32793193fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
32803194 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
32813195 const result: MCValue = result: {
3282 if (self.liveness.isUnused(inst)) break :result .unreach;
3283
32843196 const src_ty = self.air.typeOf(ty_op.operand);
32853197 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
32863198 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
34493361
34503362fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
34513363 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3452 const result = result: {
3453 if (self.liveness.isUnused(inst)) break :result .unreach;
34543364
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 }
34703378
3471 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3379 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
34723380}
34733381
34743382fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
34753383 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3476 const result = result: {
3477 if (self.liveness.isUnused(inst)) break :result .unreach;
34783384
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);
34823388
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);
34873393
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);
34913397
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;
34993405
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);
35043410
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);
35703441 }
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 }
35713477
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 }
35833487
3584 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3488 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
35853489}
35863490
35873491fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
35883492 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 });
35943496}
35953497
35963498fn reuseOperand(
......@@ -3763,9 +3665,6 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
37633665 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
37643666
37653667 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
37693668 const dst_mcv: MCValue = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr))
37703669 // The MCValue that holds the pointer can be re-used as the value.
37713670 ptr
......@@ -4062,10 +3961,6 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
40623961}
40633962
40643963fn 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
40693964 const mcv = try self.resolveInst(operand);
40703965 const ptr_ty = self.air.typeOf(operand);
40713966 const container_ty = ptr_ty.childType();
......@@ -4132,7 +4027,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32
41324027fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
41334028 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
41344029 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: {
41364031 const operand = extra.struct_operand;
41374032 const index = extra.field_index;
41384033
......@@ -4280,11 +4175,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
42804175
42814176fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
42824177 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 });
42884181}
42894182
42904183fn 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 {
55035396 const src_index = self.air.instructions.items(.data)[inst].arg.src_index;
55045397 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index);
55055398
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: {
55095400 const dst_mcv: MCValue = switch (mcv) {
55105401 .register => |reg| blk: {
55115402 self.register_manager.getRegAssumeFree(reg.to64(), inst);
......@@ -5596,23 +5487,17 @@ fn airBreakpoint(self: *Self) !void {
55965487}
55975488
55985489fn 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 });
56075495}
56085496
56095497fn 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 });
56165501}
56175502
56185503fn airFence(self: *Self, inst: Air.Inst.Index) !void {
......@@ -5892,60 +5777,58 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
58925777
58935778fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
58945779 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;
58995783
5900 try self.spillEflagsIfOccupied();
5901 self.eflags_inst = inst;
5784 try self.spillEflagsIfOccupied();
5785 self.eflags_inst = inst;
59025786
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);
59095793
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);
59375821
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);
59445828
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),
59495832 };
59505833 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
59515834}
......@@ -5957,56 +5840,55 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
59575840
59585841fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
59595842 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 }
59925843
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);
59955847
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
60075862 );
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),
60095885 };
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 };
60105892 return self.finishAir(inst, result, .{ un_op, .none, .none });
60115893}
60125894
......@@ -6365,67 +6247,53 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCVa
63656247
63666248fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
63676249 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);
63736253 return self.finishAir(inst, result, .{ un_op, .none, .none });
63746254}
63756255
63766256fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
63776257 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);
63836261 return self.finishAir(inst, result, .{ un_op, .none, .none });
63846262}
63856263
63866264fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
63876265 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,
63956271 };
63966272 return self.finishAir(inst, result, .{ un_op, .none, .none });
63976273}
63986274
63996275fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
64006276 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,
64086282 };
64096283 return self.finishAir(inst, result, .{ un_op, .none, .none });
64106284}
64116285
64126286fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
64136287 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);
64196291 return self.finishAir(inst, result, .{ un_op, .none, .none });
64206292}
64216293
64226294fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
64236295 const un_op = self.air.instructions.items(.data)[inst].un_op;
64246296
6425 if (self.liveness.isUnused(inst)) {
6426 return self.finishAir(inst, .unreach, .{ un_op, .none, .none });
6427 }
6428
64296297 const operand_ptr = try self.resolveInst(un_op);
64306298 const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
64316299 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
......@@ -6451,21 +6319,15 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
64516319
64526320fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
64536321 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);
64596325 return self.finishAir(inst, result, .{ un_op, .none, .none });
64606326}
64616327
64626328fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
64636329 const un_op = self.air.instructions.items(.data)[inst].un_op;
64646330
6465 if (self.liveness.isUnused(inst)) {
6466 return self.finishAir(inst, .unreach, .{ un_op, .none, .none });
6467 }
6468
64696331 const operand_ptr = try self.resolveInst(un_op);
64706332 const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
64716333 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
......@@ -6691,7 +6553,6 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
66916553fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
66926554 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
66936555 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
6694 const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;
66956556 const clobbers_len = @truncate(u31, extra.data.flags);
66966557 var extra_i: usize = extra.end;
66976558 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 {
67006561 extra_i += inputs.len;
67016562
67026563 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 }
67136577
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 => {},
67166602 }
6603 if (output == .none) result = mcv;
6604 }
67176605
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});
67446616 }
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});
67456620
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);
67506630 // This equation accounts for the fact that even if we have exactly 4 bytes
67516631 // 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;
67536633
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
67766635 }
6636 }
67776637
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});
68216695 }
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});
68276703 }
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),
68636717 else => error.InvalidInstruction,
68646718 },
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),
68676721 else => error.InvalidInstruction,
68686722 },
68696723 else => error.InvalidInstruction,
68706724 },
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),
68776727 else => error.InvalidInstruction,
68786728 },
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),
68916745 else => error.InvalidInstruction,
68926746 },
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),
68956749 else => error.InvalidInstruction,
68966750 },
68976751 else => error.InvalidInstruction,
68986752 },
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 };
69136772 }
69146773
69156774 simple: {
......@@ -7811,7 +7670,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
78117670
78127671fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
78137672 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: {
78157674 const src_mcv = try self.resolveInst(un_op);
78167675 if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv;
78177676
......@@ -7825,7 +7684,7 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
78257684
78267685fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
78277686 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: {
78297688 const operand = try self.resolveInst(ty_op.operand);
78307689 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
78317690
......@@ -7850,28 +7709,24 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
78507709 const ptr = try self.resolveInst(ty_op.operand);
78517710 const array_ty = ptr_ty.childType();
78527711 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 };
78597718 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
78607719}
78617720
78627721fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
78637722 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 });
78697726}
78707727
78717728fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
78727729 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 });
78757730
78767731 const src_ty = self.air.typeOf(ty_op.operand);
78777732 const dst_ty = self.air.typeOfIndex(inst);
......@@ -8255,27 +8110,22 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
82558110fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {
82568111 const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;
82578112
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);
82688120
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);
82748126
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 });
82798129}
82808130
82818131fn 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 {
83548204fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
83558205 const un_op = self.air.instructions.items(.data)[inst].un_op;
83568206 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 });
83628210}
83638211
83648212fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
83658213 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);
84088214
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);
84128220
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);
84148224
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),
84348234 }));
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 }
84358252
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 });
84488295}
84498296
84508297fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
84518298 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 });
84548302}
84558303
84568304fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
84578305 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
84588306 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 });
84618310}
84628311
84638312fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
84648313 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 });
84678317}
84688318
84698319fn airReduce(self: *Self, inst: Air.Inst.Index) !void {
84708320 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 });
84738324}
84748325
84758326fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
......@@ -8479,8 +8330,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
84798330 const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
84808331 const abi_size = @intCast(u32, result_ty.abiSize(self.target.*));
84818332 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: {
84848334 switch (result_ty.zigTypeTag()) {
84858335 .Struct => {
84868336 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 {
85718421 };
85728422 try self.genSetStack(elem_ty, stack_offset - elem_off, mat_elem_mcv, .{});
85738423 }
8574 break :res .{ .stack_offset = stack_offset };
8424 break :result .{ .stack_offset = stack_offset };
85758425 },
85768426 .Array => {
85778427 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 {
85878437 const elem_off = @intCast(i32, elem_size * elem_i);
85888438 try self.genSetStack(elem_ty, stack_offset - elem_off, mat_elem_mcv, .{});
85898439 }
8590 break :res MCValue{ .stack_offset = stack_offset };
8440 break :result MCValue{ .stack_offset = stack_offset };
85918441 },
85928442 .Vector => return self.fail("TODO implement aggregate_init for vectors", .{}),
85938443 else => unreachable,
......@@ -8607,11 +8457,9 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
86078457fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
86088458 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
86098459 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 });
86158463}
86168464
86178465fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
......@@ -8622,10 +8470,9 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
86228470fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
86238471 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
86248472 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 });
86298476}
86308477
86318478fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {