| ... | @@ -316,7 +316,7 @@ pub fn generate( | ... | @@ -316,7 +316,7 @@ pub fn generate( |
| 316 | defer function.mir_extra.deinit(bin_file.allocator); | 316 | defer function.mir_extra.deinit(bin_file.allocator); |
| 317 | defer if (builtin.mode == .Debug) function.mir_to_air_map.deinit(); | 317 | defer if (builtin.mode == .Debug) function.mir_to_air_map.deinit(); |
| 318 | | 318 | |
| 319 | var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) { | 319 | var call_info = function.resolveCallingConventionValues(fn_type, &.{}) catch |err| switch (err) { |
| 320 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, | 320 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| 321 | error.OutOfRegisters => return Result{ | 321 | error.OutOfRegisters => return Result{ |
| 322 | .fail = try ErrorMsg.create( | 322 | .fail = try ErrorMsg.create( |
| ... | @@ -952,10 +952,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -952,10 +952,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 952 | .neg, | 952 | .neg, |
| 953 | => try self.airUnaryMath(inst), | 953 | => try self.airUnaryMath(inst), |
| 954 | | 954 | |
| 955 | .add_with_overflow => try self.airAddSubShlWithOverflow(inst), | 955 | .add_with_overflow => try self.airAddSubWithOverflow(inst), |
| 956 | .sub_with_overflow => try self.airAddSubShlWithOverflow(inst), | 956 | .sub_with_overflow => try self.airAddSubWithOverflow(inst), |
| 957 | .mul_with_overflow => try self.airMulWithOverflow(inst), | 957 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 958 | .shl_with_overflow => try self.airAddSubShlWithOverflow(inst), | 958 | .shl_with_overflow => try self.airShlWithOverflow(inst), |
| 959 | | 959 | |
| 960 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airMulDivBinOp(inst), | 960 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airMulDivBinOp(inst), |
| 961 | | 961 | |
| ... | @@ -1625,24 +1625,68 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void | ... | @@ -1625,24 +1625,68 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void |
| 1625 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1625 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1626 | } | 1626 | } |
| 1627 | | 1627 | |
| | 1628 | fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| | 1629 | const air_tag = self.air.instructions.items(.tag); |
| | 1630 | const air_data = self.air.instructions.items(.data); |
| | 1631 | |
| | 1632 | const dst_ty = self.air.typeOf(dst_air); |
| | 1633 | const dst_info = dst_ty.intInfo(self.target.*); |
| | 1634 | if (Air.refToIndex(dst_air)) |inst| { |
| | 1635 | switch (air_tag[inst]) { |
| | 1636 | .constant => { |
| | 1637 | const src_val = self.air.values[air_data[inst].ty_pl.payload]; |
| | 1638 | var space: Value.BigIntSpace = undefined; |
| | 1639 | const src_int = src_val.toBigInt(&space, self.target.*); |
| | 1640 | return @intCast(u16, src_int.bitCountTwosComp()) + |
| | 1641 | @boolToInt(src_int.positive and dst_info.signedness == .signed); |
| | 1642 | }, |
| | 1643 | .intcast => { |
| | 1644 | const src_ty = self.air.typeOf(air_data[inst].ty_op.operand); |
| | 1645 | const src_info = src_ty.intInfo(self.target.*); |
| | 1646 | return @min(switch (src_info.signedness) { |
| | 1647 | .signed => switch (dst_info.signedness) { |
| | 1648 | .signed => src_info.bits, |
| | 1649 | .unsigned => src_info.bits - 1, |
| | 1650 | }, |
| | 1651 | .unsigned => switch (dst_info.signedness) { |
| | 1652 | .signed => src_info.bits + 1, |
| | 1653 | .unsigned => src_info.bits, |
| | 1654 | }, |
| | 1655 | }, dst_info.bits); |
| | 1656 | }, |
| | 1657 | else => {}, |
| | 1658 | } |
| | 1659 | } |
| | 1660 | return dst_info.bits; |
| | 1661 | } |
| | 1662 | |
| 1628 | fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { | 1663 | fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1629 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1664 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1630 | const result = result: { | 1665 | const result = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1631 | if (self.liveness.isUnused(inst)) break :result .dead; | | |
| 1632 | | | |
| 1633 | const tag = self.air.instructions.items(.tag)[inst]; | 1666 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1634 | const ty = self.air.typeOfIndex(inst); | 1667 | const dst_ty = self.air.typeOfIndex(inst); |
| 1635 | | 1668 | if (dst_ty.zigTypeTag() == .Float) |
| 1636 | if (ty.zigTypeTag() == .Float) { | | |
| 1637 | break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); | 1669 | break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1638 | } | | |
| 1639 | | 1670 | |
| 1640 | try self.spillRegisters(&.{ .rax, .rdx }); | 1671 | const dst_info = dst_ty.intInfo(self.target.*); |
| | 1672 | var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { |
| | 1673 | .signed => .int_signed, |
| | 1674 | .unsigned => .int_unsigned, |
| | 1675 | } }, .data = switch (tag) { |
| | 1676 | else => unreachable, |
| | 1677 | .mul, .mulwrap => std.math.max3( |
| | 1678 | self.activeIntBits(bin_op.lhs), |
| | 1679 | self.activeIntBits(bin_op.rhs), |
| | 1680 | dst_info.bits / 2, |
| | 1681 | ), |
| | 1682 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_info.bits, |
| | 1683 | } }; |
| | 1684 | const src_ty = Type.initPayload(&src_pl.base); |
| 1641 | | 1685 | |
| | 1686 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 1642 | const lhs = try self.resolveInst(bin_op.lhs); | 1687 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1643 | const rhs = try self.resolveInst(bin_op.rhs); | 1688 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1644 | | 1689 | break :result try self.genMulDivBinOp(tag, inst, dst_ty, src_ty, lhs, rhs); |
| 1645 | break :result try self.genMulDivBinOp(tag, inst, ty, lhs, rhs); | | |
| 1646 | }; | 1690 | }; |
| 1647 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1691 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1648 | } | 1692 | } |
| ... | @@ -1795,7 +1839,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1795,7 +1839,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1795 | break :cc .c; | 1839 | break :cc .c; |
| 1796 | }; | 1840 | }; |
| 1797 | | 1841 | |
| 1798 | const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, lhs_mcv, rhs_mcv); | 1842 | const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, ty, lhs_mcv, rhs_mcv); |
| 1799 | const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2)); | 1843 | const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2)); |
| 1800 | try self.asmCmovccRegisterRegister( | 1844 | try self.asmCmovccRegisterRegister( |
| 1801 | registerAlias(dst_mcv.register, abi_size), | 1845 | registerAlias(dst_mcv.register, abi_size), |
| ... | @@ -1807,70 +1851,133 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1807,70 +1851,133 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1807 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1851 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1808 | } | 1852 | } |
| 1809 | | 1853 | |
| 1810 | fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1854 | fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1811 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1855 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1812 | const tag = self.air.instructions.items(.tag)[inst]; | | |
| 1813 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1856 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1814 | const result = if (self.liveness.isUnused(inst)) .dead else result: { | 1857 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1858 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1815 | const ty = self.air.typeOf(bin_op.lhs); | 1859 | const ty = self.air.typeOf(bin_op.lhs); |
| 1816 | const abi_size = ty.abiSize(self.target.*); | | |
| 1817 | switch (ty.zigTypeTag()) { | 1860 | switch (ty.zigTypeTag()) { |
| 1818 | .Vector => return self.fail("TODO implement add/sub/shl with overflow for Vector type", .{}), | 1861 | .Vector => return self.fail("TODO implement add/sub with overflow for Vector type", .{}), |
| 1819 | .Int => { | 1862 | .Int => { |
| 1820 | if (abi_size > 8) { | | |
| 1821 | return self.fail("TODO implement add/sub/shl with overflow for Ints larger than 64bits", .{}); | | |
| 1822 | } | | |
| 1823 | | | |
| 1824 | try self.spillEflagsIfOccupied(); | 1863 | try self.spillEflagsIfOccupied(); |
| 1825 | | 1864 | |
| 1826 | if (tag == .shl_with_overflow) { | 1865 | const partial_mcv = switch (tag) { |
| 1827 | try self.spillRegisters(&.{.rcx}); | | |
| 1828 | } | | |
| 1829 | | | |
| 1830 | const partial: MCValue = switch (tag) { | | |
| 1831 | .add_with_overflow => try self.genBinOp(null, .add, bin_op.lhs, bin_op.rhs), | 1866 | .add_with_overflow => try self.genBinOp(null, .add, bin_op.lhs, bin_op.rhs), |
| 1832 | .sub_with_overflow => try self.genBinOp(null, .sub, bin_op.lhs, bin_op.rhs), | 1867 | .sub_with_overflow => try self.genBinOp(null, .sub, bin_op.lhs, bin_op.rhs), |
| 1833 | .shl_with_overflow => blk: { | | |
| 1834 | try self.register_manager.getReg(.rcx, null); | | |
| 1835 | const lhs = try self.resolveInst(bin_op.lhs); | | |
| 1836 | const rhs = try self.resolveInst(bin_op.rhs); | | |
| 1837 | const shift_ty = self.air.typeOf(bin_op.rhs); | | |
| 1838 | break :blk try self.genShiftBinOp(.shl, null, lhs, rhs, ty, shift_ty); | | |
| 1839 | }, | | |
| 1840 | else => unreachable, | 1868 | else => unreachable, |
| 1841 | }; | 1869 | }; |
| 1842 | | | |
| 1843 | const int_info = ty.intInfo(self.target.*); | 1870 | const int_info = ty.intInfo(self.target.*); |
| | 1871 | const cc: Condition = switch (int_info.signedness) { |
| | 1872 | .unsigned => .c, |
| | 1873 | .signed => .o, |
| | 1874 | }; |
| 1844 | | 1875 | |
| 1845 | if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) { | 1876 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 1846 | self.eflags_inst = inst; | 1877 | switch (partial_mcv) { |
| | 1878 | .register => |reg| { |
| | 1879 | self.eflags_inst = inst; |
| | 1880 | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; |
| | 1881 | }, |
| | 1882 | else => {}, |
| | 1883 | } |
| 1847 | | 1884 | |
| 1848 | const cc: Condition = switch (int_info.signedness) { | 1885 | const abi_size = @intCast(i32, ty.abiSize(self.target.*)); |
| 1849 | .unsigned => .c, | 1886 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1850 | .signed => .o, | 1887 | try self.genSetStack( |
| 1851 | }; | 1888 | Type.u1, |
| 1852 | break :result MCValue{ .register_overflow = .{ | 1889 | dst_mcv.stack_offset - abi_size, |
| 1853 | .reg = partial.register, | 1890 | .{ .eflags = cc }, |
| 1854 | .eflags = cc, | 1891 | .{}, |
| 1855 | } }; | 1892 | ); |
| | 1893 | try self.genSetStack(ty, dst_mcv.stack_offset, partial_mcv, .{}); |
| | 1894 | break :result dst_mcv; |
| 1856 | } | 1895 | } |
| 1857 | | 1896 | |
| 1858 | self.eflags_inst = null; | | |
| 1859 | | | |
| 1860 | const tuple_ty = self.air.typeOfIndex(inst); | 1897 | const tuple_ty = self.air.typeOfIndex(inst); |
| 1861 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | 1898 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); |
| 1862 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | 1899 | const tuple_align = tuple_ty.abiAlignment(self.target.*); |
| 1863 | const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)); | 1900 | const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)); |
| 1864 | const stack_offset = @intCast(i32, try self.allocMem(inst, tuple_size, tuple_align)); | 1901 | const stack_offset = @intCast(i32, try self.allocMem(inst, tuple_size, tuple_align)); |
| 1865 | | 1902 | |
| 1866 | try self.genSetStackTruncatedOverflowCompare(ty, stack_offset, overflow_bit_offset, partial.register); | 1903 | try self.genSetStackTruncatedOverflowCompare(ty, stack_offset, overflow_bit_offset, partial_mcv.register, cc); |
| 1867 | | 1904 | |
| 1868 | break :result MCValue{ .stack_offset = stack_offset }; | 1905 | break :result .{ .stack_offset = stack_offset }; |
| 1869 | }, | 1906 | }, |
| 1870 | else => unreachable, | 1907 | else => unreachable, |
| 1871 | } | 1908 | } |
| 1872 | }; | 1909 | }; |
| | 1910 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 1911 | } |
| 1873 | | 1912 | |
| | 1913 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| | 1914 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| | 1915 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 1916 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1917 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| | 1918 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| | 1919 | switch (lhs_ty.zigTypeTag()) { |
| | 1920 | .Vector => return self.fail("TODO implement shl with overflow for Vector type", .{}), |
| | 1921 | .Int => { |
| | 1922 | try self.spillEflagsIfOccupied(); |
| | 1923 | |
| | 1924 | try self.register_manager.getReg(.rcx, null); |
| | 1925 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1926 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1927 | |
| | 1928 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 1929 | |
| | 1930 | const partial_mcv = try self.genShiftBinOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty); |
| | 1931 | const partial_lock = switch (partial_mcv) { |
| | 1932 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 1933 | else => null, |
| | 1934 | }; |
| | 1935 | defer if (partial_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1936 | |
| | 1937 | const tmp_mcv = try self.genShiftBinOp(.shr, null, partial_mcv, rhs, lhs_ty, rhs_ty); |
| | 1938 | const tmp_lock = switch (tmp_mcv) { |
| | 1939 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 1940 | else => null, |
| | 1941 | }; |
| | 1942 | defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1943 | |
| | 1944 | try self.genBinOpMir(.cmp, lhs_ty, tmp_mcv, lhs); |
| | 1945 | const cc = Condition.ne; |
| | 1946 | |
| | 1947 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| | 1948 | switch (partial_mcv) { |
| | 1949 | .register => |reg| { |
| | 1950 | self.eflags_inst = inst; |
| | 1951 | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; |
| | 1952 | }, |
| | 1953 | else => {}, |
| | 1954 | } |
| | 1955 | |
| | 1956 | const abi_size = @intCast(i32, lhs_ty.abiSize(self.target.*)); |
| | 1957 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| | 1958 | try self.genSetStack( |
| | 1959 | Type.u1, |
| | 1960 | dst_mcv.stack_offset - abi_size, |
| | 1961 | .{ .eflags = cc }, |
| | 1962 | .{}, |
| | 1963 | ); |
| | 1964 | try self.genSetStack(lhs_ty, dst_mcv.stack_offset, partial_mcv, .{}); |
| | 1965 | break :result dst_mcv; |
| | 1966 | } |
| | 1967 | |
| | 1968 | const tuple_ty = self.air.typeOfIndex(inst); |
| | 1969 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); |
| | 1970 | const tuple_align = tuple_ty.abiAlignment(self.target.*); |
| | 1971 | const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)); |
| | 1972 | const stack_offset = @intCast(i32, try self.allocMem(inst, tuple_size, tuple_align)); |
| | 1973 | |
| | 1974 | try self.genSetStackTruncatedOverflowCompare(lhs_ty, stack_offset, overflow_bit_offset, partial_mcv.register, cc); |
| | 1975 | |
| | 1976 | break :result .{ .stack_offset = stack_offset }; |
| | 1977 | }, |
| | 1978 | else => unreachable, |
| | 1979 | } |
| | 1980 | }; |
| 1874 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1981 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1875 | } | 1982 | } |
| 1876 | | 1983 | |
| ... | @@ -1880,6 +1987,7 @@ fn genSetStackTruncatedOverflowCompare( | ... | @@ -1880,6 +1987,7 @@ fn genSetStackTruncatedOverflowCompare( |
| 1880 | stack_offset: i32, | 1987 | stack_offset: i32, |
| 1881 | overflow_bit_offset: i32, | 1988 | overflow_bit_offset: i32, |
| 1882 | reg: Register, | 1989 | reg: Register, |
| | 1990 | cc: Condition, |
| 1883 | ) !void { | 1991 | ) !void { |
| 1884 | const reg_lock = self.register_manager.lockReg(reg); | 1992 | const reg_lock = self.register_manager.lockReg(reg); |
| 1885 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); | 1993 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | @@ -1897,10 +2005,6 @@ fn genSetStackTruncatedOverflowCompare( | ... | @@ -1897,10 +2005,6 @@ fn genSetStackTruncatedOverflowCompare( |
| 1897 | }; | 2005 | }; |
| 1898 | | 2006 | |
| 1899 | const overflow_reg = temp_regs[0]; | 2007 | const overflow_reg = temp_regs[0]; |
| 1900 | const cc: Condition = switch (int_info.signedness) { | | |
| 1901 | .signed => .o, | | |
| 1902 | .unsigned => .c, | | |
| 1903 | }; | | |
| 1904 | try self.asmSetccRegister(overflow_reg.to8(), cc); | 2008 | try self.asmSetccRegister(overflow_reg.to8(), cc); |
| 1905 | | 2009 | |
| 1906 | const scratch_reg = temp_regs[1]; | 2010 | const scratch_reg = temp_regs[1]; |
| ... | @@ -1923,7 +2027,7 @@ fn genSetStackTruncatedOverflowCompare( | ... | @@ -1923,7 +2027,7 @@ fn genSetStackTruncatedOverflowCompare( |
| 1923 | ); | 2027 | ); |
| 1924 | | 2028 | |
| 1925 | try self.genSetStack(ty, stack_offset, .{ .register = scratch_reg }, .{}); | 2029 | try self.genSetStack(ty, stack_offset, .{ .register = scratch_reg }, .{}); |
| 1926 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ | 2030 | try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{ |
| 1927 | .register = overflow_reg.to8(), | 2031 | .register = overflow_reg.to8(), |
| 1928 | }, .{}); | 2032 | }, .{}); |
| 1929 | } | 2033 | } |
| ... | @@ -1931,48 +2035,56 @@ fn genSetStackTruncatedOverflowCompare( | ... | @@ -1931,48 +2035,56 @@ fn genSetStackTruncatedOverflowCompare( |
| 1931 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 2035 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1932 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2036 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1933 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2037 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1934 | | 2038 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1935 | if (self.liveness.isUnused(inst)) { | 2039 | const dst_ty = self.air.typeOf(bin_op.lhs); |
| 1936 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 2040 | switch (dst_ty.zigTypeTag()) { |
| 1937 | } | | |
| 1938 | | | |
| 1939 | const ty = self.air.typeOf(bin_op.lhs); | | |
| 1940 | const abi_size = ty.abiSize(self.target.*); | | |
| 1941 | const result: MCValue = result: { | | |
| 1942 | switch (ty.zigTypeTag()) { | | |
| 1943 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), | 2041 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| 1944 | .Int => { | 2042 | .Int => { |
| 1945 | if (abi_size > 8) { | 2043 | try self.spillEflagsIfOccupied(); |
| 1946 | return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{}); | | |
| 1947 | } | | |
| 1948 | | | |
| 1949 | const int_info = ty.intInfo(self.target.*); | | |
| 1950 | | 2044 | |
| 1951 | if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) { | 2045 | const dst_info = dst_ty.intInfo(self.target.*); |
| 1952 | try self.spillEflagsIfOccupied(); | 2046 | const cc: Condition = switch (dst_info.signedness) { |
| 1953 | self.eflags_inst = inst; | 2047 | .unsigned => .c, |
| | 2048 | .signed => .o, |
| | 2049 | }; |
| | 2050 | if (dst_info.bits >= 8 and math.isPowerOfTwo(dst_info.bits)) { |
| | 2051 | var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { |
| | 2052 | .signed => .int_signed, |
| | 2053 | .unsigned => .int_unsigned, |
| | 2054 | } }, .data = std.math.max3( |
| | 2055 | self.activeIntBits(bin_op.lhs), |
| | 2056 | self.activeIntBits(bin_op.rhs), |
| | 2057 | dst_info.bits / 2, |
| | 2058 | ) }; |
| | 2059 | const src_ty = Type.initPayload(&src_pl.base); |
| 1954 | | 2060 | |
| 1955 | try self.spillRegisters(&.{ .rax, .rdx }); | 2061 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 1956 | | | |
| 1957 | const lhs = try self.resolveInst(bin_op.lhs); | 2062 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1958 | const rhs = try self.resolveInst(bin_op.rhs); | 2063 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1959 | | 2064 | |
| 1960 | const partial = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs); | 2065 | const partial_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs); |
| 1961 | const cc: Condition = switch (int_info.signedness) { | 2066 | switch (partial_mcv) { |
| 1962 | .unsigned => .c, | 2067 | .register => |reg| { |
| 1963 | .signed => .o, | 2068 | self.eflags_inst = inst; |
| 1964 | }; | 2069 | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; |
| 1965 | break :result MCValue{ .register_overflow = .{ | 2070 | }, |
| 1966 | .reg = partial.register, | 2071 | else => {}, |
| 1967 | .eflags = cc, | 2072 | } |
| 1968 | } }; | | |
| 1969 | } | | |
| 1970 | | 2073 | |
| 1971 | try self.spillEflagsIfOccupied(); | 2074 | const dst_abi_size = @intCast(i32, dst_ty.abiSize(self.target.*)); |
| 1972 | self.eflags_inst = null; | 2075 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| | 2076 | try self.genSetStack( |
| | 2077 | Type.u1, |
| | 2078 | dst_mcv.stack_offset - dst_abi_size, |
| | 2079 | .{ .eflags = cc }, |
| | 2080 | .{}, |
| | 2081 | ); |
| | 2082 | try self.genSetStack(dst_ty, dst_mcv.stack_offset, partial_mcv, .{}); |
| | 2083 | break :result dst_mcv; |
| | 2084 | } |
| 1973 | | 2085 | |
| 1974 | const dst_reg: Register = dst_reg: { | 2086 | const dst_reg: Register = dst_reg: { |
| 1975 | switch (int_info.signedness) { | 2087 | switch (dst_info.signedness) { |
| 1976 | .signed => { | 2088 | .signed => { |
| 1977 | const lhs = try self.resolveInst(bin_op.lhs); | 2089 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1978 | const rhs = try self.resolveInst(bin_op.rhs); | 2090 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | @@ -1985,14 +2097,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1985,14 +2097,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1985 | | 2097 | |
| 1986 | const dst_reg: Register = blk: { | 2098 | const dst_reg: Register = blk: { |
| 1987 | if (lhs.isRegister()) break :blk lhs.register; | 2099 | if (lhs.isRegister()) break :blk lhs.register; |
| 1988 | break :blk try self.copyToTmpRegister(ty, lhs); | 2100 | break :blk try self.copyToTmpRegister(dst_ty, lhs); |
| 1989 | }; | 2101 | }; |
| 1990 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 2102 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 1991 | defer self.register_manager.unlockReg(dst_reg_lock); | 2103 | defer self.register_manager.unlockReg(dst_reg_lock); |
| 1992 | | 2104 | |
| 1993 | const rhs_mcv: MCValue = blk: { | 2105 | const rhs_mcv: MCValue = blk: { |
| 1994 | if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; | 2106 | if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; |
| 1995 | break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) }; | 2107 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; |
| 1996 | }; | 2108 | }; |
| 1997 | const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) { | 2109 | const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) { |
| 1998 | .register => |reg| self.register_manager.lockReg(reg), | 2110 | .register => |reg| self.register_manager.lockReg(reg), |
| ... | @@ -2010,7 +2122,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2010,7 +2122,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2010 | const lhs = try self.resolveInst(bin_op.lhs); | 2122 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2011 | const rhs = try self.resolveInst(bin_op.rhs); | 2123 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2012 | | 2124 | |
| 2013 | const dst_mcv = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs); | 2125 | const dst_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, dst_ty, lhs, rhs); |
| 2014 | break :dst_reg dst_mcv.register; | 2126 | break :dst_reg dst_mcv.register; |
| 2015 | }, | 2127 | }, |
| 2016 | } | 2128 | } |
| ... | @@ -2022,14 +2134,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2022,14 +2134,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2022 | const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)); | 2134 | const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)); |
| 2023 | const stack_offset = @intCast(i32, try self.allocMem(inst, tuple_size, tuple_align)); | 2135 | const stack_offset = @intCast(i32, try self.allocMem(inst, tuple_size, tuple_align)); |
| 2024 | | 2136 | |
| 2025 | try self.genSetStackTruncatedOverflowCompare(ty, stack_offset, overflow_bit_offset, dst_reg); | 2137 | try self.genSetStackTruncatedOverflowCompare(dst_ty, stack_offset, overflow_bit_offset, dst_reg, cc); |
| 2026 | | 2138 | |
| 2027 | break :result MCValue{ .stack_offset = stack_offset }; | 2139 | break :result .{ .stack_offset = stack_offset }; |
| 2028 | }, | 2140 | }, |
| 2029 | else => unreachable, | 2141 | else => unreachable, |
| 2030 | } | 2142 | } |
| 2031 | }; | 2143 | }; |
| 2032 | | | |
| 2033 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2144 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2034 | } | 2145 | } |
| 2035 | | 2146 | |
| ... | @@ -2040,7 +2151,6 @@ fn genIntMulDivOpMir( | ... | @@ -2040,7 +2151,6 @@ fn genIntMulDivOpMir( |
| 2040 | self: *Self, | 2151 | self: *Self, |
| 2041 | tag: Mir.Inst.Tag, | 2152 | tag: Mir.Inst.Tag, |
| 2042 | ty: Type, | 2153 | ty: Type, |
| 2043 | signedness: std.builtin.Signedness, | | |
| 2044 | lhs: MCValue, | 2154 | lhs: MCValue, |
| 2045 | rhs: MCValue, | 2155 | rhs: MCValue, |
| 2046 | ) !void { | 2156 | ) !void { |
| ... | @@ -2057,26 +2167,23 @@ fn genIntMulDivOpMir( | ... | @@ -2057,26 +2167,23 @@ fn genIntMulDivOpMir( |
| 2057 | try self.genSetReg(ty, .rax, lhs); | 2167 | try self.genSetReg(ty, .rax, lhs); |
| 2058 | } | 2168 | } |
| 2059 | | 2169 | |
| 2060 | switch (signedness) { | 2170 | switch (tag) { |
| 2061 | .signed => try self.asmOpOnly(.cqo), | 2171 | else => unreachable, |
| 2062 | .unsigned => try self.asmRegisterRegister(.xor, .rdx, .rdx), | 2172 | .mul, .imul => {}, |
| | 2173 | .div => try self.asmRegisterRegister(.xor, .edx, .edx), |
| | 2174 | .idiv => try self.asmOpOnly(.cqo), |
| 2063 | } | 2175 | } |
| 2064 | | 2176 | |
| 2065 | const factor = switch (rhs) { | 2177 | const factor: MCValue = switch (rhs) { |
| 2066 | .register => rhs, | 2178 | .register, .stack_offset => rhs, |
| 2067 | .stack_offset => rhs, | 2179 | else => .{ .register = try self.copyToTmpRegister(ty, rhs) }, |
| 2068 | else => blk: { | | |
| 2069 | const reg = try self.copyToTmpRegister(ty, rhs); | | |
| 2070 | break :blk MCValue{ .register = reg }; | | |
| 2071 | }, | | |
| 2072 | }; | 2180 | }; |
| 2073 | | | |
| 2074 | switch (factor) { | 2181 | switch (factor) { |
| 2075 | .register => |reg| try self.asmRegister(tag, reg), | 2182 | .register => |reg| try self.asmRegister(tag, reg), |
| 2076 | .stack_offset => |off| try self.asmMemory(tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | 2183 | .stack_offset => |off| try self.asmMemory(tag, Memory.sib( |
| 2077 | .base = .rbp, | 2184 | Memory.PtrSize.fromSize(abi_size), |
| 2078 | .disp = -off, | 2185 | .{ .base = .rbp, .disp = -off }, |
| 2079 | })), | 2186 | )), |
| 2080 | else => unreachable, | 2187 | else => unreachable, |
| 2081 | } | 2188 | } |
| 2082 | } | 2189 | } |
| ... | @@ -2102,7 +2209,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa | ... | @@ -2102,7 +2209,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 2102 | try self.genIntMulDivOpMir(switch (signedness) { | 2209 | try self.genIntMulDivOpMir(switch (signedness) { |
| 2103 | .signed => .idiv, | 2210 | .signed => .idiv, |
| 2104 | .unsigned => .div, | 2211 | .unsigned => .div, |
| 2105 | }, Type.isize, signedness, .{ .register = dividend }, .{ .register = divisor }); | 2212 | }, Type.isize, .{ .register = dividend }, .{ .register = divisor }); |
| 2106 | | 2213 | |
| 2107 | try self.asmRegisterRegister(.xor, divisor.to64(), dividend.to64()); | 2214 | try self.asmRegisterRegister(.xor, divisor.to64(), dividend.to64()); |
| 2108 | try self.asmRegisterImmediate(.sar, divisor.to64(), Immediate.u(63)); | 2215 | try self.asmRegisterImmediate(.sar, divisor.to64(), Immediate.u(63)); |
| ... | @@ -3818,45 +3925,95 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 | ... | @@ -3818,45 +3925,95 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 |
| 3818 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | 3925 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3819 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 3926 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3820 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 3927 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 3821 | const operand = extra.struct_operand; | 3928 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3822 | const index = extra.field_index; | 3929 | const operand = extra.struct_operand; |
| | 3930 | const index = extra.field_index; |
| | 3931 | |
| | 3932 | const container_ty = self.air.typeOf(operand); |
| | 3933 | const field_ty = container_ty.structFieldType(index); |
| | 3934 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) break :result .none; |
| | 3935 | |
| | 3936 | const src_mcv = try self.resolveInst(operand); |
| | 3937 | const field_off = switch (container_ty.containerLayout()) { |
| | 3938 | .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*) * 8), |
| | 3939 | .Packed => if (container_ty.castTag(.@"struct")) |struct_obj| |
| | 3940 | struct_obj.data.packedFieldBitOffset(self.target.*, index) |
| | 3941 | else |
| | 3942 | 0, |
| | 3943 | }; |
| 3823 | | 3944 | |
| 3824 | if (self.liveness.isUnused(inst)) { | 3945 | switch (src_mcv) { |
| 3825 | return self.finishAir(inst, .dead, .{ extra.struct_operand, .none, .none }); | 3946 | .stack_offset => |src_off| { |
| 3826 | } | 3947 | const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*)); |
| | 3948 | const limb_abi_size = @min(field_abi_size, 8); |
| | 3949 | const limb_abi_bits = limb_abi_size * 8; |
| | 3950 | const field_byte_off = @intCast(i32, field_off / limb_abi_bits * limb_abi_size); |
| | 3951 | const field_bit_off = field_off % limb_abi_bits; |
| | 3952 | |
| | 3953 | if (field_bit_off == 0) { |
| | 3954 | const off_mcv = MCValue{ .stack_offset = src_off - field_byte_off }; |
| | 3955 | if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result off_mcv; |
| | 3956 | |
| | 3957 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| | 3958 | try self.setRegOrMem(field_ty, dst_mcv, off_mcv); |
| | 3959 | break :result dst_mcv; |
| | 3960 | } |
| 3827 | | 3961 | |
| 3828 | const mcv = try self.resolveInst(operand); | 3962 | if (field_abi_size > 8) { |
| 3829 | const container_ty = self.air.typeOf(operand); | 3963 | return self.fail("TODO implement struct_field_val with large packed field", .{}); |
| 3830 | const field_ty = container_ty.structFieldType(index); | 3964 | } |
| 3831 | const field_bit_offset = switch (container_ty.containerLayout()) { | | |
| 3832 | .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*) * 8), | | |
| 3833 | .Packed => if (container_ty.castTag(.@"struct")) |struct_obj| | | |
| 3834 | struct_obj.data.packedFieldBitOffset(self.target.*, index) | | |
| 3835 | else | | |
| 3836 | 0, | | |
| 3837 | }; | | |
| 3838 | | 3965 | |
| 3839 | const result: MCValue = result: { | 3966 | const dst_reg = try self.register_manager.allocReg(inst, gp); |
| 3840 | switch (mcv) { | 3967 | const field_extra_bits = self.regExtraBits(field_ty); |
| 3841 | .stack_offset => |off| { | 3968 | const load_abi_size = |
| 3842 | const byte_offset = std.math.divExact(u32, field_bit_offset, 8) catch | 3969 | if (field_bit_off < field_extra_bits) field_abi_size else field_abi_size * 2; |
| 3843 | return self.fail("TODO implement struct_field_val for a packed struct", .{}); | 3970 | if (load_abi_size <= 8) { |
| 3844 | break :result MCValue{ .stack_offset = off - @intCast(i32, byte_offset) }; | 3971 | const load_reg = registerAlias(dst_reg, load_abi_size); |
| | 3972 | try self.asmRegisterMemory(.mov, load_reg, Memory.sib( |
| | 3973 | Memory.PtrSize.fromSize(load_abi_size), |
| | 3974 | .{ .base = .rbp, .disp = field_byte_off - src_off }, |
| | 3975 | )); |
| | 3976 | try self.asmRegisterImmediate(.shr, load_reg, Immediate.u(field_bit_off)); |
| | 3977 | } else { |
| | 3978 | const tmp_reg = registerAlias( |
| | 3979 | try self.register_manager.allocReg(null, gp), |
| | 3980 | field_abi_size, |
| | 3981 | ); |
| | 3982 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| | 3983 | defer self.register_manager.unlockReg(tmp_lock); |
| | 3984 | |
| | 3985 | const dst_alias = registerAlias(dst_reg, field_abi_size); |
| | 3986 | try self.asmRegisterMemory(.mov, dst_alias, Memory.sib( |
| | 3987 | Memory.PtrSize.fromSize(field_abi_size), |
| | 3988 | .{ .base = .rbp, .disp = field_byte_off - src_off }, |
| | 3989 | )); |
| | 3990 | try self.asmRegisterMemory(.mov, tmp_reg, Memory.sib( |
| | 3991 | Memory.PtrSize.fromSize(field_abi_size), |
| | 3992 | .{ .base = .rbp, .disp = field_byte_off + 1 - src_off }, |
| | 3993 | )); |
| | 3994 | try self.asmRegisterRegisterImmediate( |
| | 3995 | .shrd, |
| | 3996 | dst_alias, |
| | 3997 | tmp_reg, |
| | 3998 | Immediate.u(field_bit_off), |
| | 3999 | ); |
| | 4000 | } |
| | 4001 | |
| | 4002 | if (field_extra_bits > 0) try self.truncateRegister(field_ty, dst_reg); |
| | 4003 | break :result .{ .register = dst_reg }; |
| 3845 | }, | 4004 | }, |
| 3846 | .register => |reg| { | 4005 | .register => |reg| { |
| 3847 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); | 4006 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 3848 | defer self.register_manager.unlockReg(reg_lock); | 4007 | defer self.register_manager.unlockReg(reg_lock); |
| 3849 | | 4008 | |
| 3850 | const dst_mcv: MCValue = blk: { | 4009 | const dst_mcv = if (self.reuseOperand(inst, operand, 0, src_mcv)) |
| 3851 | if (self.reuseOperand(inst, operand, 0, mcv)) { | 4010 | src_mcv |
| 3852 | break :blk mcv; | 4011 | else |
| 3853 | } else { | 4012 | try self.copyToRegisterWithInstTracking( |
| 3854 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, Type.usize, .{ | 4013 | inst, |
| 3855 | .register = reg.to64(), | 4014 | Type.usize, |
| 3856 | }); | 4015 | .{ .register = reg.to64() }, |
| 3857 | break :blk dst_mcv; | 4016 | ); |
| 3858 | } | | |
| 3859 | }; | | |
| 3860 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { | 4017 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 3861 | .register => |a_reg| self.register_manager.lockReg(a_reg), | 4018 | .register => |a_reg| self.register_manager.lockReg(a_reg), |
| 3862 | else => null, | 4019 | else => null, |
| ... | @@ -3864,7 +4021,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3864,7 +4021,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3864 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); | 4021 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3865 | | 4022 | |
| 3866 | // Shift by struct_field_offset. | 4023 | // Shift by struct_field_offset. |
| 3867 | try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv, .{ .immediate = field_bit_offset }); | 4024 | try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv, .{ .immediate = field_off }); |
| 3868 | | 4025 | |
| 3869 | // Mask to field_bit_size bits | 4026 | // Mask to field_bit_size bits |
| 3870 | const field_bit_size = field_ty.bitSize(self.target.*); | 4027 | const field_bit_size = field_ty.bitSize(self.target.*); |
| ... | @@ -3883,31 +4040,34 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3883,31 +4040,34 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3883 | registerAlias(dst_mcv.register, field_byte_size), | 4040 | registerAlias(dst_mcv.register, field_byte_size), |
| 3884 | ); | 4041 | ); |
| 3885 | } | 4042 | } |
| 3886 | | | |
| 3887 | break :result dst_mcv; | 4043 | break :result dst_mcv; |
| 3888 | }, | 4044 | }, |
| 3889 | .register_overflow => |ro| { | 4045 | .register_overflow => |ro| { |
| 3890 | switch (index) { | 4046 | switch (index) { |
| 3891 | 0 => { | 4047 | // Get wrapped value for overflow operation. |
| 3892 | // Get wrapped value for overflow operation. | 4048 | 0 => break :result if (self.liveness.operandDies(inst, 0)) |
| 3893 | break :result MCValue{ .register = ro.reg }; | 4049 | .{ .register = ro.reg } |
| 3894 | }, | 4050 | else |
| 3895 | 1 => { | 4051 | try self.copyToRegisterWithInstTracking( |
| 3896 | // Get overflow bit. | 4052 | inst, |
| 3897 | const reg_lock = self.register_manager.lockRegAssumeUnused(ro.reg); | 4053 | Type.usize, |
| 3898 | defer self.register_manager.unlockReg(reg_lock); | 4054 | .{ .register = ro.reg }, |
| 3899 | | 4055 | ), |
| | 4056 | // Get overflow bit. |
| | 4057 | 1 => if (self.liveness.operandDies(inst, 0)) { |
| | 4058 | self.eflags_inst = inst; |
| | 4059 | break :result .{ .eflags = ro.eflags }; |
| | 4060 | } else { |
| 3900 | const dst_reg = try self.register_manager.allocReg(inst, gp); | 4061 | const dst_reg = try self.register_manager.allocReg(inst, gp); |
| 3901 | try self.asmSetccRegister(dst_reg.to8(), ro.eflags); | 4062 | try self.asmSetccRegister(dst_reg.to8(), ro.eflags); |
| 3902 | break :result MCValue{ .register = dst_reg.to8() }; | 4063 | break :result .{ .register = dst_reg.to8() }; |
| 3903 | }, | 4064 | }, |
| 3904 | else => unreachable, | 4065 | else => unreachable, |
| 3905 | } | 4066 | } |
| 3906 | }, | 4067 | }, |
| 3907 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), | 4068 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{src_mcv}), |
| 3908 | } | 4069 | } |
| 3909 | }; | 4070 | }; |
| 3910 | | | |
| 3911 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); | 4071 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 3912 | } | 4072 | } |
| 3913 | | 4073 | |
| ... | @@ -3986,7 +4146,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue | ... | @@ -3986,7 +4146,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue |
| 3986 | .eflags => unreachable, | 4146 | .eflags => unreachable, |
| 3987 | .register_overflow => unreachable, | 4147 | .register_overflow => unreachable, |
| 3988 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), | 4148 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), |
| 3989 | .ptr_stack_offset, .stack_offset => |off| { | 4149 | .stack_offset => |off| { |
| 3990 | if (abi_size > 8) { | 4150 | if (abi_size > 8) { |
| 3991 | return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag}); | 4151 | return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag}); |
| 3992 | } | 4152 | } |
| ... | @@ -3996,20 +4156,13 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue | ... | @@ -3996,20 +4156,13 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue |
| 3996 | .disp = -off, | 4156 | .disp = -off, |
| 3997 | })); | 4157 | })); |
| 3998 | }, | 4158 | }, |
| | 4159 | .ptr_stack_offset => unreachable, |
| 3999 | .memory, .linker_load => { | 4160 | .memory, .linker_load => { |
| 4000 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); | 4161 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); |
| 4001 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | 4162 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 4002 | defer self.register_manager.unlockReg(addr_reg_lock); | 4163 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 4003 | | 4164 | |
| 4004 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv); | 4165 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv); |
| 4005 | | | |
| 4006 | // To get the actual address of the value we want to modify we have to go through the GOT | | |
| 4007 | try self.asmRegisterMemory( | | |
| 4008 | .mov, | | |
| 4009 | addr_reg, | | |
| 4010 | Memory.sib(.qword, .{ .base = addr_reg }), | | |
| 4011 | ); | | |
| 4012 | | | |
| 4013 | try self.asmMemory( | 4166 | try self.asmMemory( |
| 4014 | mir_tag, | 4167 | mir_tag, |
| 4015 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), | 4168 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), |
| ... | @@ -4272,20 +4425,26 @@ fn genMulDivBinOp( | ... | @@ -4272,20 +4425,26 @@ fn genMulDivBinOp( |
| 4272 | self: *Self, | 4425 | self: *Self, |
| 4273 | tag: Air.Inst.Tag, | 4426 | tag: Air.Inst.Tag, |
| 4274 | maybe_inst: ?Air.Inst.Index, | 4427 | maybe_inst: ?Air.Inst.Index, |
| 4275 | ty: Type, | 4428 | dst_ty: Type, |
| | 4429 | src_ty: Type, |
| 4276 | lhs: MCValue, | 4430 | lhs: MCValue, |
| 4277 | rhs: MCValue, | 4431 | rhs: MCValue, |
| 4278 | ) !MCValue { | 4432 | ) !MCValue { |
| 4279 | if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) { | 4433 | if (dst_ty.zigTypeTag() == .Vector or dst_ty.zigTypeTag() == .Float) { |
| 4280 | return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()}); | 4434 | return self.fail("TODO implement genMulDivBinOp for {}", .{dst_ty.fmtDebug()}); |
| 4281 | } | | |
| 4282 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | | |
| 4283 | if (abi_size > 8) { | | |
| 4284 | return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()}); | | |
| 4285 | } | | |
| 4286 | if (tag == .div_float) { | | |
| 4287 | return self.fail("TODO implement genMulDivBinOp for div_float", .{}); | | |
| 4288 | } | 4435 | } |
| | 4436 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| | 4437 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| | 4438 | if (switch (tag) { |
| | 4439 | else => unreachable, |
| | 4440 | .mul, .mulwrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2, |
| | 4441 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size, |
| | 4442 | } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{ |
| | 4443 | src_ty.fmt(self.bin_file.options.module.?), |
| | 4444 | dst_ty.fmt(self.bin_file.options.module.?), |
| | 4445 | }); |
| | 4446 | const ty = if (dst_abi_size <= 8) dst_ty else src_ty; |
| | 4447 | const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size; |
| 4289 | | 4448 | |
| 4290 | assert(self.register_manager.isRegFree(.rax)); | 4449 | assert(self.register_manager.isRegFree(.rax)); |
| 4291 | assert(self.register_manager.isRegFree(.rdx)); | 4450 | assert(self.register_manager.isRegFree(.rdx)); |
| ... | @@ -4293,9 +4452,7 @@ fn genMulDivBinOp( | ... | @@ -4293,9 +4452,7 @@ fn genMulDivBinOp( |
| 4293 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); | 4452 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| 4294 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); | 4453 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 4295 | | 4454 | |
| 4296 | const int_info = ty.intInfo(self.target.*); | 4455 | const signedness = ty.intInfo(self.target.*).signedness; |
| 4297 | const signedness = int_info.signedness; | | |
| 4298 | | | |
| 4299 | switch (tag) { | 4456 | switch (tag) { |
| 4300 | .mul, | 4457 | .mul, |
| 4301 | .mulwrap, | 4458 | .mulwrap, |
| ... | @@ -4303,11 +4460,12 @@ fn genMulDivBinOp( | ... | @@ -4303,11 +4460,12 @@ fn genMulDivBinOp( |
| 4303 | .div_trunc, | 4460 | .div_trunc, |
| 4304 | .div_exact, | 4461 | .div_exact, |
| 4305 | => { | 4462 | => { |
| 4306 | const track_inst_rax: ?Air.Inst.Index = switch (tag) { | 4463 | const track_inst_rax = switch (tag) { |
| 4307 | .mul, .mulwrap, .div_exact, .div_trunc => maybe_inst, | 4464 | .mul, .mulwrap => if (dst_abi_size <= 8) maybe_inst else null, |
| | 4465 | .div_exact, .div_trunc => maybe_inst, |
| 4308 | else => null, | 4466 | else => null, |
| 4309 | }; | 4467 | }; |
| 4310 | const track_inst_rdx: ?Air.Inst.Index = switch (tag) { | 4468 | const track_inst_rdx = switch (tag) { |
| 4311 | .rem => maybe_inst, | 4469 | .rem => maybe_inst, |
| 4312 | else => null, | 4470 | else => null, |
| 4313 | }; | 4471 | }; |
| ... | @@ -4327,13 +4485,24 @@ fn genMulDivBinOp( | ... | @@ -4327,13 +4485,24 @@ fn genMulDivBinOp( |
| 4327 | }, | 4485 | }, |
| 4328 | }; | 4486 | }; |
| 4329 | | 4487 | |
| 4330 | try self.genIntMulDivOpMir(mir_tag, ty, .signed, lhs, rhs); | 4488 | try self.genIntMulDivOpMir(mir_tag, ty, lhs, rhs); |
| 4331 | | 4489 | |
| 4332 | return .{ .register = registerAlias(switch (tag) { | 4490 | if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) { |
| 4333 | .mul, .mulwrap, .div_trunc, .div_exact => .rax, | 4491 | .mul, .mulwrap, .div_trunc, .div_exact => .rax, |
| 4334 | .rem => .rdx, | 4492 | .rem => .rdx, |
| 4335 | else => unreachable, | 4493 | else => unreachable, |
| 4336 | }, abi_size) }; | 4494 | }, dst_abi_size) }; |
| | 4495 | |
| | 4496 | const dst_mcv = try self.allocRegOrMemAdvanced(dst_ty, maybe_inst, false); |
| | 4497 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ |
| | 4498 | .base = .rbp, |
| | 4499 | .disp = 0 - dst_mcv.stack_offset, |
| | 4500 | }), .rax); |
| | 4501 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ |
| | 4502 | .base = .rbp, |
| | 4503 | .disp = 8 - dst_mcv.stack_offset, |
| | 4504 | }), .rdx); |
| | 4505 | return dst_mcv; |
| 4337 | }, | 4506 | }, |
| 4338 | | 4507 | |
| 4339 | .mod => { | 4508 | .mod => { |
| ... | @@ -4356,7 +4525,7 @@ fn genMulDivBinOp( | ... | @@ -4356,7 +4525,7 @@ fn genMulDivBinOp( |
| 4356 | return result; | 4525 | return result; |
| 4357 | }, | 4526 | }, |
| 4358 | .unsigned => { | 4527 | .unsigned => { |
| 4359 | try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs); | 4528 | try self.genIntMulDivOpMir(.div, ty, lhs, rhs); |
| 4360 | return .{ .register = registerAlias(.rdx, abi_size) }; | 4529 | return .{ .register = registerAlias(.rdx, abi_size) }; |
| 4361 | }, | 4530 | }, |
| 4362 | } | 4531 | } |
| ... | @@ -4395,18 +4564,13 @@ fn genMulDivBinOp( | ... | @@ -4395,18 +4564,13 @@ fn genMulDivBinOp( |
| 4395 | }; | 4564 | }; |
| 4396 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 4565 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 4397 | | 4566 | |
| 4398 | const result: MCValue = result: { | 4567 | switch (signedness) { |
| 4399 | switch (signedness) { | 4568 | .signed => return try self.genInlineIntDivFloor(ty, lhs, actual_rhs), |
| 4400 | .signed => break :result try self.genInlineIntDivFloor(ty, lhs, actual_rhs), | 4569 | .unsigned => { |
| 4401 | .unsigned => { | 4570 | try self.genIntMulDivOpMir(.div, ty, lhs, actual_rhs); |
| 4402 | try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, actual_rhs); | 4571 | return .{ .register = registerAlias(.rax, abi_size) }; |
| 4403 | break :result MCValue{ | 4572 | }, |
| 4404 | .register = registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))), | 4573 | } |
| 4405 | }; | | |
| 4406 | }, | | |
| 4407 | } | | |
| 4408 | }; | | |
| 4409 | return result; | | |
| 4410 | }, | 4574 | }, |
| 4411 | | 4575 | |
| 4412 | else => unreachable, | 4576 | else => unreachable, |
| ... | @@ -4454,7 +4618,7 @@ fn genBinOp( | ... | @@ -4454,7 +4618,7 @@ fn genBinOp( |
| 4454 | | 4618 | |
| 4455 | else => false, | 4619 | else => false, |
| 4456 | }; | 4620 | }; |
| 4457 | const needs_reg_dst = switch (tag) { | 4621 | const dst_mem_ok = switch (tag) { |
| 4458 | .add, | 4622 | .add, |
| 4459 | .addwrap, | 4623 | .addwrap, |
| 4460 | .sub, | 4624 | .sub, |
| ... | @@ -4464,9 +4628,9 @@ fn genBinOp( | ... | @@ -4464,9 +4628,9 @@ fn genBinOp( |
| 4464 | .div_exact, | 4628 | .div_exact, |
| 4465 | .div_trunc, | 4629 | .div_trunc, |
| 4466 | .div_floor, | 4630 | .div_floor, |
| 4467 | => lhs_ty.isRuntimeFloat(), | 4631 | => !lhs_ty.isRuntimeFloat(), |
| 4468 | | 4632 | |
| 4469 | else => false, | 4633 | else => true, |
| 4470 | }; | 4634 | }; |
| 4471 | | 4635 | |
| 4472 | const lhs_lock: ?RegisterLock = switch (lhs) { | 4636 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| ... | @@ -4482,18 +4646,21 @@ fn genBinOp( | ... | @@ -4482,18 +4646,21 @@ fn genBinOp( |
| 4482 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 4646 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 4483 | | 4647 | |
| 4484 | var flipped: bool = false; | 4648 | var flipped: bool = false; |
| 4485 | const dst_mcv: MCValue = blk: { | 4649 | const dst_mcv: MCValue = dst: { |
| 4486 | if (maybe_inst) |inst| { | 4650 | if (maybe_inst) |inst| { |
| 4487 | if ((!needs_reg_dst or lhs.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs)) { | 4651 | if ((dst_mem_ok or lhs.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs)) { |
| 4488 | break :blk lhs; | 4652 | break :dst lhs; |
| 4489 | } | 4653 | } |
| 4490 | if (is_commutative and (!needs_reg_dst or rhs.isRegister()) and self.reuseOperand(inst, rhs_air, 1, rhs)) { | 4654 | if (is_commutative and (dst_mem_ok or rhs.isRegister()) and |
| | 4655 | self.reuseOperand(inst, rhs_air, 1, rhs)) |
| | 4656 | { |
| 4491 | flipped = true; | 4657 | flipped = true; |
| 4492 | break :blk rhs; | 4658 | break :dst rhs; |
| 4493 | } | 4659 | } |
| 4494 | break :blk try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs); | | |
| 4495 | } | 4660 | } |
| 4496 | break :blk MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) }; | 4661 | const dst_mcv = try self.allocRegOrMemAdvanced(lhs_ty, maybe_inst, true); |
| | 4662 | try self.setRegOrMem(lhs_ty, dst_mcv, lhs); |
| | 4663 | break :dst dst_mcv; |
| 4497 | }; | 4664 | }; |
| 4498 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { | 4665 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 4499 | .register => |reg| self.register_manager.lockReg(reg), | 4666 | .register => |reg| self.register_manager.lockReg(reg), |
| ... | @@ -4501,17 +4668,7 @@ fn genBinOp( | ... | @@ -4501,17 +4668,7 @@ fn genBinOp( |
| 4501 | }; | 4668 | }; |
| 4502 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); | 4669 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 4503 | | 4670 | |
| 4504 | const src_mcv: MCValue = blk: { | 4671 | const src_mcv = if (flipped) lhs else rhs; |
| 4505 | const mcv = if (flipped) lhs else rhs; | | |
| 4506 | if (mcv.isRegister() or mcv.isMemory()) break :blk mcv; | | |
| 4507 | break :blk MCValue{ .register = try self.copyToTmpRegister(rhs_ty, mcv) }; | | |
| 4508 | }; | | |
| 4509 | const src_mcv_lock: ?RegisterLock = switch (src_mcv) { | | |
| 4510 | .register => |reg| self.register_manager.lockReg(reg), | | |
| 4511 | else => null, | | |
| 4512 | }; | | |
| 4513 | defer if (src_mcv_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 4514 | | | |
| 4515 | switch (tag) { | 4672 | switch (tag) { |
| 4516 | .add, | 4673 | .add, |
| 4517 | .addwrap, | 4674 | .addwrap, |
| ... | @@ -4573,14 +4730,18 @@ fn genBinOp( | ... | @@ -4573,14 +4730,18 @@ fn genBinOp( |
| 4573 | .ptr_add, | 4730 | .ptr_add, |
| 4574 | .ptr_sub, | 4731 | .ptr_sub, |
| 4575 | => { | 4732 | => { |
| 4576 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 4733 | const tmp_reg = try self.copyToTmpRegister(rhs_ty, src_mcv); |
| | 4734 | const tmp_mcv = MCValue{ .register = tmp_reg }; |
| | 4735 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| | 4736 | defer self.register_manager.unlockReg(tmp_lock); |
| | 4737 | |
| | 4738 | const elem_size = lhs_ty.elemType2().abiSize(self.target.*); |
| | 4739 | try self.genIntMulComplexOpMir(rhs_ty, tmp_mcv, .{ .immediate = elem_size }); |
| | 4740 | try self.genBinOpMir(switch (tag) { |
| 4577 | .ptr_add => .add, | 4741 | .ptr_add => .add, |
| 4578 | .ptr_sub => .sub, | 4742 | .ptr_sub => .sub, |
| 4579 | else => unreachable, | 4743 | else => unreachable, |
| 4580 | }; | 4744 | }, lhs_ty, dst_mcv, tmp_mcv); |
| 4581 | const elem_size = lhs_ty.elemType2().abiSize(self.target.*); | | |
| 4582 | try self.genIntMulComplexOpMir(rhs_ty, src_mcv, .{ .immediate = elem_size }); | | |
| 4583 | try self.genBinOpMir(mir_tag, lhs_ty, dst_mcv, src_mcv); | | |
| 4584 | }, | 4745 | }, |
| 4585 | | 4746 | |
| 4586 | .bool_or, | 4747 | .bool_or, |
| ... | @@ -4657,16 +4818,8 @@ fn genBinOp( | ... | @@ -4657,16 +4818,8 @@ fn genBinOp( |
| 4657 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); | 4818 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); |
| 4658 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | 4819 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 4659 | defer self.register_manager.unlockReg(addr_reg_lock); | 4820 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 4660 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mat_src_mcv); | | |
| 4661 | | | |
| 4662 | // To get the actual address of the value we want to modify we | | |
| 4663 | // we have to go through the GOT | | |
| 4664 | try self.asmRegisterMemory( | | |
| 4665 | .mov, | | |
| 4666 | addr_reg, | | |
| 4667 | Memory.sib(.qword, .{ .base = addr_reg }), | | |
| 4668 | ); | | |
| 4669 | | 4821 | |
| | 4822 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mat_src_mcv); |
| 4670 | try self.asmCmovccRegisterMemory( | 4823 | try self.asmCmovccRegisterMemory( |
| 4671 | registerAlias(tmp_reg, abi_size), | 4824 | registerAlias(tmp_reg, abi_size), |
| 4672 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), | 4825 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), |
| ... | @@ -4706,6 +4859,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s | ... | @@ -4706,6 +4859,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4706 | .eflags => unreachable, | 4859 | .eflags => unreachable, |
| 4707 | .register_overflow => unreachable, | 4860 | .register_overflow => unreachable, |
| 4708 | .register => |dst_reg| { | 4861 | .register => |dst_reg| { |
| | 4862 | const dst_alias = registerAlias(dst_reg, abi_size); |
| 4709 | switch (src_mcv) { | 4863 | switch (src_mcv) { |
| 4710 | .none => unreachable, | 4864 | .none => unreachable, |
| 4711 | .undef => unreachable, | 4865 | .undef => unreachable, |
| ... | @@ -4728,41 +4882,47 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s | ... | @@ -4728,41 +4882,47 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4728 | }, | 4882 | }, |
| 4729 | else => try self.asmRegisterRegister( | 4883 | else => try self.asmRegisterRegister( |
| 4730 | mir_tag, | 4884 | mir_tag, |
| 4731 | registerAlias(dst_reg, abi_size), | 4885 | dst_alias, |
| 4732 | registerAlias(src_reg, abi_size), | 4886 | registerAlias(src_reg, abi_size), |
| 4733 | ), | 4887 | ), |
| 4734 | }, | 4888 | }, |
| 4735 | .immediate => |imm| { | 4889 | .immediate => |imm| { |
| 4736 | switch (self.regBitSize(ty)) { | 4890 | switch (self.regBitSize(ty)) { |
| 4737 | 8, 16, 32 => { | 4891 | 8 => try self.asmRegisterImmediate( |
| 4738 | try self.asmRegisterImmediate( | 4892 | mir_tag, |
| 4739 | mir_tag, | 4893 | dst_alias, |
| 4740 | registerAlias(dst_reg, abi_size), | 4894 | if (math.cast(i8, @bitCast(i64, imm))) |small| |
| | 4895 | Immediate.s(small) |
| | 4896 | else |
| | 4897 | Immediate.u(@intCast(u8, imm)), |
| | 4898 | ), |
| | 4899 | 16 => try self.asmRegisterImmediate( |
| | 4900 | mir_tag, |
| | 4901 | dst_alias, |
| | 4902 | if (math.cast(i16, @bitCast(i64, imm))) |small| |
| | 4903 | Immediate.s(small) |
| | 4904 | else |
| | 4905 | Immediate.u(@intCast(u16, imm)), |
| | 4906 | ), |
| | 4907 | 32 => try self.asmRegisterImmediate( |
| | 4908 | mir_tag, |
| | 4909 | dst_alias, |
| | 4910 | if (math.cast(i32, @bitCast(i64, imm))) |small| |
| | 4911 | Immediate.s(small) |
| | 4912 | else |
| 4741 | Immediate.u(@intCast(u32, imm)), | 4913 | Immediate.u(@intCast(u32, imm)), |
| 4742 | ); | 4914 | ), |
| 4743 | }, | 4915 | 64 => if (math.cast(i32, @bitCast(i64, imm))) |small| |
| 4744 | 64 => { | 4916 | try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small)) |
| 4745 | if (math.cast(i32, @bitCast(i64, imm))) |small| { | 4917 | else |
| 4746 | try self.asmRegisterImmediate( | 4918 | try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias( |
| 4747 | mir_tag, | 4919 | try self.copyToTmpRegister(ty, src_mcv), |
| 4748 | registerAlias(dst_reg, abi_size), | 4920 | abi_size, |
| 4749 | Immediate.s(small), | 4921 | )), |
| 4750 | ); | 4922 | else => unreachable, |
| 4751 | } else { | | |
| 4752 | try self.asmRegisterRegister( | | |
| 4753 | mir_tag, | | |
| 4754 | registerAlias(dst_reg, abi_size), | | |
| 4755 | registerAlias(try self.copyToTmpRegister(ty, src_mcv), abi_size), | | |
| 4756 | ); | | |
| 4757 | } | | |
| 4758 | }, | | |
| 4759 | else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}), | | |
| 4760 | } | 4923 | } |
| 4761 | }, | 4924 | }, |
| 4762 | .memory, | 4925 | .memory, .linker_load, .eflags => { |
| 4763 | .linker_load, | | |
| 4764 | .eflags, | | |
| 4765 | => { | | |
| 4766 | assert(abi_size <= 8); | 4926 | assert(abi_size <= 8); |
| 4767 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); | 4927 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 4768 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); | 4928 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | @@ -4779,7 +4939,27 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s | ... | @@ -4779,7 +4939,27 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4779 | }, | 4939 | }, |
| 4780 | } | 4940 | } |
| 4781 | }, | 4941 | }, |
| 4782 | .ptr_stack_offset, .stack_offset => |dst_off| { | 4942 | .memory, .linker_load, .stack_offset => { |
| | 4943 | const dst: ?struct { |
| | 4944 | addr_reg: Register, |
| | 4945 | addr_lock: RegisterLock, |
| | 4946 | } = switch (dst_mcv) { |
| | 4947 | else => unreachable, |
| | 4948 | .memory, .linker_load => dst: { |
| | 4949 | const dst_addr_reg = try self.register_manager.allocReg(null, gp); |
| | 4950 | const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg); |
| | 4951 | errdefer self.register_manager.unlockReg(dst_addr_lock); |
| | 4952 | |
| | 4953 | try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_mcv); |
| | 4954 | break :dst .{ |
| | 4955 | .addr_reg = dst_addr_reg, |
| | 4956 | .addr_lock = dst_addr_lock, |
| | 4957 | }; |
| | 4958 | }, |
| | 4959 | .stack_offset => null, |
| | 4960 | }; |
| | 4961 | defer if (dst) |lock| self.register_manager.unlockReg(lock.addr_lock); |
| | 4962 | |
| 4783 | const src: ?struct { | 4963 | const src: ?struct { |
| 4784 | limb_reg: Register, | 4964 | limb_reg: Register, |
| 4785 | limb_lock: RegisterLock, | 4965 | limb_lock: RegisterLock, |
| ... | @@ -4787,7 +4967,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s | ... | @@ -4787,7 +4967,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4787 | addr_lock: RegisterLock, | 4967 | addr_lock: RegisterLock, |
| 4788 | } = switch (src_mcv) { | 4968 | } = switch (src_mcv) { |
| 4789 | else => null, | 4969 | else => null, |
| 4790 | .memory, .linker_load => addr: { | 4970 | .memory, .linker_load => src: { |
| 4791 | const src_limb_reg = try self.register_manager.allocReg(null, gp); | 4971 | const src_limb_reg = try self.register_manager.allocReg(null, gp); |
| 4792 | const src_limb_lock = self.register_manager.lockRegAssumeUnused(src_limb_reg); | 4972 | const src_limb_lock = self.register_manager.lockRegAssumeUnused(src_limb_reg); |
| 4793 | errdefer self.register_manager.unlockReg(src_limb_lock); | 4973 | errdefer self.register_manager.unlockReg(src_limb_lock); |
| ... | @@ -4797,15 +4977,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s | ... | @@ -4797,15 +4977,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4797 | errdefer self.register_manager.unlockReg(src_addr_lock); | 4977 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 4798 | | 4978 | |
| 4799 | try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_mcv); | 4979 | try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_mcv); |
| 4800 | // To get the actual address of the value we want to modify we | 4980 | break :src .{ |
| 4801 | // we have to go through the GOT | | |
| 4802 | try self.asmRegisterMemory( | | |
| 4803 | .mov, | | |
| 4804 | src_addr_reg, | | |
| 4805 | Memory.sib(.qword, .{ .base = src_addr_reg }), | | |
| 4806 | ); | | |
| 4807 | | | |
| 4808 | break :addr .{ | | |
| 4809 | .addr_reg = src_addr_reg, | 4981 | .addr_reg = src_addr_reg, |
| 4810 | .addr_lock = src_addr_lock, | 4982 | .addr_lock = src_addr_lock, |
| 4811 | .limb_reg = src_limb_reg, | 4983 | .limb_reg = src_limb_reg, |
| ... | @@ -4831,7 +5003,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s | ... | @@ -4831,7 +5003,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4831 | 0 => mir_tag, | 5003 | 0 => mir_tag, |
| 4832 | else => switch (mir_tag) { | 5004 | else => switch (mir_tag) { |
| 4833 | .add => .adc, | 5005 | .add => .adc, |
| 4834 | .sub => .sbb, | 5006 | .sub, .cmp => .sbb, |
| 4835 | .@"or", .@"and", .xor => mir_tag, | 5007 | .@"or", .@"and", .xor => mir_tag, |
| 4836 | else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{ | 5008 | else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{ |
| 4837 | @tagName(mir_tag), | 5009 | @tagName(mir_tag), |
| ... | @@ -4840,7 +5012,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s | ... | @@ -4840,7 +5012,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4840 | }; | 5012 | }; |
| 4841 | const dst_limb_mem = Memory.sib( | 5013 | const dst_limb_mem = Memory.sib( |
| 4842 | Memory.PtrSize.fromSize(limb_abi_size), | 5014 | Memory.PtrSize.fromSize(limb_abi_size), |
| 4843 | .{ .base = .rbp, .disp = off - dst_off }, | 5015 | switch (dst_mcv) { |
| | 5016 | else => unreachable, |
| | 5017 | .stack_offset => |dst_off| .{ |
| | 5018 | .base = .rbp, |
| | 5019 | .disp = off - dst_off, |
| | 5020 | }, |
| | 5021 | .memory, .linker_load => .{ .base = dst.?.addr_reg, .disp = off }, |
| | 5022 | }, |
| 4844 | ); | 5023 | ); |
| 4845 | switch (src_mcv) { | 5024 | switch (src_mcv) { |
| 4846 | .none => unreachable, | 5025 | .none => unreachable, |
| ... | @@ -4861,34 +5040,45 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s | ... | @@ -4861,34 +5040,45 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4861 | .unsigned => 0, | 5040 | .unsigned => 0, |
| 4862 | }; | 5041 | }; |
| 4863 | switch (self.regBitSize(limb_ty)) { | 5042 | switch (self.regBitSize(limb_ty)) { |
| 4864 | 8, 16, 32 => { | 5043 | 8 => try self.asmMemoryImmediate( |
| | 5044 | mir_limb_tag, |
| | 5045 | dst_limb_mem, |
| | 5046 | if (math.cast(i8, @bitCast(i64, imm))) |small| |
| | 5047 | Immediate.s(small) |
| | 5048 | else |
| | 5049 | Immediate.u(@intCast(u8, imm)), |
| | 5050 | ), |
| | 5051 | 16 => try self.asmMemoryImmediate( |
| | 5052 | mir_limb_tag, |
| | 5053 | dst_limb_mem, |
| | 5054 | if (math.cast(i16, @bitCast(i64, imm))) |small| |
| | 5055 | Immediate.s(small) |
| | 5056 | else |
| | 5057 | Immediate.u(@intCast(u16, imm)), |
| | 5058 | ), |
| | 5059 | 32 => try self.asmMemoryImmediate( |
| | 5060 | mir_limb_tag, |
| | 5061 | dst_limb_mem, |
| | 5062 | if (math.cast(i32, @bitCast(i64, imm))) |small| |
| | 5063 | Immediate.s(small) |
| | 5064 | else |
| | 5065 | Immediate.u(@intCast(u32, imm)), |
| | 5066 | ), |
| | 5067 | 64 => if (math.cast(i32, @bitCast(i64, imm))) |small| |
| 4865 | try self.asmMemoryImmediate( | 5068 | try self.asmMemoryImmediate( |
| 4866 | mir_limb_tag, | 5069 | mir_limb_tag, |
| 4867 | dst_limb_mem, | 5070 | dst_limb_mem, |
| 4868 | if (math.cast(i32, @bitCast(i64, imm))) |small| | 5071 | Immediate.s(small), |
| 4869 | Immediate.s(small) | 5072 | ) |
| 4870 | else | 5073 | else |
| 4871 | Immediate.u(@intCast(u32, imm)), | 5074 | try self.asmMemoryRegister( |
| 4872 | ); | 5075 | mir_limb_tag, |
| 4873 | }, | 5076 | dst_limb_mem, |
| 4874 | 64 => { | 5077 | registerAlias( |
| 4875 | if (math.cast(i32, @bitCast(i64, imm))) |small| { | 5078 | try self.copyToTmpRegister(limb_ty, .{ .immediate = imm }), |
| 4876 | try self.asmMemoryImmediate( | 5079 | limb_abi_size, |
| 4877 | mir_limb_tag, | 5080 | ), |
| 4878 | dst_limb_mem, | 5081 | ), |
| 4879 | Immediate.s(small), | | |
| 4880 | ); | | |
| 4881 | } else { | | |
| 4882 | try self.asmMemoryRegister( | | |
| 4883 | mir_limb_tag, | | |
| 4884 | dst_limb_mem, | | |
| 4885 | registerAlias( | | |
| 4886 | try self.copyToTmpRegister(limb_ty, .{ .immediate = imm }), | | |
| 4887 | limb_abi_size, | | |
| 4888 | ), | | |
| 4889 | ); | | |
| 4890 | } | | |
| 4891 | }, | | |
| 4892 | else => unreachable, | 5082 | else => unreachable, |
| 4893 | } | 5083 | } |
| 4894 | }, | 5084 | }, |
| ... | @@ -4930,12 +5120,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s | ... | @@ -4930,12 +5120,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4930 | } | 5120 | } |
| 4931 | } | 5121 | } |
| 4932 | }, | 5122 | }, |
| 4933 | .memory => { | 5123 | .ptr_stack_offset => unreachable, |
| 4934 | return self.fail("TODO implement x86 genBinOpMir destination memory", .{}); | | |
| 4935 | }, | | |
| 4936 | .linker_load => { | | |
| 4937 | return self.fail("TODO implement x86 genBinOpMir destination symbol at index", .{}); | | |
| 4938 | }, | | |
| 4939 | } | 5124 | } |
| 4940 | } | 5125 | } |
| 4941 | | 5126 | |
| ... | @@ -5191,7 +5376,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -5191,7 +5376,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5191 | else => unreachable, | 5376 | else => unreachable, |
| 5192 | }; | 5377 | }; |
| 5193 | | 5378 | |
| 5194 | var info = try self.resolveCallingConventionValues(fn_ty); | 5379 | var info = try self.resolveCallingConventionValues(fn_ty, args[fn_ty.fnParamLen()..]); |
| 5195 | defer info.deinit(self); | 5380 | defer info.deinit(self); |
| 5196 | | 5381 | |
| 5197 | try self.spillEflagsIfOccupied(); | 5382 | try self.spillEflagsIfOccupied(); |
| ... | @@ -5280,8 +5465,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -5280,8 +5465,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5280 | | 5465 | |
| 5281 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | 5466 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 5282 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); | 5467 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 5283 | const atom = elf_file.getAtom(atom_index); | 5468 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); |
| 5284 | const got_addr = atom.getOffsetTableAddress(elf_file); | | |
| 5285 | try self.asmMemory(.call, Memory.sib(.qword, .{ | 5469 | try self.asmMemory(.call, Memory.sib(.qword, .{ |
| 5286 | .base = .ds, | 5470 | .base = .ds, |
| 5287 | .disp = @intCast(i32, got_addr), | 5471 | .disp = @intCast(i32, got_addr), |
| ... | @@ -5289,22 +5473,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -5289,22 +5473,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5289 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | 5473 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 5290 | const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl); | 5474 | const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl); |
| 5291 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | 5475 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 5292 | try self.genSetReg(Type.initTag(.usize), .rax, .{ | 5476 | try self.genSetReg(Type.usize, .rax, .{ .linker_load = .{ |
| 5293 | .linker_load = .{ | 5477 | .type = .got, |
| 5294 | .type = .got, | 5478 | .sym_index = sym_index, |
| 5295 | .sym_index = sym_index, | 5479 | } }); |
| 5296 | }, | | |
| 5297 | }); | | |
| 5298 | try self.asmRegister(.call, .rax); | 5480 | try self.asmRegister(.call, .rax); |
| 5299 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | 5481 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 5300 | const atom_index = try macho_file.getOrCreateAtomForDecl(func.owner_decl); | 5482 | const atom_index = try macho_file.getOrCreateAtomForDecl(func.owner_decl); |
| 5301 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; | 5483 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 5302 | try self.genSetReg(Type.initTag(.usize), .rax, .{ | 5484 | try self.genSetReg(Type.usize, .rax, .{ .linker_load = .{ |
| 5303 | .linker_load = .{ | 5485 | .type = .got, |
| 5304 | .type = .got, | 5486 | .sym_index = sym_index, |
| 5305 | .sym_index = sym_index, | 5487 | } }); |
| 5306 | }, | | |
| 5307 | }); | | |
| 5308 | try self.asmRegister(.call, .rax); | 5488 | try self.asmRegister(.call, .rax); |
| 5309 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | 5489 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { |
| 5310 | const decl_block_index = try p9.seeDecl(func.owner_decl); | 5490 | const decl_block_index = try p9.seeDecl(func.owner_decl); |
| ... | @@ -5325,7 +5505,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -5325,7 +5505,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5325 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); | 5505 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); |
| 5326 | if (self.bin_file.cast(link.File.Coff)) |coff_file| { | 5506 | if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 5327 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); | 5507 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); |
| 5328 | try self.genSetReg(Type.initTag(.usize), .rax, .{ | 5508 | try self.genSetReg(Type.usize, .rax, .{ |
| 5329 | .linker_load = .{ | 5509 | .linker_load = .{ |
| 5330 | .type = .import, | 5510 | .type = .import, |
| 5331 | .sym_index = sym_index, | 5511 | .sym_index = sym_index, |
| ... | @@ -5353,7 +5533,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -5353,7 +5533,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5353 | } else { | 5533 | } else { |
| 5354 | assert(ty.zigTypeTag() == .Pointer); | 5534 | assert(ty.zigTypeTag() == .Pointer); |
| 5355 | const mcv = try self.resolveInst(callee); | 5535 | const mcv = try self.resolveInst(callee); |
| 5356 | try self.genSetReg(Type.initTag(.usize), .rax, mcv); | 5536 | try self.genSetReg(Type.usize, .rax, mcv); |
| 5357 | try self.asmRegister(.call, .rax); | 5537 | try self.asmRegister(.call, .rax); |
| 5358 | } | 5538 | } |
| 5359 | | 5539 | |
| ... | @@ -5457,79 +5637,61 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5457,79 +5637,61 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 5457 | | 5637 | |
| 5458 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 5638 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 5459 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 5639 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 5640 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 5641 | const ty = self.air.typeOf(bin_op.lhs); |
| | 5642 | const ty_abi_size = ty.abiSize(self.target.*); |
| | 5643 | const can_reuse = ty_abi_size <= 8; |
| 5460 | | 5644 | |
| 5461 | if (self.liveness.isUnused(inst)) { | 5645 | try self.spillEflagsIfOccupied(); |
| 5462 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 5646 | self.eflags_inst = inst; |
| 5463 | } | | |
| 5464 | | | |
| 5465 | const ty = self.air.typeOf(bin_op.lhs); | | |
| 5466 | const abi_size = ty.abiSize(self.target.*); | | |
| 5467 | if (abi_size > 8) return self.fail("TODO implement cmp for large values", .{}); | | |
| 5468 | | | |
| 5469 | const signedness: std.builtin.Signedness = blk: { | | |
| 5470 | // For non-int types, we treat the values as unsigned | | |
| 5471 | if (ty.zigTypeTag() != .Int) break :blk .unsigned; | | |
| 5472 | | | |
| 5473 | // Otherwise, we take the signedness of the actual int | | |
| 5474 | break :blk ty.intInfo(self.target.*).signedness; | | |
| 5475 | }; | | |
| 5476 | | | |
| 5477 | try self.spillEflagsIfOccupied(); | | |
| 5478 | self.eflags_inst = inst; | | |
| 5479 | | 5647 | |
| 5480 | const result: MCValue = result: { | 5648 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 5481 | // There are 2 operands, destination and source. | 5649 | const lhs_lock = switch (lhs_mcv) { |
| 5482 | // Either one, but not both, can be a memory operand. | | |
| 5483 | // Source operand can be an immediate, 8 bits or 32 bits. | | |
| 5484 | // TODO look into reusing the operand | | |
| 5485 | const lhs = try self.resolveInst(bin_op.lhs); | | |
| 5486 | const lhs_lock: ?RegisterLock = switch (lhs) { | | |
| 5487 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 5650 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5488 | else => null, | 5651 | else => null, |
| 5489 | }; | 5652 | }; |
| 5490 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 5653 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 5491 | | 5654 | |
| 5492 | const dst_reg = try self.copyToTmpRegister(ty, lhs); | 5655 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 5493 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 5656 | const rhs_lock = switch (rhs_mcv) { |
| 5494 | defer self.register_manager.unlockReg(dst_reg_lock); | 5657 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5495 | | 5658 | else => null, |
| 5496 | const dst_mcv = MCValue{ .register = dst_reg }; | | |
| 5497 | | | |
| 5498 | const rhs_ty = self.air.typeOf(bin_op.rhs); | | |
| 5499 | // This instruction supports only signed 32-bit immediates at most. | | |
| 5500 | const src_mcv: MCValue = blk: { | | |
| 5501 | switch (rhs_ty.zigTypeTag()) { | | |
| 5502 | .Float => { | | |
| 5503 | const rhs = try self.resolveInst(bin_op.rhs); | | |
| 5504 | const rhs_lock: ?RegisterLock = switch (rhs) { | | |
| 5505 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 5506 | else => null, | | |
| 5507 | }; | | |
| 5508 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 5509 | const src_reg = try self.copyToTmpRegister(rhs_ty, rhs); | | |
| 5510 | break :blk MCValue{ .register = src_reg }; | | |
| 5511 | }, | | |
| 5512 | else => break :blk try self.limitImmediateType(bin_op.rhs, i32), | | |
| 5513 | } | | |
| 5514 | }; | 5659 | }; |
| 5515 | const src_lock: ?RegisterLock = switch (src_mcv) { | 5660 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 5661 | |
| | 5662 | const dst_mem_ok = !ty.isRuntimeFloat(); |
| | 5663 | var flipped = false; |
| | 5664 | const dst_mcv: MCValue = if (can_reuse and !lhs_mcv.isImmediate() and |
| | 5665 | (dst_mem_ok or lhs_mcv.isRegister()) and self.liveness.operandDies(inst, 0)) |
| | 5666 | lhs_mcv |
| | 5667 | else if (can_reuse and !rhs_mcv.isImmediate() and |
| | 5668 | (dst_mem_ok or rhs_mcv.isRegister()) and self.liveness.operandDies(inst, 1)) |
| | 5669 | dst: { |
| | 5670 | flipped = true; |
| | 5671 | break :dst rhs_mcv; |
| | 5672 | } else if (dst_mem_ok) dst: { |
| | 5673 | const dst_mcv = try self.allocTempRegOrMem(ty, true); |
| | 5674 | try self.setRegOrMem(ty, dst_mcv, lhs_mcv); |
| | 5675 | break :dst dst_mcv; |
| | 5676 | } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) }; |
| | 5677 | const dst_lock = switch (dst_mcv) { |
| 5516 | .register => |reg| self.register_manager.lockReg(reg), | 5678 | .register => |reg| self.register_manager.lockReg(reg), |
| 5517 | else => null, | 5679 | else => null, |
| 5518 | }; | 5680 | }; |
| 5519 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); | 5681 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5520 | | 5682 | |
| | 5683 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; |
| 5521 | try self.genBinOpMir(switch (ty.tag()) { | 5684 | try self.genBinOpMir(switch (ty.tag()) { |
| 5522 | else => .cmp, | 5685 | else => .cmp, |
| 5523 | .f32 => .ucomiss, | 5686 | .f32 => .ucomiss, |
| 5524 | .f64 => .ucomisd, | 5687 | .f64 => .ucomisd, |
| 5525 | }, ty, dst_mcv, src_mcv); | 5688 | }, ty, dst_mcv, src_mcv); |
| 5526 | | 5689 | |
| 5527 | break :result switch (signedness) { | 5690 | const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned; |
| 5528 | .signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) }, | 5691 | break :result .{ |
| 5529 | .unsigned => MCValue{ .eflags = Condition.fromCompareOperatorUnsigned(op) }, | 5692 | .eflags = Condition.fromCompareOperator(signedness, if (flipped) op.reverse() else op), |
| 5530 | }; | 5693 | }; |
| 5531 | }; | 5694 | }; |
| 5532 | | | |
| 5533 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 5695 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 5534 | } | 5696 | } |
| 5535 | | 5697 | |
| ... | @@ -5790,13 +5952,6 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC | ... | @@ -5790,13 +5952,6 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 5790 | | 5952 | |
| 5791 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv); | 5953 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv); |
| 5792 | | 5954 | |
| 5793 | // To get the actual address of the value we want to modify we have to go through the GOT | | |
| 5794 | try self.asmRegisterMemory( | | |
| 5795 | .mov, | | |
| 5796 | addr_reg, | | |
| 5797 | Memory.sib(.qword, .{ .base = addr_reg }), | | |
| 5798 | ); | | |
| 5799 | | | |
| 5800 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); | 5955 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); |
| 5801 | try self.asmMemoryImmediate(.cmp, Memory.sib( | 5956 | try self.asmMemoryImmediate(.cmp, Memory.sib( |
| 5802 | Memory.PtrSize.fromSize(some_abi_size), | 5957 | Memory.PtrSize.fromSize(some_abi_size), |
| ... | @@ -6681,6 +6836,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -6681,6 +6836,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 6681 | } | 6836 | } |
| 6682 | | 6837 | |
| 6683 | fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: InlineMemcpyOpts) InnerError!void { | 6838 | fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: InlineMemcpyOpts) InnerError!void { |
| | 6839 | const base_reg = opts.dest_stack_base orelse .rbp; |
| 6684 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 6840 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 6685 | switch (mcv) { | 6841 | switch (mcv) { |
| 6686 | .dead => unreachable, | 6842 | .dead => unreachable, |
| ... | @@ -6696,12 +6852,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -6696,12 +6852,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 6696 | 4 => 0xaaaaaaaa, | 6852 | 4 => 0xaaaaaaaa, |
| 6697 | else => unreachable, | 6853 | else => unreachable, |
| 6698 | }; | 6854 | }; |
| 6699 | return self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | 6855 | return self.asmMemoryImmediate(.mov, Memory.sib( |
| 6700 | .base = opts.dest_stack_base orelse .rbp, | 6856 | Memory.PtrSize.fromSize(abi_size), |
| 6701 | .disp = -stack_offset, | 6857 | .{ .base = base_reg, .disp = -stack_offset }, |
| 6702 | }), Immediate.u(value)); | 6858 | ), Immediate.u(value)); |
| 6703 | }, | 6859 | }, |
| 6704 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, opts), | 6860 | 8 => return self.genSetStack( |
| | 6861 | ty, |
| | 6862 | stack_offset, |
| | 6863 | .{ .immediate = 0xaaaaaaaaaaaaaaaa }, |
| | 6864 | opts, |
| | 6865 | ), |
| 6705 | else => |x| return self.genInlineMemset( | 6866 | else => |x| return self.genInlineMemset( |
| 6706 | .{ .stack_offset = stack_offset }, | 6867 | .{ .stack_offset = stack_offset }, |
| 6707 | .{ .immediate = 0xaa }, | 6868 | .{ .immediate = 0xaa }, |
| ... | @@ -6729,12 +6890,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -6729,12 +6890,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 6729 | .{}, | 6890 | .{}, |
| 6730 | ); | 6891 | ); |
| 6731 | }, | 6892 | }, |
| 6732 | .eflags => { | 6893 | .eflags => |cc| try self.asmSetccMemory( |
| 6733 | const reg = try self.copyToTmpRegister(ty, mcv); | 6894 | Memory.sib(.byte, .{ .base = base_reg, .disp = -stack_offset }), |
| 6734 | return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts); | 6895 | cc, |
| 6735 | }, | 6896 | ), |
| 6736 | .immediate => |x_big| { | 6897 | .immediate => |imm| { |
| 6737 | const base_reg = opts.dest_stack_base orelse .rbp; | | |
| 6738 | // TODO | 6898 | // TODO |
| 6739 | switch (abi_size) { | 6899 | switch (abi_size) { |
| 6740 | 0 => { | 6900 | 0 => { |
| ... | @@ -6742,13 +6902,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -6742,13 +6902,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 6742 | try self.asmMemoryImmediate(.mov, Memory.sib(.byte, .{ | 6902 | try self.asmMemoryImmediate(.mov, Memory.sib(.byte, .{ |
| 6743 | .base = base_reg, | 6903 | .base = base_reg, |
| 6744 | .disp = -stack_offset, | 6904 | .disp = -stack_offset, |
| 6745 | }), Immediate.u(@truncate(u8, x_big))); | 6905 | }), Immediate.u(@truncate(u8, imm))); |
| 6746 | }, | 6906 | }, |
| 6747 | 1, 2, 4 => { | 6907 | 1, 2, 4 => { |
| 6748 | const immediate = if (ty.isSignedInt()) | 6908 | const immediate = if (ty.isSignedInt()) |
| 6749 | Immediate.s(@truncate(i32, @bitCast(i64, x_big))) | 6909 | Immediate.s(@truncate(i32, @bitCast(i64, imm))) |
| 6750 | else | 6910 | else |
| 6751 | Immediate.u(@intCast(u32, x_big)); | 6911 | Immediate.u(@intCast(u32, imm)); |
| 6752 | try self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | 6912 | try self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| 6753 | .base = base_reg, | 6913 | .base = base_reg, |
| 6754 | .disp = -stack_offset, | 6914 | .disp = -stack_offset, |
| ... | @@ -6758,27 +6918,32 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -6758,27 +6918,32 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 6758 | else => { | 6918 | else => { |
| 6759 | // 64 bit write to memory would take two mov's anyways so we | 6919 | // 64 bit write to memory would take two mov's anyways so we |
| 6760 | // insted just use two 32 bit writes to avoid register allocation | 6920 | // insted just use two 32 bit writes to avoid register allocation |
| 6761 | var offset: i32 = 0; | 6921 | if (std.math.cast(i32, @bitCast(i64, imm))) |small| { |
| 6762 | while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate( | 6922 | try self.asmMemoryImmediate(.mov, Memory.sib( |
| 6763 | .mov, | 6923 | Memory.PtrSize.fromSize(abi_size), |
| 6764 | Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }), | 6924 | .{ .base = base_reg, .disp = -stack_offset }, |
| 6765 | if (ty.isSignedInt()) | 6925 | ), Immediate.s(small)); |
| 6766 | Immediate.s(@truncate( | 6926 | } else { |
| 6767 | i32, | 6927 | var offset: i32 = 0; |
| 6768 | @bitCast(i64, x_big) >> (math.cast(u6, offset * 8) orelse 63), | 6928 | while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate( |
| 6769 | )) | 6929 | .mov, |
| 6770 | else | 6930 | Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }), |
| 6771 | Immediate.u(@truncate( | 6931 | if (ty.isSignedInt()) |
| 6772 | u32, | 6932 | Immediate.s(@truncate( |
| 6773 | if (math.cast(u6, offset * 8)) |shift| x_big >> shift else 0, | 6933 | i32, |
| 6774 | )), | 6934 | @bitCast(i64, imm) >> (math.cast(u6, offset * 8) orelse 63), |
| 6775 | ); | 6935 | )) |
| | 6936 | else |
| | 6937 | Immediate.u(@truncate( |
| | 6938 | u32, |
| | 6939 | if (math.cast(u6, offset * 8)) |shift| imm >> shift else 0, |
| | 6940 | )), |
| | 6941 | ); |
| | 6942 | } |
| 6776 | }, | 6943 | }, |
| 6777 | } | 6944 | } |
| 6778 | }, | 6945 | }, |
| 6779 | .register => |reg| { | 6946 | .register => |reg| { |
| 6780 | const base_reg = opts.dest_stack_base orelse .rbp; | | |
| 6781 | | | |
| 6782 | switch (ty.zigTypeTag()) { | 6947 | switch (ty.zigTypeTag()) { |
| 6783 | .Float => { | 6948 | .Float => { |
| 6784 | if (intrinsicsAllowed(self.target.*, ty)) { | 6949 | if (intrinsicsAllowed(self.target.*, ty)) { |
| ... | @@ -6808,22 +6973,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -6808,22 +6973,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 6808 | }, | 6973 | }, |
| 6809 | } | 6974 | } |
| 6810 | }, | 6975 | }, |
| 6811 | .memory, .linker_load => { | 6976 | .memory, .linker_load, .stack_offset, .ptr_stack_offset => { |
| 6812 | if (abi_size <= 8) { | 6977 | switch (mcv) { |
| 6813 | const reg = try self.copyToTmpRegister(ty, mcv); | 6978 | else => unreachable, |
| 6814 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); | 6979 | .memory, .linker_load, .ptr_stack_offset => {}, |
| 6815 | } | 6980 | .stack_offset => |src_off| if (stack_offset == src_off) { |
| 6816 | | 6981 | // Copy stack variable to itself; nothing to do. |
| 6817 | try self.genInlineMemcpy(.{ .stack_offset = stack_offset }, mcv, .{ .immediate = abi_size }, opts); | 6982 | return; |
| 6818 | }, | 6983 | }, |
| 6819 | .ptr_stack_offset => { | | |
| 6820 | const reg = try self.copyToTmpRegister(ty, mcv); | | |
| 6821 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); | | |
| 6822 | }, | | |
| 6823 | .stack_offset => |off| { | | |
| 6824 | if (stack_offset == off) { | | |
| 6825 | // Copy stack variable to itself; nothing to do. | | |
| 6826 | return; | | |
| 6827 | } | 6984 | } |
| 6828 | | 6985 | |
| 6829 | if (abi_size <= 8) { | 6986 | if (abi_size <= 8) { |
| ... | @@ -7101,69 +7258,38 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -7101,69 +7258,38 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7101 | | 7258 | |
| 7102 | try self.asmRegisterRegister(.mov, registerAlias(reg, abi_size), registerAlias(src_reg, abi_size)); | 7259 | try self.asmRegisterRegister(.mov, registerAlias(reg, abi_size), registerAlias(src_reg, abi_size)); |
| 7103 | }, | 7260 | }, |
| 7104 | .linker_load => { | 7261 | .memory, .linker_load => switch (ty.zigTypeTag()) { |
| 7105 | switch (ty.zigTypeTag()) { | | |
| 7106 | .Float => { | | |
| 7107 | const base_reg = try self.register_manager.allocReg(null, gp); | | |
| 7108 | try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv); | | |
| 7109 | | | |
| 7110 | if (intrinsicsAllowed(self.target.*, ty)) { | | |
| 7111 | const tag: Mir.Inst.Tag = switch (ty.tag()) { | | |
| 7112 | .f32 => .movss, | | |
| 7113 | .f64 => .movsd, | | |
| 7114 | else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}), | | |
| 7115 | }; | | |
| 7116 | const ptr_size: Memory.PtrSize = switch (ty.tag()) { | | |
| 7117 | .f32 => .dword, | | |
| 7118 | .f64 => .qword, | | |
| 7119 | else => unreachable, | | |
| 7120 | }; | | |
| 7121 | return self.asmRegisterMemory( | | |
| 7122 | tag, | | |
| 7123 | reg.to128(), | | |
| 7124 | Memory.sib(ptr_size, .{ .base = base_reg.to64() }), | | |
| 7125 | ); | | |
| 7126 | } | | |
| 7127 | | | |
| 7128 | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); | | |
| 7129 | }, | | |
| 7130 | else => { | | |
| 7131 | try self.loadMemPtrIntoRegister(reg, Type.usize, mcv); | | |
| 7132 | try self.asmRegisterMemory( | | |
| 7133 | .mov, | | |
| 7134 | registerAlias(reg, abi_size), | | |
| 7135 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), | | |
| 7136 | ); | | |
| 7137 | }, | | |
| 7138 | } | | |
| 7139 | }, | | |
| 7140 | .memory => |x| switch (ty.zigTypeTag()) { | | |
| 7141 | .Float => { | 7262 | .Float => { |
| 7142 | const base_reg = try self.register_manager.allocReg(null, gp); | 7263 | const base_reg = try self.register_manager.allocReg(null, gp); |
| 7143 | try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv); | 7264 | try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv); |
| 7144 | | 7265 | |
| 7145 | if (intrinsicsAllowed(self.target.*, ty)) { | 7266 | if (intrinsicsAllowed(self.target.*, ty)) { |
| 7146 | const tag: Mir.Inst.Tag = switch (ty.tag()) { | | |
| 7147 | .f32 => .movss, | | |
| 7148 | .f64 => .movsd, | | |
| 7149 | else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}), | | |
| 7150 | }; | | |
| 7151 | const ptr_size: Memory.PtrSize = switch (ty.tag()) { | | |
| 7152 | .f32 => .dword, | | |
| 7153 | .f64 => .qword, | | |
| 7154 | else => unreachable, | | |
| 7155 | }; | | |
| 7156 | return self.asmRegisterMemory( | 7267 | return self.asmRegisterMemory( |
| 7157 | tag, | 7268 | switch (ty.tag()) { |
| | 7269 | .f32 => .movss, |
| | 7270 | .f64 => .movsd, |
| | 7271 | else => return self.fail("TODO genSetReg from memory for {}", .{ |
| | 7272 | ty.fmt(self.bin_file.options.module.?), |
| | 7273 | }), |
| | 7274 | }, |
| 7158 | reg.to128(), | 7275 | reg.to128(), |
| 7159 | Memory.sib(ptr_size, .{ .base = base_reg.to64() }), | 7276 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base_reg.to64() }), |
| 7160 | ); | 7277 | ); |
| 7161 | } | 7278 | } |
| 7162 | | 7279 | |
| 7163 | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); | 7280 | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); |
| 7164 | }, | 7281 | }, |
| 7165 | else => { | 7282 | else => switch (mcv) { |
| 7166 | if (x <= math.maxInt(i32)) { | 7283 | else => unreachable, |
| | 7284 | .linker_load => { |
| | 7285 | try self.loadMemPtrIntoRegister(reg, Type.usize, mcv); |
| | 7286 | try self.asmRegisterMemory( |
| | 7287 | .mov, |
| | 7288 | registerAlias(reg, abi_size), |
| | 7289 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), |
| | 7290 | ); |
| | 7291 | }, |
| | 7292 | .memory => |x| if (x <= math.maxInt(i32)) { |
| 7167 | try self.asmRegisterMemory( | 7293 | try self.asmRegisterMemory( |
| 7168 | .mov, | 7294 | .mov, |
| 7169 | registerAlias(reg, abi_size), | 7295 | registerAlias(reg, abi_size), |
| ... | @@ -7190,7 +7316,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -7190,7 +7316,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7190 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), | 7316 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), |
| 7191 | ); | 7317 | ); |
| 7192 | } | 7318 | } |
| 7193 | } | 7319 | }, |
| 7194 | }, | 7320 | }, |
| 7195 | }, | 7321 | }, |
| 7196 | .stack_offset => |off| { | 7322 | .stack_offset => |off| { |
| ... | @@ -7231,15 +7357,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -7231,15 +7357,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7231 | .{ty.fmtDebug()}, | 7357 | .{ty.fmtDebug()}, |
| 7232 | ), | 7358 | ), |
| 7233 | }; | 7359 | }; |
| 7234 | const ptr_size: Memory.PtrSize = switch (ty.tag()) { | 7360 | return self.asmRegisterMemory(tag, reg.to128(), Memory.sib( |
| 7235 | .f32 => .dword, | 7361 | Memory.PtrSize.fromSize(abi_size), |
| 7236 | .f64 => .qword, | 7362 | .{ .base = .rbp, .disp = -off }, |
| 7237 | else => unreachable, | 7363 | )); |
| 7238 | }; | | |
| 7239 | return self.asmRegisterMemory(tag, reg.to128(), Memory.sib(ptr_size, .{ | | |
| 7240 | .base = .rbp, | | |
| 7241 | .disp = -off, | | |
| 7242 | })); | | |
| 7243 | } | 7364 | } |
| 7244 | return self.fail("TODO genSetReg from stack offset for float with no intrinsics", .{}); | 7365 | return self.fail("TODO genSetReg from stack offset for float with no intrinsics", .{}); |
| 7245 | }, | 7366 | }, |
| ... | @@ -7299,7 +7420,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7299,7 +7420,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 7299 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { | 7420 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 7300 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); | 7421 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); |
| 7301 | try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); | 7422 | try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); |
| 7302 | try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len }, .{}); | 7423 | try self.genSetStack(Type.u64, stack_offset - 8, .{ .immediate = array_len }, .{}); |
| 7303 | break :blk .{ .stack_offset = stack_offset }; | 7424 | break :blk .{ .stack_offset = stack_offset }; |
| 7304 | }; | 7425 | }; |
| 7305 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 7426 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -7809,10 +7930,92 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7809,10 +7930,92 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 7809 | | 7930 | |
| 7810 | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { | 7931 | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 7811 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 7932 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 7812 | const operand = try self.resolveInst(un_op); | 7933 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 7813 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else { | 7934 | const err_ty = self.air.typeOf(un_op); |
| 7814 | _ = operand; | 7935 | const err_mcv = try self.resolveInst(un_op); |
| 7815 | return self.fail("TODO implement airErrorName for x86_64", .{}); | 7936 | const err_reg = try self.copyToTmpRegister(err_ty, err_mcv); |
| | 7937 | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); |
| | 7938 | defer self.register_manager.unlockReg(err_lock); |
| | 7939 | |
| | 7940 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| | 7941 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| | 7942 | defer self.register_manager.unlockReg(addr_lock); |
| | 7943 | |
| | 7944 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| | 7945 | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( |
| | 7946 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| | 7947 | 4, // dword alignment |
| | 7948 | ); |
| | 7949 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); |
| | 7950 | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ |
| | 7951 | .base = .ds, |
| | 7952 | .disp = @intCast(i32, got_addr), |
| | 7953 | })); |
| | 7954 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| | 7955 | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( |
| | 7956 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| | 7957 | 4, // dword alignment |
| | 7958 | ); |
| | 7959 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| | 7960 | try self.genSetReg(Type.usize, addr_reg, .{ .linker_load = .{ |
| | 7961 | .type = .got, |
| | 7962 | .sym_index = sym_index, |
| | 7963 | } }); |
| | 7964 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| | 7965 | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( |
| | 7966 | .{ .kind = .const_data, .ty = Type.anyerror }, |
| | 7967 | 4, // dword alignment |
| | 7968 | ); |
| | 7969 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| | 7970 | try self.genSetReg(Type.usize, addr_reg, .{ .linker_load = .{ |
| | 7971 | .type = .got, |
| | 7972 | .sym_index = sym_index, |
| | 7973 | } }); |
| | 7974 | } else { |
| | 7975 | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); |
| | 7976 | } |
| | 7977 | |
| | 7978 | const start_reg = try self.register_manager.allocReg(null, gp); |
| | 7979 | const start_lock = self.register_manager.lockRegAssumeUnused(start_reg); |
| | 7980 | defer self.register_manager.unlockReg(start_lock); |
| | 7981 | |
| | 7982 | const end_reg = try self.register_manager.allocReg(null, gp); |
| | 7983 | const end_lock = self.register_manager.lockRegAssumeUnused(end_reg); |
| | 7984 | defer self.register_manager.unlockReg(end_lock); |
| | 7985 | |
| | 7986 | try self.truncateRegister(err_ty, err_reg.to32()); |
| | 7987 | |
| | 7988 | try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{ |
| | 7989 | .base = addr_reg.to64(), |
| | 7990 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, |
| | 7991 | .disp = 0, |
| | 7992 | })); |
| | 7993 | try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{ |
| | 7994 | .base = addr_reg.to64(), |
| | 7995 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, |
| | 7996 | .disp = 4, |
| | 7997 | })); |
| | 7998 | try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32()); |
| | 7999 | try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{ |
| | 8000 | .base = addr_reg.to64(), |
| | 8001 | .scale_index = .{ .scale = 1, .index = start_reg.to64() }, |
| | 8002 | .disp = 0, |
| | 8003 | })); |
| | 8004 | try self.asmRegisterMemory(.lea, end_reg.to32(), Memory.sib(.byte, .{ |
| | 8005 | .base = end_reg.to64(), |
| | 8006 | .disp = -1, |
| | 8007 | })); |
| | 8008 | |
| | 8009 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| | 8010 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ |
| | 8011 | .base = .rbp, |
| | 8012 | .disp = 0 - dst_mcv.stack_offset, |
| | 8013 | }), start_reg.to64()); |
| | 8014 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ |
| | 8015 | .base = .rbp, |
| | 8016 | .disp = 8 - dst_mcv.stack_offset, |
| | 8017 | }), end_reg.to64()); |
| | 8018 | break :result dst_mcv; |
| 7816 | }; | 8019 | }; |
| 7817 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 8020 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 7818 | } | 8021 | } |
| ... | @@ -7853,19 +8056,88 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7853,19 +8056,88 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 7853 | if (self.liveness.isUnused(inst)) break :res MCValue.dead; | 8056 | if (self.liveness.isUnused(inst)) break :res MCValue.dead; |
| 7854 | switch (result_ty.zigTypeTag()) { | 8057 | switch (result_ty.zigTypeTag()) { |
| 7855 | .Struct => { | 8058 | .Struct => { |
| 7856 | if (result_ty.containerLayout() == .Packed) { | | |
| 7857 | return self.fail("TODO airAggregateInit implement packed structs", .{}); | | |
| 7858 | } | | |
| 7859 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); | 8059 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); |
| 7860 | for (elements, 0..) |elem, elem_i| { | 8060 | const dst_mcv = MCValue{ .stack_offset = stack_offset }; |
| 7861 | if (result_ty.structFieldValueComptime(elem_i) != null) continue; // comptime elem | 8061 | if (result_ty.containerLayout() == .Packed) { |
| | 8062 | const struct_obj = result_ty.castTag(.@"struct").?.data; |
| | 8063 | try self.genInlineMemset( |
| | 8064 | dst_mcv, |
| | 8065 | .{ .immediate = 0 }, |
| | 8066 | .{ .immediate = abi_size }, |
| | 8067 | .{}, |
| | 8068 | ); |
| | 8069 | for (elements, 0..) |elem, elem_i| { |
| | 8070 | if (result_ty.structFieldValueComptime(elem_i) != null) continue; |
| | 8071 | |
| | 8072 | const elem_ty = result_ty.structFieldType(elem_i); |
| | 8073 | const elem_bit_size = @intCast(u32, elem_ty.bitSize(self.target.*)); |
| | 8074 | if (elem_bit_size > 64) { |
| | 8075 | return self.fail("TODO airAggregateInit implement packed structs with large fields", .{}); |
| | 8076 | } |
| | 8077 | const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*)); |
| | 8078 | const elem_abi_bits = elem_abi_size * 8; |
| | 8079 | const elem_off = struct_obj.packedFieldBitOffset(self.target.*, elem_i); |
| | 8080 | const elem_byte_off = @intCast(i32, elem_off / elem_abi_bits * elem_abi_size); |
| | 8081 | const elem_bit_off = elem_off % elem_abi_bits; |
| | 8082 | const elem_mcv = try self.resolveInst(elem); |
| | 8083 | const elem_lock = switch (elem_mcv) { |
| | 8084 | .register => |reg| self.register_manager.lockReg(reg), |
| | 8085 | .immediate => |imm| lock: { |
| | 8086 | if (imm == 0) continue; |
| | 8087 | break :lock null; |
| | 8088 | }, |
| | 8089 | else => null, |
| | 8090 | }; |
| | 8091 | defer if (elem_lock) |lock| self.register_manager.unlockReg(lock); |
| | 8092 | const elem_reg = registerAlias( |
| | 8093 | try self.copyToTmpRegister(elem_ty, elem_mcv), |
| | 8094 | elem_abi_size, |
| | 8095 | ); |
| | 8096 | const elem_extra_bits = self.regExtraBits(elem_ty); |
| | 8097 | if (elem_bit_off < elem_extra_bits) { |
| | 8098 | try self.truncateRegister(elem_ty, elem_reg); |
| | 8099 | } |
| | 8100 | if (elem_bit_off > 0) try self.genShiftBinOpMir( |
| | 8101 | .shl, |
| | 8102 | elem_ty, |
| | 8103 | .{ .register = elem_reg }, |
| | 8104 | .{ .immediate = elem_bit_off }, |
| | 8105 | ); |
| | 8106 | try self.genBinOpMir( |
| | 8107 | .@"or", |
| | 8108 | elem_ty, |
| | 8109 | .{ .stack_offset = stack_offset - elem_byte_off }, |
| | 8110 | .{ .register = elem_reg }, |
| | 8111 | ); |
| | 8112 | if (elem_bit_off > elem_extra_bits) { |
| | 8113 | const reg = try self.copyToTmpRegister(elem_ty, elem_mcv); |
| | 8114 | if (elem_extra_bits > 0) { |
| | 8115 | try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size)); |
| | 8116 | } |
| | 8117 | try self.genShiftBinOpMir( |
| | 8118 | .shr, |
| | 8119 | elem_ty, |
| | 8120 | .{ .register = reg }, |
| | 8121 | .{ .immediate = elem_abi_bits - elem_bit_off }, |
| | 8122 | ); |
| | 8123 | try self.genBinOpMir( |
| | 8124 | .@"or", |
| | 8125 | elem_ty, |
| | 8126 | .{ .stack_offset = stack_offset - elem_byte_off - |
| | 8127 | @intCast(i32, elem_abi_size) }, |
| | 8128 | .{ .register = reg }, |
| | 8129 | ); |
| | 8130 | } |
| | 8131 | } |
| | 8132 | } else for (elements, 0..) |elem, elem_i| { |
| | 8133 | if (result_ty.structFieldValueComptime(elem_i) != null) continue; |
| 7862 | | 8134 | |
| 7863 | const elem_ty = result_ty.structFieldType(elem_i); | 8135 | const elem_ty = result_ty.structFieldType(elem_i); |
| 7864 | const elem_off = result_ty.structFieldOffset(elem_i, self.target.*); | 8136 | const elem_off = @intCast(i32, result_ty.structFieldOffset(elem_i, self.target.*)); |
| 7865 | const elem_mcv = try self.resolveInst(elem); | 8137 | const elem_mcv = try self.resolveInst(elem); |
| 7866 | try self.genSetStack(elem_ty, stack_offset - @intCast(i32, elem_off), elem_mcv, .{}); | 8138 | try self.genSetStack(elem_ty, stack_offset - elem_off, elem_mcv, .{}); |
| 7867 | } | 8139 | } |
| 7868 | break :res MCValue{ .stack_offset = stack_offset }; | 8140 | break :res dst_mcv; |
| 7869 | }, | 8141 | }, |
| 7870 | .Array => { | 8142 | .Array => { |
| 7871 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); | 8143 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); |
| ... | @@ -7980,7 +8252,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV | ... | @@ -7980,7 +8252,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV |
| 7980 | // This immediate is unsigned. | 8252 | // This immediate is unsigned. |
| 7981 | const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed)); | 8253 | const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed)); |
| 7982 | if (imm >= math.maxInt(U)) { | 8254 | if (imm >= math.maxInt(U)) { |
| 7983 | return MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.usize), mcv) }; | 8255 | return MCValue{ .register = try self.copyToTmpRegister(Type.usize, mcv) }; |
| 7984 | } | 8256 | } |
| 7985 | }, | 8257 | }, |
| 7986 | else => {}, | 8258 | else => {}, |
| ... | @@ -8023,11 +8295,18 @@ const CallMCValues = struct { | ... | @@ -8023,11 +8295,18 @@ const CallMCValues = struct { |
| 8023 | }; | 8295 | }; |
| 8024 | | 8296 | |
| 8025 | /// Caller must call `CallMCValues.deinit`. | 8297 | /// Caller must call `CallMCValues.deinit`. |
| 8026 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | 8298 | fn resolveCallingConventionValues( |
| | 8299 | self: *Self, |
| | 8300 | fn_ty: Type, |
| | 8301 | var_args: []const Air.Inst.Ref, |
| | 8302 | ) !CallMCValues { |
| 8027 | const cc = fn_ty.fnCallingConvention(); | 8303 | const cc = fn_ty.fnCallingConvention(); |
| 8028 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | 8304 | const param_len = fn_ty.fnParamLen(); |
| | 8305 | const param_types = try self.gpa.alloc(Type, param_len + var_args.len); |
| 8029 | defer self.gpa.free(param_types); | 8306 | defer self.gpa.free(param_types); |
| 8030 | fn_ty.fnParamTypes(param_types); | 8307 | fn_ty.fnParamTypes(param_types); |
| | 8308 | // TODO: promote var arg types |
| | 8309 | for (param_types[param_len..], var_args) |*param_ty, arg| param_ty.* = self.air.typeOf(arg); |
| 8031 | var result: CallMCValues = .{ | 8310 | var result: CallMCValues = .{ |
| 8032 | .args = try self.gpa.alloc(MCValue, param_types.len), | 8311 | .args = try self.gpa.alloc(MCValue, param_types.len), |
| 8033 | // These undefined values must be populated before returning from this function. | 8312 | // These undefined values must be populated before returning from this function. |
| ... | @@ -8248,8 +8527,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { | ... | @@ -8248,8 +8527,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 8248 | .unsigned => { | 8527 | .unsigned => { |
| 8249 | const shift = @intCast(u6, max_reg_bit_width - int_info.bits); | 8528 | const shift = @intCast(u6, max_reg_bit_width - int_info.bits); |
| 8250 | const mask = (~@as(u64, 0)) >> shift; | 8529 | const mask = (~@as(u64, 0)) >> shift; |
| 8251 | if (int_info.bits < 32) { | 8530 | if (int_info.bits <= 32) { |
| 8252 | try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask }); | 8531 | try self.genBinOpMir(.@"and", Type.u32, .{ .register = reg }, .{ .immediate = mask }); |
| 8253 | } else { | 8532 | } else { |
| 8254 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); | 8533 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); |
| 8255 | try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg }); | 8534 | try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg }); |