| ... | @@ -883,7 +883,8 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | ... | @@ -883,7 +883,8 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 883 | /// Allocates a new register and copies `mcv` into it. | 883 | /// Allocates a new register and copies `mcv` into it. |
| 884 | /// `reg_owner` is the instruction that gets associated with the register in the register table. | 884 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 885 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 885 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 886 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue { | 886 | /// WARNING make sure that the allocated register matches the returned MCValue from an instruction! |
| | 887 | fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue { |
| 887 | const reg = try self.register_manager.allocReg(reg_owner); | 888 | const reg = try self.register_manager.allocReg(reg_owner); |
| 888 | try self.genSetReg(ty, reg, mcv); | 889 | try self.genSetReg(ty, reg, mcv); |
| 889 | return MCValue{ .register = reg }; | 890 | return MCValue{ .register = reg }; |
| ... | @@ -939,7 +940,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -939,7 +940,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 939 | operand.freezeIfRegister(&self.register_manager); | 940 | operand.freezeIfRegister(&self.register_manager); |
| 940 | defer operand.unfreezeIfRegister(&self.register_manager); | 941 | defer operand.unfreezeIfRegister(&self.register_manager); |
| 941 | | 942 | |
| 942 | break :blk try self.copyToNewRegister(inst, dest_ty, operand); | 943 | break :blk try self.copyToRegisterWithInstTracking(inst, dest_ty, operand); |
| 943 | }; | 944 | }; |
| 944 | | 945 | |
| 945 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); | 946 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| ... | @@ -970,7 +971,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -970,7 +971,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 970 | break :blk operand.register.to64(); | 971 | break :blk operand.register.to64(); |
| 971 | } | 972 | } |
| 972 | } | 973 | } |
| 973 | const mcv = try self.copyToNewRegister(inst, src_ty, operand); | 974 | const mcv = try self.copyToRegisterWithInstTracking(inst, src_ty, operand); |
| 974 | break :blk mcv.register.to64(); | 975 | break :blk mcv.register.to64(); |
| 975 | }; | 976 | }; |
| 976 | | 977 | |
| ... | @@ -1088,7 +1089,7 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r | ... | @@ -1088,7 +1089,7 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r |
| 1088 | if (self.reuseOperand(inst, op_lhs, 0, ptr)) { | 1089 | if (self.reuseOperand(inst, op_lhs, 0, ptr)) { |
| 1089 | if (ptr.isMemory() or ptr.isRegister()) break :blk ptr; | 1090 | if (ptr.isMemory() or ptr.isRegister()) break :blk ptr; |
| 1090 | } | 1091 | } |
| 1091 | break :blk try self.copyToNewRegister(inst, dst_ty, ptr); | 1092 | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, ptr); |
| 1092 | }; | 1093 | }; |
| 1093 | | 1094 | |
| 1094 | const offset_mcv = blk: { | 1095 | const offset_mcv = blk: { |
| ... | @@ -1338,7 +1339,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1338,7 +1339,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1338 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) { | 1339 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) { |
| 1339 | break :result operand; | 1340 | break :result operand; |
| 1340 | } | 1341 | } |
| 1341 | break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), operand); | 1342 | break :result try self.copyToRegisterWithInstTracking(inst, self.air.typeOfIndex(inst), operand); |
| 1342 | }; | 1343 | }; |
| 1343 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1344 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1344 | } | 1345 | } |
| ... | @@ -1500,52 +1501,60 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi | ... | @@ -1500,52 +1501,60 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi |
| 1500 | return reg; | 1501 | return reg; |
| 1501 | } | 1502 | } |
| 1502 | | 1503 | |
| | 1504 | fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| | 1505 | const slice_ty = self.air.typeOf(lhs); |
| | 1506 | const slice_mcv = try self.resolveInst(lhs); |
| | 1507 | slice_mcv.freezeIfRegister(&self.register_manager); |
| | 1508 | defer slice_mcv.unfreezeIfRegister(&self.register_manager); |
| | 1509 | |
| | 1510 | const elem_ty = slice_ty.childType(); |
| | 1511 | const elem_size = elem_ty.abiSize(self.target.*); |
| | 1512 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| | 1513 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| | 1514 | |
| | 1515 | const index_ty = self.air.typeOf(rhs); |
| | 1516 | const index_mcv = try self.resolveInst(rhs); |
| | 1517 | index_mcv.freezeIfRegister(&self.register_manager); |
| | 1518 | defer index_mcv.unfreezeIfRegister(&self.register_manager); |
| | 1519 | |
| | 1520 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); |
| | 1521 | self.register_manager.freezeRegs(&.{offset_reg}); |
| | 1522 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| | 1523 | |
| | 1524 | const addr_reg = try self.register_manager.allocReg(null); |
| | 1525 | switch (slice_mcv) { |
| | 1526 | .stack_offset => |off| { |
| | 1527 | // mov reg, [rbp - 8] |
| | 1528 | _ = try self.addInst(.{ |
| | 1529 | .tag = .mov, |
| | 1530 | .ops = (Mir.Ops{ |
| | 1531 | .reg1 = addr_reg.to64(), |
| | 1532 | .reg2 = .rbp, |
| | 1533 | .flags = 0b01, |
| | 1534 | }).encode(), |
| | 1535 | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) }, |
| | 1536 | }); |
| | 1537 | }, |
| | 1538 | else => return self.fail("TODO implement slice_elem_ptr when slice is {}", .{slice_mcv}), |
| | 1539 | } |
| | 1540 | // TODO we could allocate register here, but need to expect addr register and potentially |
| | 1541 | // offset register. |
| | 1542 | try self.genBinMathOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg.to64() }, .{ |
| | 1543 | .register = offset_reg.to64(), |
| | 1544 | }); |
| | 1545 | return MCValue{ .register = addr_reg.to64() }; |
| | 1546 | } |
| | 1547 | |
| 1503 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 1548 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1504 | const is_volatile = false; // TODO | 1549 | const is_volatile = false; // TODO |
| 1505 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1550 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1506 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { | 1551 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { |
| 1507 | const slice_ty = self.air.typeOf(bin_op.lhs); | 1552 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 1508 | const slice_mcv = try self.resolveInst(bin_op.lhs); | | |
| 1509 | slice_mcv.freezeIfRegister(&self.register_manager); | | |
| 1510 | defer slice_mcv.unfreezeIfRegister(&self.register_manager); | | |
| 1511 | | | |
| 1512 | const elem_ty = slice_ty.childType(); | | |
| 1513 | const elem_size = elem_ty.abiSize(self.target.*); | | |
| 1514 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1553 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1515 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | 1554 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| 1516 | | 1555 | const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs); |
| 1517 | const index_ty = self.air.typeOf(bin_op.rhs); | | |
| 1518 | const index_mcv = try self.resolveInst(bin_op.rhs); | | |
| 1519 | index_mcv.freezeIfRegister(&self.register_manager); | | |
| 1520 | defer index_mcv.unfreezeIfRegister(&self.register_manager); | | |
| 1521 | | | |
| 1522 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); | | |
| 1523 | self.register_manager.freezeRegs(&.{offset_reg}); | | |
| 1524 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); | | |
| 1525 | | | |
| 1526 | const addr_reg = try self.register_manager.allocReg(null); | | |
| 1527 | switch (slice_mcv) { | | |
| 1528 | .stack_offset => |off| { | | |
| 1529 | // mov reg, [rbp - 8] | | |
| 1530 | _ = try self.addInst(.{ | | |
| 1531 | .tag = .mov, | | |
| 1532 | .ops = (Mir.Ops{ | | |
| 1533 | .reg1 = addr_reg.to64(), | | |
| 1534 | .reg2 = .rbp, | | |
| 1535 | .flags = 0b01, | | |
| 1536 | }).encode(), | | |
| 1537 | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) }, | | |
| 1538 | }); | | |
| 1539 | }, | | |
| 1540 | else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}), | | |
| 1541 | } | | |
| 1542 | // TODO we could allocate register here, but need to expect addr register and potentially | | |
| 1543 | // offset register. | | |
| 1544 | const dst_mcv = try self.allocRegOrMem(inst, false); | 1556 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1545 | try self.genBinMathOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg.to64() }, .{ | 1557 | try self.load(dst_mcv, elem_ptr, slice_ptr_field_type); |
| 1546 | .register = offset_reg.to64(), | | |
| 1547 | }); | | |
| 1548 | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, slice_ptr_field_type); | | |
| 1549 | break :result dst_mcv; | 1558 | break :result dst_mcv; |
| 1550 | }; | 1559 | }; |
| 1551 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1560 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | @@ -1557,7 +1566,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1557,7 +1566,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1557 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1566 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1558 | .dead | 1567 | .dead |
| 1559 | else | 1568 | else |
| 1560 | return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch}); | 1569 | try self.genSliceElemPtr(extra.lhs, extra.rhs); |
| 1561 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); | 1570 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1562 | } | 1571 | } |
| 1563 | | 1572 | |
| ... | @@ -1571,6 +1580,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1571,6 +1580,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1571 | | 1580 | |
| 1572 | const elem_ty = array_ty.childType(); | 1581 | const elem_ty = array_ty.childType(); |
| 1573 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 1582 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| | 1583 | |
| 1574 | const index_ty = self.air.typeOf(bin_op.rhs); | 1584 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 1575 | const index = try self.resolveInst(bin_op.rhs); | 1585 | const index = try self.resolveInst(bin_op.rhs); |
| 1576 | index.freezeIfRegister(&self.register_manager); | 1586 | index.freezeIfRegister(&self.register_manager); |
| ... | @@ -1580,21 +1590,43 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1580,21 +1590,43 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1580 | self.register_manager.freezeRegs(&.{offset_reg}); | 1590 | self.register_manager.freezeRegs(&.{offset_reg}); |
| 1581 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); | 1591 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 1582 | | 1592 | |
| 1583 | const addr_reg = try self.register_manager.allocReg(null); | 1593 | const addr_reg = blk: { |
| 1584 | switch (array) { | 1594 | const off = inner: { |
| 1585 | .stack_offset => |off| { | 1595 | switch (array) { |
| 1586 | // lea reg, [rbp] | 1596 | .register => { |
| 1587 | _ = try self.addInst(.{ | 1597 | const off = @intCast(i32, try self.allocMem( |
| 1588 | .tag = .lea, | 1598 | inst, |
| 1589 | .ops = (Mir.Ops{ | 1599 | @intCast(u32, array_ty.abiSize(self.target.*)), |
| 1590 | .reg1 = addr_reg.to64(), | 1600 | array_ty.abiAlignment(self.target.*), |
| 1591 | .reg2 = .rbp, | 1601 | )); |
| 1592 | }).encode(), | 1602 | try self.genSetStack(array_ty, off, array); |
| 1593 | .data = .{ .imm = @bitCast(u32, -off) }, | 1603 | break :inner off; |
| 1594 | }); | 1604 | }, |
| 1595 | }, | 1605 | .stack_offset => |off| { |
| 1596 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), | 1606 | break :inner off; |
| 1597 | } | 1607 | }, |
| | 1608 | .memory, |
| | 1609 | .got_load, |
| | 1610 | .direct_load, |
| | 1611 | => { |
| | 1612 | break :blk try self.loadMemPtrIntoRegister(Type.usize, array); |
| | 1613 | }, |
| | 1614 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), |
| | 1615 | } |
| | 1616 | }; |
| | 1617 | const addr_reg = try self.register_manager.allocReg(null); |
| | 1618 | // lea reg, [rbp] |
| | 1619 | _ = try self.addInst(.{ |
| | 1620 | .tag = .lea, |
| | 1621 | .ops = (Mir.Ops{ |
| | 1622 | .reg1 = addr_reg.to64(), |
| | 1623 | .reg2 = .rbp, |
| | 1624 | }).encode(), |
| | 1625 | .data = .{ .imm = @bitCast(u32, -off) }, |
| | 1626 | }); |
| | 1627 | break :blk addr_reg.to64(); |
| | 1628 | }; |
| | 1629 | |
| 1598 | // TODO we could allocate register here, but need to expect addr register and potentially | 1630 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 1599 | // offset register. | 1631 | // offset register. |
| 1600 | const dst_mcv = try self.allocRegOrMem(inst, false); | 1632 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| ... | @@ -1635,7 +1667,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1635,7 +1667,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1635 | self.register_manager.freezeRegs(&.{offset_reg}); | 1667 | self.register_manager.freezeRegs(&.{offset_reg}); |
| 1636 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); | 1668 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 1637 | | 1669 | |
| 1638 | const dst_mcv = try self.copyToNewRegister(inst, ptr_ty, ptr); | 1670 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| 1639 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); | 1671 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 1640 | break :result dst_mcv; | 1672 | break :result dst_mcv; |
| 1641 | }; | 1673 | }; |
| ... | @@ -1693,7 +1725,13 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1693,7 +1725,13 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { |
| 1693 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 1725 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 1694 | } | 1726 | } |
| 1695 | | 1727 | |
| 1696 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { | 1728 | fn reuseOperand( |
| | 1729 | self: *Self, |
| | 1730 | inst: Air.Inst.Index, |
| | 1731 | operand: Air.Inst.Ref, |
| | 1732 | op_index: Liveness.OperandInt, |
| | 1733 | mcv: MCValue, |
| | 1734 | ) bool { |
| 1697 | if (!self.liveness.operandDies(inst, op_index)) | 1735 | if (!self.liveness.operandDies(inst, op_index)) |
| 1698 | return false; | 1736 | return false; |
| 1699 | | 1737 | |
| ... | @@ -1737,6 +1775,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1737,6 +1775,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1737 | .immediate => |imm| { | 1775 | .immediate => |imm| { |
| 1738 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }); | 1776 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }); |
| 1739 | }, | 1777 | }, |
| | 1778 | .stack_offset => { |
| | 1779 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| | 1780 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| | 1781 | }, |
| 1740 | .ptr_stack_offset => |off| { | 1782 | .ptr_stack_offset => |off| { |
| 1741 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }); | 1783 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }); |
| 1742 | }, | 1784 | }, |
| ... | @@ -1787,9 +1829,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1787,9 +1829,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1787 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); | 1829 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 1788 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); | 1830 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| 1789 | }, | 1831 | }, |
| 1790 | .stack_offset => { | | |
| 1791 | return self.fail("TODO implement loading from MCValue.stack_offset", .{}); | | |
| 1792 | }, | | |
| 1793 | } | 1832 | } |
| 1794 | } | 1833 | } |
| 1795 | | 1834 | |
| ... | @@ -1819,6 +1858,42 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1819,6 +1858,42 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1819 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1858 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1820 | } | 1859 | } |
| 1821 | | 1860 | |
| | 1861 | fn loadMemPtrIntoRegister(self: *Self, ptr_ty: Type, ptr: MCValue) InnerError!Register { |
| | 1862 | switch (ptr) { |
| | 1863 | .got_load, |
| | 1864 | .direct_load, |
| | 1865 | => |sym_index| { |
| | 1866 | const flags: u2 = switch (ptr) { |
| | 1867 | .got_load => 0b00, |
| | 1868 | .direct_load => 0b01, |
| | 1869 | else => unreachable, |
| | 1870 | }; |
| | 1871 | const reg = try self.register_manager.allocReg(null); |
| | 1872 | _ = try self.addInst(.{ |
| | 1873 | .tag = .lea_pie, |
| | 1874 | .ops = (Mir.Ops{ |
| | 1875 | .reg1 = reg.to64(), |
| | 1876 | .flags = flags, |
| | 1877 | }).encode(), |
| | 1878 | .data = .{ |
| | 1879 | .load_reloc = .{ |
| | 1880 | .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index, |
| | 1881 | .sym_index = sym_index, |
| | 1882 | }, |
| | 1883 | }, |
| | 1884 | }); |
| | 1885 | return reg.to64(); |
| | 1886 | }, |
| | 1887 | .memory => |addr| { |
| | 1888 | // TODO: in case the address fits in an imm32 we can use [ds:imm32] |
| | 1889 | // instead of wasting an instruction copying the address to a register |
| | 1890 | const reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr }); |
| | 1891 | return reg.to64(); |
| | 1892 | }, |
| | 1893 | else => unreachable, |
| | 1894 | } |
| | 1895 | } |
| | 1896 | |
| 1822 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { | 1897 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| 1823 | _ = ptr_ty; | 1898 | _ = ptr_ty; |
| 1824 | const abi_size = value_ty.abiSize(self.target.*); | 1899 | const abi_size = value_ty.abiSize(self.target.*); |
| ... | @@ -1832,6 +1907,10 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1832,6 +1907,10 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1832 | .immediate => |imm| { | 1907 | .immediate => |imm| { |
| 1833 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); | 1908 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); |
| 1834 | }, | 1909 | }, |
| | 1910 | .stack_offset => { |
| | 1911 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| | 1912 | try self.store(.{ .register = reg }, value, ptr_ty, value_ty); |
| | 1913 | }, |
| 1835 | .ptr_stack_offset => |off| { | 1914 | .ptr_stack_offset => |off| { |
| 1836 | try self.genSetStack(value_ty, off, value); | 1915 | try self.genSetStack(value_ty, off, value); |
| 1837 | }, | 1916 | }, |
| ... | @@ -1909,6 +1988,10 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1909,6 +1988,10 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1909 | .data = .{ .imm = 0 }, | 1988 | .data = .{ .imm = 0 }, |
| 1910 | }); | 1989 | }); |
| 1911 | }, | 1990 | }, |
| | 1991 | .stack_offset => { |
| | 1992 | const tmp_reg = try self.copyToTmpRegister(value_ty, value); |
| | 1993 | return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); |
| | 1994 | }, |
| 1912 | else => |other| { | 1995 | else => |other| { |
| 1913 | return self.fail("TODO implement set pointee with {}", .{other}); | 1996 | return self.fail("TODO implement set pointee with {}", .{other}); |
| 1914 | }, | 1997 | }, |
| ... | @@ -1921,41 +2004,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1921,41 +2004,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1921 | value.freezeIfRegister(&self.register_manager); | 2004 | value.freezeIfRegister(&self.register_manager); |
| 1922 | defer value.unfreezeIfRegister(&self.register_manager); | 2005 | defer value.unfreezeIfRegister(&self.register_manager); |
| 1923 | | 2006 | |
| 1924 | const addr_reg: Register = blk: { | 2007 | const addr_reg = try self.loadMemPtrIntoRegister(ptr_ty, ptr); |
| 1925 | switch (ptr) { | | |
| 1926 | .got_load, | | |
| 1927 | .direct_load, | | |
| 1928 | => |sym_index| { | | |
| 1929 | const flags: u2 = switch (ptr) { | | |
| 1930 | .got_load => 0b00, | | |
| 1931 | .direct_load => 0b01, | | |
| 1932 | else => unreachable, | | |
| 1933 | }; | | |
| 1934 | const addr_reg = try self.register_manager.allocReg(null); | | |
| 1935 | _ = try self.addInst(.{ | | |
| 1936 | .tag = .lea_pie, | | |
| 1937 | .ops = (Mir.Ops{ | | |
| 1938 | .reg1 = addr_reg.to64(), | | |
| 1939 | .flags = flags, | | |
| 1940 | }).encode(), | | |
| 1941 | .data = .{ | | |
| 1942 | .load_reloc = .{ | | |
| 1943 | .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index, | | |
| 1944 | .sym_index = sym_index, | | |
| 1945 | }, | | |
| 1946 | }, | | |
| 1947 | }); | | |
| 1948 | break :blk addr_reg; | | |
| 1949 | }, | | |
| 1950 | .memory => |addr| { | | |
| 1951 | // TODO: in case the address fits in an imm32 we can use [ds:imm32] | | |
| 1952 | // instead of wasting an instruction copying the address to a register | | |
| 1953 | const addr_reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr }); | | |
| 1954 | break :blk addr_reg; | | |
| 1955 | }, | | |
| 1956 | else => unreachable, | | |
| 1957 | } | | |
| 1958 | }; | | |
| 1959 | | 2008 | |
| 1960 | // to get the actual address of the value we want to modify we have to go through the GOT | 2009 | // to get the actual address of the value we want to modify we have to go through the GOT |
| 1961 | // mov reg, [reg] | 2010 | // mov reg, [reg] |
| ... | @@ -2020,9 +2069,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2020,9 +2069,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2020 | else => return self.fail("TODO implement storing {} to MCValue.memory", .{value}), | 2069 | else => return self.fail("TODO implement storing {} to MCValue.memory", .{value}), |
| 2021 | } | 2070 | } |
| 2022 | }, | 2071 | }, |
| 2023 | .stack_offset => { | | |
| 2024 | return self.fail("TODO implement storing to MCValue.stack_offset", .{}); | | |
| 2025 | }, | | |
| 2026 | } | 2072 | } |
| 2027 | } | 2073 | } |
| 2028 | | 2074 | |
| ... | @@ -2068,7 +2114,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde | ... | @@ -2068,7 +2114,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 2068 | self.register_manager.freezeRegs(&.{offset_reg}); | 2114 | self.register_manager.freezeRegs(&.{offset_reg}); |
| 2069 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); | 2115 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 2070 | | 2116 | |
| 2071 | const dst_mcv = try self.copyToNewRegister(inst, ptr_ty, mcv); | 2117 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, mcv); |
| 2072 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); | 2118 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 2073 | break :result dst_mcv; | 2119 | break :result dst_mcv; |
| 2074 | }, | 2120 | }, |
| ... | @@ -2129,7 +2175,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2129,7 +2175,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2129 | if (self.reuseOperand(inst, operand, 0, mcv)) { | 2175 | if (self.reuseOperand(inst, operand, 0, mcv)) { |
| 2130 | break :blk mcv; | 2176 | break :blk mcv; |
| 2131 | } else { | 2177 | } else { |
| 2132 | const dst_mcv = try self.copyToNewRegister(inst, Type.usize, .{ .register = reg.to64() }); | 2178 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, Type.usize, .{ |
| | 2179 | .register = reg.to64(), |
| | 2180 | }); |
| 2133 | break :blk dst_mcv; | 2181 | break :blk dst_mcv; |
| 2134 | } | 2182 | } |
| 2135 | }; | 2183 | }; |
| ... | @@ -2192,7 +2240,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -2192,7 +2240,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 2192 | // LHS dies; use it as the destination. | 2240 | // LHS dies; use it as the destination. |
| 2193 | // Both operands cannot be memory. | 2241 | // Both operands cannot be memory. |
| 2194 | if (lhs.isMemory() and rhs.isMemory()) { | 2242 | if (lhs.isMemory() and rhs.isMemory()) { |
| 2195 | dst_mcv = try self.copyToNewRegister(inst, dst_ty, lhs); | 2243 | dst_mcv = try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); |
| 2196 | src_mcv = rhs; | 2244 | src_mcv = rhs; |
| 2197 | } else { | 2245 | } else { |
| 2198 | dst_mcv = lhs; | 2246 | dst_mcv = lhs; |
| ... | @@ -2202,7 +2250,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -2202,7 +2250,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 2202 | // RHS dies; use it as the destination. | 2250 | // RHS dies; use it as the destination. |
| 2203 | // Both operands cannot be memory. | 2251 | // Both operands cannot be memory. |
| 2204 | if (lhs.isMemory() and rhs.isMemory()) { | 2252 | if (lhs.isMemory() and rhs.isMemory()) { |
| 2205 | dst_mcv = try self.copyToNewRegister(inst, dst_ty, rhs); | 2253 | dst_mcv = try self.copyToRegisterWithInstTracking(inst, dst_ty, rhs); |
| 2206 | src_mcv = lhs; | 2254 | src_mcv = lhs; |
| 2207 | } else { | 2255 | } else { |
| 2208 | dst_mcv = rhs; | 2256 | dst_mcv = rhs; |
| ... | @@ -2213,13 +2261,13 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -2213,13 +2261,13 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 2213 | rhs.freezeIfRegister(&self.register_manager); | 2261 | rhs.freezeIfRegister(&self.register_manager); |
| 2214 | defer rhs.unfreezeIfRegister(&self.register_manager); | 2262 | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 2215 | | 2263 | |
| 2216 | dst_mcv = try self.copyToNewRegister(inst, dst_ty, lhs); | 2264 | dst_mcv = try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); |
| 2217 | src_mcv = rhs; | 2265 | src_mcv = rhs; |
| 2218 | } else { | 2266 | } else { |
| 2219 | lhs.freezeIfRegister(&self.register_manager); | 2267 | lhs.freezeIfRegister(&self.register_manager); |
| 2220 | defer lhs.unfreezeIfRegister(&self.register_manager); | 2268 | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 2221 | | 2269 | |
| 2222 | dst_mcv = try self.copyToNewRegister(inst, dst_ty, rhs); | 2270 | dst_mcv = try self.copyToRegisterWithInstTracking(inst, dst_ty, rhs); |
| 2223 | src_mcv = lhs; | 2271 | src_mcv = lhs; |
| 2224 | } | 2272 | } |
| 2225 | } | 2273 | } |
| ... | @@ -2228,13 +2276,14 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -2228,13 +2276,14 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 2228 | // A potential opportunity for future optimization here would be keeping track | 2276 | // A potential opportunity for future optimization here would be keeping track |
| 2229 | // of the fact that the instruction is available both as an immediate | 2277 | // of the fact that the instruction is available both as an immediate |
| 2230 | // and as a register. | 2278 | // and as a register. |
| | 2279 | // TODO consolidate with limitImmediateType() function |
| 2231 | switch (src_mcv) { | 2280 | switch (src_mcv) { |
| 2232 | .immediate => |imm| { | 2281 | .immediate => |imm| { |
| 2233 | if (imm > math.maxInt(u31)) { | 2282 | if (imm > math.maxInt(u31)) { |
| 2234 | dst_mcv.freezeIfRegister(&self.register_manager); | 2283 | dst_mcv.freezeIfRegister(&self.register_manager); |
| 2235 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); | 2284 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); |
| 2236 | | 2285 | |
| 2237 | src_mcv = try self.copyToNewRegister(inst, Type.u64, src_mcv); | 2286 | src_mcv = MCValue{ .register = try self.copyToTmpRegister(Type.usize, src_mcv) }; |
| 2238 | } | 2287 | } |
| 2239 | }, | 2288 | }, |
| 2240 | else => {}, | 2289 | else => {}, |
| ... | @@ -2452,7 +2501,18 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -2452,7 +2501,18 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2452 | return self.genIMulOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg }); | 2501 | return self.genIMulOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg }); |
| 2453 | } | 2502 | } |
| 2454 | }, | 2503 | }, |
| 2455 | .embedded_in_code, .memory, .stack_offset => { | 2504 | .stack_offset => |off| { |
| | 2505 | _ = try self.addInst(.{ |
| | 2506 | .tag = .imul_complex, |
| | 2507 | .ops = (Mir.Ops{ |
| | 2508 | .reg1 = dst_reg, |
| | 2509 | .reg2 = .rbp, |
| | 2510 | .flags = 0b01, |
| | 2511 | }).encode(), |
| | 2512 | .data = .{ .imm = @bitCast(u32, -off) }, |
| | 2513 | }); |
| | 2514 | }, |
| | 2515 | .embedded_in_code, .memory => { |
| 2456 | return self.fail("TODO implement x86 multiply source memory", .{}); | 2516 | return self.fail("TODO implement x86 multiply source memory", .{}); |
| 2457 | }, | 2517 | }, |
| 2458 | .got_load, .direct_load => { | 2518 | .got_load, .direct_load => { |
| ... | @@ -2521,16 +2581,10 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2521,16 +2581,10 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 2521 | self.arg_index += 1; | 2581 | self.arg_index += 1; |
| 2522 | | 2582 | |
| 2523 | const mcv = self.args[arg_index]; | 2583 | const mcv = self.args[arg_index]; |
| 2524 | const max_stack = loop: for (self.args) |arg| { | | |
| 2525 | switch (arg) { | | |
| 2526 | .stack_offset => |last| break :loop last, | | |
| 2527 | else => {}, | | |
| 2528 | } | | |
| 2529 | } else 0; | | |
| 2530 | const payload = try self.addExtra(Mir.ArgDbgInfo{ | 2584 | const payload = try self.addExtra(Mir.ArgDbgInfo{ |
| 2531 | .air_inst = inst, | 2585 | .air_inst = inst, |
| 2532 | .arg_index = arg_index, | 2586 | .arg_index = arg_index, |
| 2533 | .max_stack = @intCast(u32, max_stack), | 2587 | .max_stack = self.max_end_stack, |
| 2534 | }); | 2588 | }); |
| 2535 | _ = try self.addInst(.{ | 2589 | _ = try self.addInst(.{ |
| 2536 | .tag = .arg_dbg_info, | 2590 | .tag = .arg_dbg_info, |
| ... | @@ -2547,7 +2601,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2547,7 +2601,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 2547 | break :blk mcv; | 2601 | break :blk mcv; |
| 2548 | }, | 2602 | }, |
| 2549 | .stack_offset => |off| { | 2603 | .stack_offset => |off| { |
| 2550 | const offset = max_stack - off + 16; | 2604 | const offset = @intCast(i32, self.max_end_stack) - off + 16; |
| 2551 | break :blk MCValue{ .stack_offset = -offset }; | 2605 | break :blk MCValue{ .stack_offset = -offset }; |
| 2552 | }, | 2606 | }, |
| 2553 | else => return self.fail("TODO implement arg for {}", .{mcv}), | 2607 | else => return self.fail("TODO implement arg for {}", .{mcv}), |
| ... | @@ -2591,7 +2645,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2591,7 +2645,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2591 | var info = try self.resolveCallingConventionValues(fn_ty); | 2645 | var info = try self.resolveCallingConventionValues(fn_ty); |
| 2592 | defer info.deinit(self); | 2646 | defer info.deinit(self); |
| 2593 | | 2647 | |
| 2594 | var stack_adjustment: ?u32 = null; | | |
| 2595 | for (args) |arg, arg_i| { | 2648 | for (args) |arg, arg_i| { |
| 2596 | const mc_arg = info.args[arg_i]; | 2649 | const mc_arg = info.args[arg_i]; |
| 2597 | const arg_ty = self.air.typeOf(arg); | 2650 | const arg_ty = self.air.typeOf(arg); |
| ... | @@ -2606,9 +2659,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2606,9 +2659,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2606 | }, | 2659 | }, |
| 2607 | .stack_offset => |off| { | 2660 | .stack_offset => |off| { |
| 2608 | try self.genSetStackArg(arg_ty, off, arg_mcv); | 2661 | try self.genSetStackArg(arg_ty, off, arg_mcv); |
| 2609 | if (stack_adjustment == null) { | | |
| 2610 | stack_adjustment = @intCast(u32, off); | | |
| 2611 | } | | |
| 2612 | }, | 2662 | }, |
| 2613 | .ptr_stack_offset => { | 2663 | .ptr_stack_offset => { |
| 2614 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | 2664 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| ... | @@ -2629,14 +2679,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2629,14 +2679,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2629 | } | 2679 | } |
| 2630 | } | 2680 | } |
| 2631 | | 2681 | |
| 2632 | if (stack_adjustment) |off| { | 2682 | if (info.stack_byte_count > 0) { |
| 2633 | // Adjust the stack | 2683 | // Adjust the stack |
| 2634 | _ = try self.addInst(.{ | 2684 | _ = try self.addInst(.{ |
| 2635 | .tag = .sub, | 2685 | .tag = .sub, |
| 2636 | .ops = (Mir.Ops{ | 2686 | .ops = (Mir.Ops{ |
| 2637 | .reg1 = .rsp, | 2687 | .reg1 = .rsp, |
| 2638 | }).encode(), | 2688 | }).encode(), |
| 2639 | .data = .{ .imm = off }, | 2689 | .data = .{ .imm = info.stack_byte_count }, |
| 2640 | }); | 2690 | }); |
| 2641 | } | 2691 | } |
| 2642 | | 2692 | |
| ... | @@ -2764,14 +2814,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2764,14 +2814,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2764 | } | 2814 | } |
| 2765 | } else unreachable; | 2815 | } else unreachable; |
| 2766 | | 2816 | |
| 2767 | if (stack_adjustment) |off| { | 2817 | if (info.stack_byte_count > 0) { |
| 2768 | // Readjust the stack | 2818 | // Readjust the stack |
| 2769 | _ = try self.addInst(.{ | 2819 | _ = try self.addInst(.{ |
| 2770 | .tag = .add, | 2820 | .tag = .add, |
| 2771 | .ops = (Mir.Ops{ | 2821 | .ops = (Mir.Ops{ |
| 2772 | .reg1 = .rsp, | 2822 | .reg1 = .rsp, |
| 2773 | }).encode(), | 2823 | }).encode(), |
| 2774 | .data = .{ .imm = off }, | 2824 | .data = .{ .imm = info.stack_byte_count }, |
| 2775 | }); | 2825 | }); |
| 2776 | } | 2826 | } |
| 2777 | | 2827 | |
| ... | @@ -2780,7 +2830,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2780,7 +2830,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2780 | .register => |reg| { | 2830 | .register => |reg| { |
| 2781 | if (Register.allocIndex(reg) == null) { | 2831 | if (Register.allocIndex(reg) == null) { |
| 2782 | // Save function return value in a callee saved register | 2832 | // Save function return value in a callee saved register |
| 2783 | break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), info.return_value); | 2833 | break :result try self.copyToRegisterWithInstTracking( |
| | 2834 | inst, |
| | 2835 | self.air.typeOfIndex(inst), |
| | 2836 | info.return_value, |
| | 2837 | ); |
| 2784 | } | 2838 | } |
| 2785 | }, | 2839 | }, |
| 2786 | else => {}, | 2840 | else => {}, |
| ... | @@ -2857,7 +2911,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -2857,7 +2911,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2857 | // Either one, but not both, can be a memory operand. | 2911 | // Either one, but not both, can be a memory operand. |
| 2858 | // Source operand can be an immediate, 8 bits or 32 bits. | 2912 | // Source operand can be an immediate, 8 bits or 32 bits. |
| 2859 | const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory())) | 2913 | const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory())) |
| 2860 | try self.copyToNewRegister(inst, ty, lhs) | 2914 | MCValue{ .register = try self.copyToTmpRegister(ty, lhs) } |
| 2861 | else | 2915 | else |
| 2862 | lhs; | 2916 | lhs; |
| 2863 | // This instruction supports only signed 32-bit immediates at most. | 2917 | // This instruction supports only signed 32-bit immediates at most. |
| ... | @@ -3520,6 +3574,13 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -3520,6 +3574,13 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3520 | .dead => unreachable, | 3574 | .dead => unreachable, |
| 3521 | .ptr_embedded_in_code => unreachable, | 3575 | .ptr_embedded_in_code => unreachable, |
| 3522 | .unreach, .none => return, | 3576 | .unreach, .none => return, |
| | 3577 | .undef => { |
| | 3578 | if (abi_size <= 8) { |
| | 3579 | const reg = try self.copyToTmpRegister(ty, mcv); |
| | 3580 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| | 3581 | } |
| | 3582 | try self.genInlineMemset(stack_offset, .rsp, ty, .{ .immediate = 0xaa }); |
| | 3583 | }, |
| 3523 | .compare_flags_unsigned, | 3584 | .compare_flags_unsigned, |
| 3524 | .compare_flags_signed, | 3585 | .compare_flags_signed, |
| 3525 | => { | 3586 | => { |
| ... | @@ -3598,7 +3659,6 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -3598,7 +3659,6 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3598 | | 3659 | |
| 3599 | try self.genInlineMemcpy(stack_offset, .rsp, ty, mcv); | 3660 | try self.genInlineMemcpy(stack_offset, .rsp, ty, mcv); |
| 3600 | }, | 3661 | }, |
| 3601 | else => return self.fail("TODO implement args on stack for {}", .{mcv}), | | |
| 3602 | } | 3662 | } |
| 3603 | } | 3663 | } |
| 3604 | | 3664 | |
| ... | @@ -3617,7 +3677,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro | ... | @@ -3617,7 +3677,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3617 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), | 3677 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 3618 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 3678 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 3619 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), | 3679 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| 3620 | else => return self.genInlineMemset(ty, stack_offset, .{ .immediate = 0xaa }), | 3680 | else => return self.genInlineMemset(stack_offset, .rbp, ty, .{ .immediate = 0xaa }), |
| 3621 | } | 3681 | } |
| 3622 | }, | 3682 | }, |
| 3623 | .compare_flags_unsigned, | 3683 | .compare_flags_unsigned, |
| ... | @@ -3783,33 +3843,11 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type | ... | @@ -3783,33 +3843,11 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type |
| 3783 | | 3843 | |
| 3784 | const addr_reg: Register = blk: { | 3844 | const addr_reg: Register = blk: { |
| 3785 | switch (val) { | 3845 | switch (val) { |
| 3786 | .memory => |addr| { | 3846 | .memory, |
| 3787 | const reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr }); | | |
| 3788 | break :blk reg; | | |
| 3789 | }, | | |
| 3790 | .direct_load, | 3847 | .direct_load, |
| 3791 | .got_load, | 3848 | .got_load, |
| 3792 | => |sym_index| { | 3849 | => { |
| 3793 | const flags: u2 = switch (val) { | 3850 | break :blk try self.loadMemPtrIntoRegister(Type.usize, val); |
| 3794 | .got_load => 0b00, | | |
| 3795 | .direct_load => 0b01, | | |
| 3796 | else => unreachable, | | |
| 3797 | }; | | |
| 3798 | const addr_reg = (try self.register_manager.allocReg(null)).to64(); | | |
| 3799 | _ = try self.addInst(.{ | | |
| 3800 | .tag = .lea_pie, | | |
| 3801 | .ops = (Mir.Ops{ | | |
| 3802 | .reg1 = addr_reg, | | |
| 3803 | .flags = flags, | | |
| 3804 | }).encode(), | | |
| 3805 | .data = .{ | | |
| 3806 | .load_reloc = .{ | | |
| 3807 | .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index, | | |
| 3808 | .sym_index = sym_index, | | |
| 3809 | }, | | |
| 3810 | }, | | |
| 3811 | }); | | |
| 3812 | break :blk addr_reg; | | |
| 3813 | }, | 3851 | }, |
| 3814 | .stack_offset => |off| { | 3852 | .stack_offset => |off| { |
| 3815 | const addr_reg = (try self.register_manager.allocReg(null)).to64(); | 3853 | const addr_reg = (try self.register_manager.allocReg(null)).to64(); |
| ... | @@ -3943,12 +3981,20 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type | ... | @@ -3943,12 +3981,20 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type |
| 3943 | try self.performReloc(loop_reloc); | 3981 | try self.performReloc(loop_reloc); |
| 3944 | } | 3982 | } |
| 3945 | | 3983 | |
| 3946 | fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) InnerError!void { | 3984 | fn genInlineMemset( |
| | 3985 | self: *Self, |
| | 3986 | stack_offset: i32, |
| | 3987 | stack_register: Register, |
| | 3988 | ty: Type, |
| | 3989 | value: MCValue, |
| | 3990 | ) InnerError!void { |
| 3947 | try self.register_manager.getReg(.rax, null); | 3991 | try self.register_manager.getReg(.rax, null); |
| | 3992 | |
| 3948 | const abi_size = ty.abiSize(self.target.*); | 3993 | const abi_size = ty.abiSize(self.target.*); |
| 3949 | if (stack_offset > 128) { | 3994 | if (stack_offset > 128) { |
| 3950 | return self.fail("TODO inline memset with large stack offset", .{}); | 3995 | return self.fail("TODO inline memset with large stack offset", .{}); |
| 3951 | } | 3996 | } |
| | 3997 | |
| 3952 | const negative_offset = @bitCast(u32, -stack_offset); | 3998 | const negative_offset = @bitCast(u32, -stack_offset); |
| 3953 | | 3999 | |
| 3954 | // We are actually counting `abi_size` bytes; however, we reuse the index register | 4000 | // We are actually counting `abi_size` bytes; however, we reuse the index register |
| ... | @@ -4005,7 +4051,7 @@ fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) Inn | ... | @@ -4005,7 +4051,7 @@ fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) Inn |
| 4005 | _ = try self.addInst(.{ | 4051 | _ = try self.addInst(.{ |
| 4006 | .tag = .mov_mem_index_imm, | 4052 | .tag = .mov_mem_index_imm, |
| 4007 | .ops = (Mir.Ops{ | 4053 | .ops = (Mir.Ops{ |
| 4008 | .reg1 = .rbp, | 4054 | .reg1 = stack_register.to64(), |
| 4009 | }).encode(), | 4055 | }).encode(), |
| 4010 | .data = .{ .payload = payload }, | 4056 | .data = .{ .payload = payload }, |
| 4011 | }); | 4057 | }); |
| ... | @@ -4731,20 +4777,40 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -4731,20 +4777,40 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4731 | var next_int_reg: usize = 0; | 4777 | var next_int_reg: usize = 0; |
| 4732 | var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator); | 4778 | var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator); |
| 4733 | defer by_reg.deinit(); | 4779 | defer by_reg.deinit(); |
| 4734 | for (param_types) |ty, i| { | 4780 | |
| 4735 | if (!ty.hasRuntimeBits()) continue; | 4781 | // If we want debug output, we store all args on stack for better liveness of args |
| 4736 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 4782 | // in debugging contexts such as previewing the args in the debugger anywhere in |
| 4737 | const pass_in_reg = switch (ty.zigTypeTag()) { | 4783 | // the procedure. Passing the args via registers can lead to reusing the register |
| 4738 | .Bool => true, | 4784 | // for local ops thus clobbering the input arg forever. |
| 4739 | .Int, .Enum => param_size <= 8, | 4785 | // This of course excludes C ABI calls. |
| 4740 | .Pointer => ty.ptrSize() != .Slice, | 4786 | const omit_args_in_registers = blk: { |
| 4741 | .Optional => ty.isPtrLikeOptional(), | 4787 | if (cc == .C) break :blk false; |
| 4742 | else => false, | 4788 | switch (self.bin_file.options.optimize_mode) { |
| 4743 | }; | 4789 | .Debug => break :blk true, |
| 4744 | if (pass_in_reg) { | 4790 | else => break :blk false, |
| 4745 | if (next_int_reg >= c_abi_int_param_regs.len) break; | 4791 | } |
| 4746 | try by_reg.putNoClobber(i, next_int_reg); | 4792 | }; |
| 4747 | next_int_reg += 1; | 4793 | if (!omit_args_in_registers) { |
| | 4794 | for (param_types) |ty, i| { |
| | 4795 | if (!ty.hasRuntimeBits()) continue; |
| | 4796 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| | 4797 | // For simplicity of codegen, slices and other types are always pushed onto the stack. |
| | 4798 | // TODO: look into optimizing this by passing things as registers sometimes, |
| | 4799 | // such as ptr and len of slices as separate registers. |
| | 4800 | // TODO: also we need to honor the C ABI for relevant types rather than passing on |
| | 4801 | // the stack here. |
| | 4802 | const pass_in_reg = switch (ty.zigTypeTag()) { |
| | 4803 | .Bool => true, |
| | 4804 | .Int, .Enum => param_size <= 8, |
| | 4805 | .Pointer => ty.ptrSize() != .Slice, |
| | 4806 | .Optional => ty.isPtrLikeOptional(), |
| | 4807 | else => false, |
| | 4808 | }; |
| | 4809 | if (pass_in_reg) { |
| | 4810 | if (next_int_reg >= c_abi_int_param_regs.len) break; |
| | 4811 | try by_reg.putNoClobber(i, next_int_reg); |
| | 4812 | next_int_reg += 1; |
| | 4813 | } |
| 4748 | } | 4814 | } |
| 4749 | } | 4815 | } |
| 4750 | | 4816 | |
| ... | @@ -4765,19 +4831,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -4765,19 +4831,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4765 | result.args[i] = .{ .register = aliased_reg }; | 4831 | result.args[i] = .{ .register = aliased_reg }; |
| 4766 | next_int_reg += 1; | 4832 | next_int_reg += 1; |
| 4767 | } else { | 4833 | } else { |
| 4768 | // For simplicity of codegen, slices and other types are always pushed onto the stack. | | |
| 4769 | // TODO: look into optimizing this by passing things as registers sometimes, | | |
| 4770 | // such as ptr and len of slices as separate registers. | | |
| 4771 | // TODO: also we need to honor the C ABI for relevant types rather than passing on | | |
| 4772 | // the stack here. | | |
| 4773 | const offset = mem.alignForwardGeneric(u32, next_stack_offset + param_size, param_align); | 4834 | const offset = mem.alignForwardGeneric(u32, next_stack_offset + param_size, param_align); |
| 4774 | result.args[i] = .{ .stack_offset = @intCast(i32, offset) }; | 4835 | result.args[i] = .{ .stack_offset = @intCast(i32, offset) }; |
| 4775 | next_stack_offset = offset; | 4836 | next_stack_offset = offset; |
| 4776 | } | 4837 | } |
| 4777 | } | 4838 | } |
| 4778 | | 4839 | |
| 4779 | result.stack_byte_count = next_stack_offset; | | |
| 4780 | result.stack_align = 16; | 4840 | result.stack_align = 16; |
| | 4841 | result.stack_byte_count = mem.alignForwardGeneric(u32, next_stack_offset, result.stack_align); |
| 4781 | }, | 4842 | }, |
| 4782 | else => return self.fail("TODO implement function parameters for {} on x86_64", .{cc}), | 4843 | else => return self.fail("TODO implement function parameters for {} on x86_64", .{cc}), |
| 4783 | } | 4844 | } |