authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-02 14:34:12+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-04-02 14:34:12+02:00
log878163e58813aef968900aa7495dacc5220eb941
tree998bf1472c044903d21d301d362f1c650cc69152
parent43a6384e9c6ee6f3e250172f6f655782e808afed
parentf4359531b154951f9c242c487249169499f0852d
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15140 from jacobly0/x86_64

x86_64: implement more stuff

33 files changed, 1240 insertions(+), 574 deletions(-)

lib/std/os.zig+2
...@@ -1937,6 +1937,8 @@ pub fn getenv(key: []const u8) ?[]const u8 {...@@ -1937,6 +1937,8 @@ pub fn getenv(key: []const u8) ?[]const u8 {
1937 if (builtin.os.tag == .windows) {1937 if (builtin.os.tag == .windows) {
1938 @compileError("std.os.getenv is unavailable for Windows because environment string is in WTF-16 format. See std.process.getEnvVarOwned for cross-platform API or std.os.getenvW for Windows-specific API.");1938 @compileError("std.os.getenv is unavailable for Windows because environment string is in WTF-16 format. See std.process.getEnvVarOwned for cross-platform API or std.os.getenvW for Windows-specific API.");
1939 }1939 }
1940 // The simplified start logic doesn't populate environ.
1941 if (std.start.simplified_logic) return null;
1940 // TODO see https://github.com/ziglang/zig/issues/45241942 // TODO see https://github.com/ziglang/zig/issues/4524
1941 for (environ) |ptr| {1943 for (environ) |ptr| {
1942 var line_i: usize = 0;1944 var line_i: usize = 0;
lib/std/start.zig+13-11
...@@ -14,22 +14,24 @@ var argc_argv_ptr: [*]usize = undefined;...@@ -14,22 +14,24 @@ var argc_argv_ptr: [*]usize = undefined;
1414
15const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start";15const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start";
1616
17// The self-hosted compiler is not fully capable of handling all of this start.zig file.
18// Until then, we have simplified logic here for self-hosted. TODO remove this once
19// self-hosted is capable enough to handle all of the real start.zig logic.
20pub const simplified_logic =
21 builtin.zig_backend == .stage2_wasm or
22 builtin.zig_backend == .stage2_x86_64 or
23 builtin.zig_backend == .stage2_x86 or
24 builtin.zig_backend == .stage2_aarch64 or
25 builtin.zig_backend == .stage2_arm or
26 builtin.zig_backend == .stage2_riscv64 or
27 builtin.zig_backend == .stage2_sparc64;
28
17comptime {29comptime {
18 // No matter what, we import the root file, so that any export, test, comptime30 // No matter what, we import the root file, so that any export, test, comptime
19 // decls there get run.31 // decls there get run.
20 _ = root;32 _ = root;
2133
22 // The self-hosted compiler is not fully capable of handling all of this start.zig file.34 if (simplified_logic) {
23 // Until then, we have simplified logic here for self-hosted. TODO remove this once
24 // self-hosted is capable enough to handle all of the real start.zig logic.
25 if (builtin.zig_backend == .stage2_wasm or
26 builtin.zig_backend == .stage2_x86_64 or
27 builtin.zig_backend == .stage2_x86 or
28 builtin.zig_backend == .stage2_aarch64 or
29 builtin.zig_backend == .stage2_arm or
30 builtin.zig_backend == .stage2_riscv64 or
31 builtin.zig_backend == .stage2_sparc64)
32 {
33 if (builtin.output_mode == .Exe) {35 if (builtin.output_mode == .Exe) {
34 if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) {36 if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) {
35 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {37 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
src/arch/x86_64/CodeGen.zig+784-505
...@@ -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();
318318
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),
954954
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),
959959
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),
961961
...@@ -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}
16271627
1628fn 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
1628fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {1663fn 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);
16351668 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 }
16391670
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);
16411685
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);
16441689 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 };
17971841
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}
18091853
1810fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1854fn 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();
18251864
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 };
18441875
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 }
18471884
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 }
18571896
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));
18651902
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);
18671904
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}
18731912
1913fn 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}
18761983
...@@ -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 };
18982006
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);
19052009
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 );
19242028
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(
1931fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {2035fn 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;
19342038 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.*);
19502044
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);
19542060
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);
19592064
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 }
19702073
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 }
19732085
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 {
19852097
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);
19922104
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);
20122124
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));
20242136
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);
20262138
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}
20352146
...@@ -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 }
20592169
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 }
20642176
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 });
21062213
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
3818fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {3925fn 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 };
38233944
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 }
38273961
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 };
38383965
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) catch3969 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);
38494008
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);
38654022
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 });
38684025
3869 // Mask to field_bit_size bits4026 // 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 },
38994055 ),
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}
39134073
...@@ -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);
40034164
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;
42894448
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);
42954454
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 };
43294487
4330 try self.genIntMulDivOpMir(mir_tag, ty, .signed, lhs, rhs);4488 try self.genIntMulDivOpMir(mir_tag, ty, lhs, rhs);
43314489
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 },
43384507
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);
43974566
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 },
44114575
4412 else => unreachable,4576 else => unreachable,
...@@ -4454,7 +4618,7 @@ fn genBinOp(...@@ -4454,7 +4618,7 @@ fn genBinOp(
44544618
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(),
44684632
4469 else => false,4633 else => true,
4470 };4634 };
44714635
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);
44834647
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);
45034670
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 },
45854746
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 );
46694821
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);
47984978
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 we4980 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 else5073 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}
49415126
...@@ -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 };
51935378
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);
51965381
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
52805465
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 }
53595539
...@@ -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 {
54575637
5458fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {5638fn 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;
54605644
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;
54795647
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);
54915654
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),
54955658 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);
55205682
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);
55265689
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}
55355697
...@@ -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
57905952
5791 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv);5953 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv);
57925954
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}
66826837
6683fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: InlineMemcpyOpts) InnerError!void {6838fn 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 // TODO6898 // 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 else6910 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 we6919 // 64 bit write to memory would take two mov's anyways so we
6760 // insted just use two 32 bit writes to avoid register allocation6920 // 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 else6930 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) {
68166981 // 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 }
68286985
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
71017258
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);
71447265
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 }
71627279
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 {
78097930
7810fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {7931fn 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 elem8061 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;
78628134
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};
80248296
8025/// Caller must call `CallMCValues.deinit`.8297/// Caller must call `CallMCValues.deinit`.
8026fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {8298fn 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 });
src/arch/x86_64/bits.zig+10
...@@ -100,6 +100,16 @@ pub const Condition = enum(u5) {...@@ -100,6 +100,16 @@ pub const Condition = enum(u5) {
100 };100 };
101 }101 }
102102
103 pub fn fromCompareOperator(
104 signedness: std.builtin.Signedness,
105 op: std.math.CompareOperator,
106 ) Condition {
107 return switch (signedness) {
108 .signed => fromCompareOperatorSigned(op),
109 .unsigned => fromCompareOperatorUnsigned(op),
110 };
111 }
112
103 /// Returns the condition which is true iff the given condition is false113 /// Returns the condition which is true iff the given condition is false
104 pub fn negate(cond: Condition) Condition {114 pub fn negate(cond: Condition) Condition {
105 return switch (cond) {115 return switch (cond) {
src/codegen.zig+44-7
...@@ -99,6 +99,47 @@ fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian...@@ -99,6 +99,47 @@ fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian
99 mem.writeInt(Int, code[0..@sizeOf(Int)], int, endian);99 mem.writeInt(Int, code[0..@sizeOf(Int)], int, endian);
100}100}
101101
102pub fn generateLazySymbol(
103 bin_file: *link.File,
104 src_loc: Module.SrcLoc,
105 lazy_sym: link.File.LazySymbol,
106 code: *std.ArrayList(u8),
107 debug_output: DebugInfoOutput,
108 reloc_info: RelocInfo,
109) CodeGenError!Result {
110 _ = debug_output;
111 _ = reloc_info;
112
113 const tracy = trace(@src());
114 defer tracy.end();
115
116 const target = bin_file.options.target;
117 const endian = target.cpu.arch.endian();
118
119 const mod = bin_file.options.module.?;
120 log.debug("generateLazySymbol: kind = {s}, ty = {}", .{
121 @tagName(lazy_sym.kind),
122 lazy_sym.ty.fmt(mod),
123 });
124
125 if (lazy_sym.kind == .const_data and lazy_sym.ty.isAnyError()) {
126 const err_names = mod.error_name_list.items;
127 try code.resize(err_names.len * 4);
128 for (err_names, 0..) |err_name, index| {
129 mem.writeInt(u32, code.items[index * 4 ..][0..4], @intCast(u32, code.items.len), endian);
130 try code.ensureUnusedCapacity(err_name.len + 1);
131 code.appendSliceAssumeCapacity(err_name);
132 code.appendAssumeCapacity(0);
133 }
134 return Result.ok;
135 } else return .{ .fail = try ErrorMsg.create(
136 bin_file.allocator,
137 src_loc,
138 "TODO implement generateLazySymbol for {s} {}",
139 .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(mod) },
140 ) };
141}
142
102pub fn generateSymbol(143pub fn generateSymbol(
103 bin_file: *link.File,144 bin_file: *link.File,
104 src_loc: Module.SrcLoc,145 src_loc: Module.SrcLoc,
...@@ -118,9 +159,10 @@ pub fn generateSymbol(...@@ -118,9 +159,10 @@ pub fn generateSymbol(
118 const target = bin_file.options.target;159 const target = bin_file.options.target;
119 const endian = target.cpu.arch.endian();160 const endian = target.cpu.arch.endian();
120161
162 const mod = bin_file.options.module.?;
121 log.debug("generateSymbol: ty = {}, val = {}", .{163 log.debug("generateSymbol: ty = {}, val = {}", .{
122 typed_value.ty.fmtDebug(),164 typed_value.ty.fmt(mod),
123 typed_value.val.fmtDebug(),165 typed_value.val.fmtValue(typed_value.ty, mod),
124 });166 });
125167
126 if (typed_value.val.isUndefDeep()) {168 if (typed_value.val.isUndefDeep()) {
...@@ -170,7 +212,6 @@ pub fn generateSymbol(...@@ -170,7 +212,6 @@ pub fn generateSymbol(
170 },212 },
171 .str_lit => {213 .str_lit => {
172 const str_lit = typed_value.val.castTag(.str_lit).?.data;214 const str_lit = typed_value.val.castTag(.str_lit).?.data;
173 const mod = bin_file.options.module.?;
174 const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];215 const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
175 try code.ensureUnusedCapacity(bytes.len + 1);216 try code.ensureUnusedCapacity(bytes.len + 1);
176 code.appendSliceAssumeCapacity(bytes);217 code.appendSliceAssumeCapacity(bytes);
...@@ -300,7 +341,6 @@ pub fn generateSymbol(...@@ -300,7 +341,6 @@ pub fn generateSymbol(
300 switch (container_ptr.tag()) {341 switch (container_ptr.tag()) {
301 .decl_ref => {342 .decl_ref => {
302 const decl_index = container_ptr.castTag(.decl_ref).?.data;343 const decl_index = container_ptr.castTag(.decl_ref).?.data;
303 const mod = bin_file.options.module.?;
304 const decl = mod.declPtr(decl_index);344 const decl = mod.declPtr(decl_index);
305 const addend = blk: {345 const addend = blk: {
306 switch (decl.ty.zigTypeTag()) {346 switch (decl.ty.zigTypeTag()) {
...@@ -493,7 +533,6 @@ pub fn generateSymbol(...@@ -493,7 +533,6 @@ pub fn generateSymbol(
493 const field_vals = typed_value.val.castTag(.aggregate).?.data;533 const field_vals = typed_value.val.castTag(.aggregate).?.data;
494 const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow;534 const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow;
495 const current_pos = code.items.len;535 const current_pos = code.items.len;
496 const mod = bin_file.options.module.?;
497 try code.resize(current_pos + abi_size);536 try code.resize(current_pos + abi_size);
498 var bits: u16 = 0;537 var bits: u16 = 0;
499538
...@@ -570,7 +609,6 @@ pub fn generateSymbol(...@@ -570,7 +609,6 @@ pub fn generateSymbol(
570 }609 }
571610
572 const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;611 const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;
573 const mod = bin_file.options.module.?;
574 const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?;612 const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?;
575 assert(union_ty.haveFieldTypes());613 assert(union_ty.haveFieldTypes());
576 const field_ty = union_ty.fields.values()[field_index].ty;614 const field_ty = union_ty.fields.values()[field_index].ty;
...@@ -776,7 +814,6 @@ pub fn generateSymbol(...@@ -776,7 +814,6 @@ pub fn generateSymbol(
776 },814 },
777 .str_lit => {815 .str_lit => {
778 const str_lit = typed_value.val.castTag(.str_lit).?.data;816 const str_lit = typed_value.val.castTag(.str_lit).?.data;
779 const mod = bin_file.options.module.?;
780 const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];817 const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
781 try code.ensureUnusedCapacity(str_lit.len);818 try code.ensureUnusedCapacity(str_lit.len);
782 code.appendSliceAssumeCapacity(bytes);819 code.appendSliceAssumeCapacity(bytes);
src/link.zig+21
...@@ -687,6 +687,7 @@ pub const File = struct {...@@ -687,6 +687,7 @@ pub const File = struct {
687 FrameworkNotFound,687 FrameworkNotFound,
688 FunctionSignatureMismatch,688 FunctionSignatureMismatch,
689 GlobalTypeMismatch,689 GlobalTypeMismatch,
690 HotSwapUnavailableOnHostOperatingSystem,
690 InvalidCharacter,691 InvalidCharacter,
691 InvalidEntryKind,692 InvalidEntryKind,
692 InvalidFeatureSet,693 InvalidFeatureSet,
...@@ -1104,6 +1105,26 @@ pub const File = struct {...@@ -1104,6 +1105,26 @@ pub const File = struct {
1104 missing_libc: bool = false,1105 missing_libc: bool = false,
1105 };1106 };
11061107
1108 pub const LazySymbol = struct {
1109 kind: enum { code, const_data },
1110 ty: Type,
1111
1112 pub const Context = struct {
1113 mod: *Module,
1114
1115 pub fn hash(ctx: @This(), sym: LazySymbol) u32 {
1116 var hasher = std.hash.Wyhash.init(0);
1117 std.hash.autoHash(&hasher, sym.kind);
1118 sym.ty.hashWithHasher(&hasher, ctx.mod);
1119 return @truncate(u32, hasher.final());
1120 }
1121
1122 pub fn eql(ctx: @This(), lhs: LazySymbol, rhs: LazySymbol, _: usize) bool {
1123 return lhs.kind == rhs.kind and lhs.ty.eql(rhs.ty, ctx.mod);
1124 }
1125 };
1126 };
1127
1107 pub const C = @import("link/C.zig");1128 pub const C = @import("link/C.zig");
1108 pub const Coff = @import("link/Coff.zig");1129 pub const Coff = @import("link/Coff.zig");
1109 pub const Plan9 = @import("link/Plan9.zig");1130 pub const Plan9 = @import("link/Plan9.zig");
src/link/Coff.zig+122
...@@ -49,6 +49,9 @@ imports_count_dirty: bool = true,...@@ -49,6 +49,9 @@ imports_count_dirty: bool = true,
49/// Virtual address of the entry point procedure relative to image base.49/// Virtual address of the entry point procedure relative to image base.
50entry_addr: ?u32 = null,50entry_addr: ?u32 = null,
5151
52/// Table of tracked LazySymbols.
53lazy_syms: LazySymbolTable = .{},
54
52/// Table of tracked Decls.55/// Table of tracked Decls.
53decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},56decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
5457
...@@ -142,6 +145,18 @@ const Section = struct {...@@ -142,6 +145,18 @@ const Section = struct {
142 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},145 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
143};146};
144147
148const LazySymbolTable = std.ArrayHashMapUnmanaged(
149 link.File.LazySymbol,
150 LazySymbolMetadata,
151 link.File.LazySymbol.Context,
152 true,
153);
154
155const LazySymbolMetadata = struct {
156 atom: Atom.Index,
157 section: u16,
158};
159
145const DeclMetadata = struct {160const DeclMetadata = struct {
146 atom: Atom.Index,161 atom: Atom.Index,
147 section: u16,162 section: u16,
...@@ -1168,6 +1183,100 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -1168,6 +1183,100 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
1168 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));1183 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
1169}1184}
11701185
1186fn updateLazySymbol(
1187 self: *Coff,
1188 lazy_sym: link.File.LazySymbol,
1189 lazy_metadata: LazySymbolMetadata,
1190) !void {
1191 const gpa = self.base.allocator;
1192 const mod = self.base.options.module.?;
1193
1194 var code_buffer = std.ArrayList(u8).init(gpa);
1195 defer code_buffer.deinit();
1196
1197 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
1198 @tagName(lazy_sym.kind),
1199 lazy_sym.ty.fmt(mod),
1200 });
1201 defer gpa.free(name);
1202
1203 const atom_index = lazy_metadata.atom;
1204 const atom = self.getAtomPtr(atom_index);
1205 const local_sym_index = atom.getSymbolIndex().?;
1206
1207 const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl|
1208 mod.declPtr(owner_decl).srcLoc()
1209 else
1210 Module.SrcLoc{
1211 .file_scope = undefined,
1212 .parent_decl_node = undefined,
1213 .lazy = .unneeded,
1214 };
1215 const res = try codegen.generateLazySymbol(
1216 &self.base,
1217 src,
1218 lazy_sym,
1219 &code_buffer,
1220 .none,
1221 .{ .parent_atom_index = local_sym_index },
1222 );
1223 const code = switch (res) {
1224 .ok => code_buffer.items,
1225 .fail => |em| {
1226 log.err("{s}", .{em.msg});
1227 return error.CodegenFail;
1228 },
1229 };
1230
1231 const required_alignment = atom.alignment;
1232 const code_len = @intCast(u32, code.len);
1233 const symbol = atom.getSymbolPtr(self);
1234 try self.setSymbolName(symbol, name);
1235 symbol.section_number = @intToEnum(coff.SectionNumber, lazy_metadata.section + 1);
1236 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };
1237
1238 const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
1239 errdefer self.freeAtom(atom_index);
1240
1241 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });
1242 log.debug(" (required alignment 0x{x})", .{required_alignment});
1243
1244 atom.size = code_len;
1245 symbol.value = vaddr;
1246
1247 const got_target = SymbolWithLoc{ .sym_index = local_sym_index, .file = null };
1248 const got_index = try self.allocateGotEntry(got_target);
1249 const got_atom_index = try self.createGotAtom(got_target);
1250 const got_atom = self.getAtom(got_atom_index);
1251 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
1252 try self.writePtrWidthAtom(got_atom_index);
1253
1254 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
1255 try self.writeAtom(atom_index, code);
1256}
1257
1258pub fn getOrCreateAtomForLazySymbol(
1259 self: *Coff,
1260 lazy_sym: link.File.LazySymbol,
1261 alignment: u32,
1262) !Atom.Index {
1263 const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{
1264 .mod = self.base.options.module.?,
1265 });
1266 errdefer _ = self.lazy_syms.pop();
1267 if (!gop.found_existing) {
1268 gop.value_ptr.* = .{
1269 .atom = try self.createAtom(),
1270 .section = switch (lazy_sym.kind) {
1271 .code => self.text_section_index.?,
1272 .const_data => self.rdata_section_index.?,
1273 },
1274 };
1275 self.getAtomPtr(gop.value_ptr.atom).alignment = alignment;
1276 }
1277 return gop.value_ptr.atom;
1278}
1279
1171pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {1280pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {
1172 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);1281 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
1173 if (!gop.found_existing) {1282 if (!gop.found_existing) {
...@@ -1498,6 +1607,19 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1498,6 +1607,19 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1498 sub_prog_node.activate();1607 sub_prog_node.activate();
1499 defer sub_prog_node.end();1608 defer sub_prog_node.end();
15001609
1610 {
1611 var lazy_it = self.lazy_syms.iterator();
1612 while (lazy_it.next()) |lazy_entry| {
1613 self.updateLazySymbol(
1614 lazy_entry.key_ptr.*,
1615 lazy_entry.value_ptr.*,
1616 ) catch |err| switch (err) {
1617 error.CodegenFail => return error.FlushFailure,
1618 else => |e| return e,
1619 };
1620 }
1621 }
1622
1501 const gpa = self.base.allocator;1623 const gpa = self.base.allocator;
15021624
1503 while (self.unresolved.popOrNull()) |entry| {1625 while (self.unresolved.popOrNull()) |entry| {
src/link/Elf.zig+114
...@@ -63,6 +63,12 @@ const Section = struct {...@@ -63,6 +63,12 @@ const Section = struct {
63 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},63 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
64};64};
6565
66const LazySymbolMetadata = struct {
67 atom: Atom.Index,
68 shdr: u16,
69 alignment: u32,
70};
71
66const DeclMetadata = struct {72const DeclMetadata = struct {
67 atom: Atom.Index,73 atom: Atom.Index,
68 shdr: u16,74 shdr: u16,
...@@ -157,6 +163,9 @@ debug_line_header_dirty: bool = false,...@@ -157,6 +163,9 @@ debug_line_header_dirty: bool = false,
157163
158error_flags: File.ErrorFlags = File.ErrorFlags{},164error_flags: File.ErrorFlags = File.ErrorFlags{},
159165
166/// Table of tracked LazySymbols.
167lazy_syms: LazySymbolTable = .{},
168
160/// Table of tracked Decls.169/// Table of tracked Decls.
161decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},170decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
162171
...@@ -194,6 +203,7 @@ relocs: RelocTable = .{},...@@ -194,6 +203,7 @@ relocs: RelocTable = .{},
194203
195const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));204const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));
196const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));205const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
206const LazySymbolTable = std.ArrayHashMapUnmanaged(File.LazySymbol, LazySymbolMetadata, File.LazySymbol.Context, true);
197207
198/// When allocating, the ideal_capacity is calculated by208/// When allocating, the ideal_capacity is calculated by
199/// actual_capacity + (actual_capacity / ideal_factor)209/// actual_capacity + (actual_capacity / ideal_factor)
...@@ -1011,6 +1021,19 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1011,6 +1021,19 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1011 sub_prog_node.activate();1021 sub_prog_node.activate();
1012 defer sub_prog_node.end();1022 defer sub_prog_node.end();
10131023
1024 {
1025 var lazy_it = self.lazy_syms.iterator();
1026 while (lazy_it.next()) |lazy_entry| {
1027 self.updateLazySymbol(
1028 lazy_entry.key_ptr.*,
1029 lazy_entry.value_ptr.*,
1030 ) catch |err| switch (err) {
1031 error.CodegenFail => return error.FlushFailure,
1032 else => |e| return e,
1033 };
1034 }
1035 }
1036
1014 // TODO This linker code currently assumes there is only 1 compilation unit and it1037 // TODO This linker code currently assumes there is only 1 compilation unit and it
1015 // corresponds to the Zig source code.1038 // corresponds to the Zig source code.
1016 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;1039 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
...@@ -2344,6 +2367,24 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {...@@ -2344,6 +2367,24 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
2344 }2367 }
2345}2368}
23462369
2370pub fn getOrCreateAtomForLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, alignment: u32) !Atom.Index {
2371 const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{
2372 .mod = self.base.options.module.?,
2373 });
2374 errdefer _ = self.lazy_syms.pop();
2375 if (!gop.found_existing) {
2376 gop.value_ptr.* = .{
2377 .atom = try self.createAtom(),
2378 .shdr = switch (lazy_sym.kind) {
2379 .code => self.text_section_index.?,
2380 .const_data => self.rodata_section_index.?,
2381 },
2382 .alignment = alignment,
2383 };
2384 }
2385 return gop.value_ptr.atom;
2386}
2387
2347pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {2388pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {
2348 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);2389 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2349 if (!gop.found_existing) {2390 if (!gop.found_existing) {
...@@ -2610,6 +2651,79 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2610,6 +2651,79 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2610 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));2651 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2611}2652}
26122653
2654fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySymbolMetadata) !void {
2655 const gpa = self.base.allocator;
2656 const mod = self.base.options.module.?;
2657
2658 var code_buffer = std.ArrayList(u8).init(gpa);
2659 defer code_buffer.deinit();
2660
2661 const name_str_index = blk: {
2662 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
2663 @tagName(lazy_sym.kind),
2664 lazy_sym.ty.fmt(mod),
2665 });
2666 defer gpa.free(name);
2667 break :blk try self.shstrtab.insert(gpa, name);
2668 };
2669 const name = self.shstrtab.get(name_str_index).?;
2670
2671 const atom_index = lazy_metadata.atom;
2672 const atom = self.getAtom(atom_index);
2673 const local_sym_index = atom.getSymbolIndex().?;
2674
2675 const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl|
2676 mod.declPtr(owner_decl).srcLoc()
2677 else
2678 Module.SrcLoc{
2679 .file_scope = undefined,
2680 .parent_decl_node = undefined,
2681 .lazy = .unneeded,
2682 };
2683 const res = try codegen.generateLazySymbol(
2684 &self.base,
2685 src,
2686 lazy_sym,
2687 &code_buffer,
2688 .none,
2689 .{ .parent_atom_index = local_sym_index },
2690 );
2691 const code = switch (res) {
2692 .ok => code_buffer.items,
2693 .fail => |em| {
2694 log.err("{s}", .{em.msg});
2695 return error.CodegenFail;
2696 },
2697 };
2698
2699 const shdr_index = lazy_metadata.shdr;
2700 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
2701 const local_sym = atom.getSymbolPtr(self);
2702 local_sym.* = .{
2703 .st_name = name_str_index,
2704 .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT,
2705 .st_other = 0,
2706 .st_shndx = shdr_index,
2707 .st_value = 0,
2708 .st_size = 0,
2709 };
2710 const required_alignment = lazy_metadata.alignment;
2711 const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);
2712 errdefer self.freeAtom(atom_index);
2713 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });
2714
2715 self.offset_table.items[atom.offset_table_index] = vaddr;
2716 local_sym.st_value = vaddr;
2717 local_sym.st_size = code.len;
2718
2719 try self.writeSymbol(local_sym_index);
2720 try self.writeOffsetTableEntry(atom.offset_table_index);
2721
2722 const section_offset = vaddr - self.program_headers.items[phdr_index].p_vaddr;
2723 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
2724 try self.base.file.?.pwriteAll(code, file_offset);
2725}
2726
2613pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {2727pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
2614 const gpa = self.base.allocator;2728 const gpa = self.base.allocator;
26152729
src/link/MachO.zig+126-4
...@@ -218,6 +218,9 @@ bindings: BindingTable = .{},...@@ -218,6 +218,9 @@ bindings: BindingTable = .{},
218/// this will be a table indexed by index into the list of Atoms.218/// this will be a table indexed by index into the list of Atoms.
219lazy_bindings: BindingTable = .{},219lazy_bindings: BindingTable = .{},
220220
221/// Table of tracked LazySymbols.
222lazy_syms: LazySymbolTable = .{},
223
221/// Table of tracked Decls.224/// Table of tracked Decls.
222decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},225decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
223226
...@@ -229,6 +232,18 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {...@@ -229,6 +232,18 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
229 else => false,232 else => false,
230};233};
231234
235const LazySymbolTable = std.ArrayHashMapUnmanaged(
236 link.File.LazySymbol,
237 LazySymbolMetadata,
238 link.File.LazySymbol.Context,
239 true,
240);
241
242const LazySymbolMetadata = struct {
243 atom: Atom.Index,
244 section: u8,
245};
246
232const DeclMetadata = struct {247const DeclMetadata = struct {
233 atom: Atom.Index,248 atom: Atom.Index,
234 section: u8,249 section: u8,
...@@ -497,6 +512,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -497,6 +512,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
497 sub_prog_node.activate();512 sub_prog_node.activate();
498 defer sub_prog_node.end();513 defer sub_prog_node.end();
499514
515 {
516 var lazy_it = self.lazy_syms.iterator();
517 while (lazy_it.next()) |lazy_entry| {
518 self.updateLazySymbol(
519 lazy_entry.key_ptr.*,
520 lazy_entry.value_ptr.*,
521 ) catch |err| switch (err) {
522 error.CodegenFail => return error.FlushFailure,
523 else => |e| return e,
524 };
525 }
526 }
527
500 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;528 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
501529
502 if (self.d_sym) |*d_sym| {530 if (self.d_sym) |*d_sym| {
...@@ -2163,13 +2191,13 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu...@@ -2163,13 +2191,13 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
21632191
2164 const name_str_index = blk: {2192 const name_str_index = blk: {
2165 const index = unnamed_consts.items.len;2193 const index = unnamed_consts.items.len;
2166 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });2194 const name = try std.fmt.allocPrint(gpa, "___unnamed_{s}_{d}", .{ decl_name, index });
2167 defer gpa.free(name);2195 defer gpa.free(name);
2168 break :blk try self.strtab.insert(gpa, name);2196 break :blk try self.strtab.insert(gpa, name);
2169 };2197 };
2170 const name = self.strtab.get(name_str_index);2198 const name = self.strtab.get(name_str_index).?;
21712199
2172 log.debug("allocating symbol indexes for {?s}", .{name});2200 log.debug("allocating symbol indexes for {s}", .{name});
21732201
2174 const atom_index = try self.createAtom();2202 const atom_index = try self.createAtom();
21752203
...@@ -2202,7 +2230,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu...@@ -2202,7 +2230,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
22022230
2203 try unnamed_consts.append(gpa, atom_index);2231 try unnamed_consts.append(gpa, atom_index);
22042232
2205 log.debug("allocated atom for {?s} at 0x{x}", .{ name, symbol.n_value });2233 log.debug("allocated atom for {s} at 0x{x}", .{ name, symbol.n_value });
2206 log.debug(" (required alignment 0x{x})", .{required_alignment});2234 log.debug(" (required alignment 0x{x})", .{required_alignment});
22072235
2208 try self.writeAtom(atom_index, code);2236 try self.writeAtom(atom_index, code);
...@@ -2282,6 +2310,100 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2282,6 +2310,100 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2282 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));2310 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2283}2311}
22842312
2313fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: LazySymbolMetadata) !void {
2314 const gpa = self.base.allocator;
2315 const mod = self.base.options.module.?;
2316
2317 var code_buffer = std.ArrayList(u8).init(gpa);
2318 defer code_buffer.deinit();
2319
2320 const name_str_index = blk: {
2321 const name = try std.fmt.allocPrint(gpa, "___lazy_{s}_{}", .{
2322 @tagName(lazy_sym.kind),
2323 lazy_sym.ty.fmt(mod),
2324 });
2325 defer gpa.free(name);
2326 break :blk try self.strtab.insert(gpa, name);
2327 };
2328 const name = self.strtab.get(name_str_index).?;
2329
2330 const atom_index = lazy_metadata.atom;
2331 const atom = self.getAtomPtr(atom_index);
2332 const local_sym_index = atom.getSymbolIndex().?;
2333
2334 const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl|
2335 mod.declPtr(owner_decl).srcLoc()
2336 else
2337 Module.SrcLoc{
2338 .file_scope = undefined,
2339 .parent_decl_node = undefined,
2340 .lazy = .unneeded,
2341 };
2342 const res = try codegen.generateLazySymbol(
2343 &self.base,
2344 src,
2345 lazy_sym,
2346 &code_buffer,
2347 .none,
2348 .{ .parent_atom_index = local_sym_index },
2349 );
2350 const code = switch (res) {
2351 .ok => code_buffer.items,
2352 .fail => |em| {
2353 log.err("{s}", .{em.msg});
2354 return error.CodegenFail;
2355 },
2356 };
2357
2358 const required_alignment = atom.alignment;
2359 const symbol = atom.getSymbolPtr(self);
2360 symbol.n_strx = name_str_index;
2361 symbol.n_type = macho.N_SECT;
2362 symbol.n_sect = lazy_metadata.section + 1;
2363 symbol.n_desc = 0;
2364
2365 const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);
2366 errdefer self.freeAtom(atom_index);
2367
2368 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });
2369 log.debug(" (required alignment 0x{x}", .{required_alignment});
2370
2371 atom.size = code.len;
2372 symbol.n_value = vaddr;
2373
2374 const got_target = SymbolWithLoc{ .sym_index = local_sym_index, .file = null };
2375 const got_index = try self.allocateGotEntry(got_target);
2376 const got_atom_index = try self.createGotAtom(got_target);
2377 const got_atom = self.getAtom(got_atom_index);
2378 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
2379 try self.writePtrWidthAtom(got_atom_index);
2380
2381 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
2382 try self.writeAtom(atom_index, code);
2383}
2384
2385pub fn getOrCreateAtomForLazySymbol(
2386 self: *MachO,
2387 lazy_sym: File.LazySymbol,
2388 alignment: u32,
2389) !Atom.Index {
2390 const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{
2391 .mod = self.base.options.module.?,
2392 });
2393 errdefer _ = self.lazy_syms.pop();
2394 if (!gop.found_existing) {
2395 gop.value_ptr.* = .{
2396 .atom = try self.createAtom(),
2397 .section = switch (lazy_sym.kind) {
2398 .code => self.text_section_index.?,
2399 .const_data => self.data_const_section_index.?,
2400 },
2401 };
2402 self.getAtomPtr(gop.value_ptr.atom).alignment = alignment;
2403 }
2404 return gop.value_ptr.atom;
2405}
2406
2285pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index {2407pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index {
2286 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);2408 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2287 if (!gop.found_existing) {2409 if (!gop.found_existing) {
test/behavior/align.zig-3
...@@ -271,7 +271,6 @@ fn sliceExpects4(slice: []align(4) u32) void {...@@ -271,7 +271,6 @@ fn sliceExpects4(slice: []align(4) u32) void {
271271
272test "return error union with 128-bit integer" {272test "return error union with 128-bit integer" {
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
274 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;274 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO275 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
277276
...@@ -477,7 +476,6 @@ const DefaultAligned = struct {...@@ -477,7 +476,6 @@ const DefaultAligned = struct {
477476
478test "read 128-bit field from default aligned struct in stack memory" {477test "read 128-bit field from default aligned struct in stack memory" {
479 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;478 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
480 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
481 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;479 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
482 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO480 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
483481
...@@ -494,7 +492,6 @@ var default_aligned_global = DefaultAligned{...@@ -494,7 +492,6 @@ var default_aligned_global = DefaultAligned{
494};492};
495493
496test "read 128-bit field from default aligned struct in global memory" {494test "read 128-bit field from default aligned struct in global memory" {
497 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;496 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO497 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/basic.zig-8
...@@ -39,7 +39,6 @@ test "truncate to non-power-of-two integers" {...@@ -39,7 +39,6 @@ test "truncate to non-power-of-two integers" {
3939
40test "truncate to non-power-of-two integers from 128-bit" {40test "truncate to non-power-of-two integers from 128-bit" {
41 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO41 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO43 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO44 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -345,7 +344,6 @@ fn copy(src: *const u64, dst: *u64) void {...@@ -345,7 +344,6 @@ fn copy(src: *const u64, dst: *u64) void {
345test "call result of if else expression" {344test "call result of if else expression" {
346 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
347 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
348 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
349 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO347 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350348
351 try expect(mem.eql(u8, f2(true), "a"));349 try expect(mem.eql(u8, f2(true), "a"));
...@@ -663,7 +661,6 @@ test "multiline string literal is null terminated" {...@@ -663,7 +661,6 @@ test "multiline string literal is null terminated" {
663test "string escapes" {661test "string escapes" {
664 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;662 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;663 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
666 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
667 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO664 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
668665
669 try expectEqualStrings("\"", "\x22");666 try expectEqualStrings("\"", "\x22");
...@@ -682,8 +679,6 @@ test "explicit cast optional pointers" {...@@ -682,8 +679,6 @@ test "explicit cast optional pointers" {
682}679}
683680
684test "pointer comparison" {681test "pointer comparison" {
685 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
686
687 const a = @as([]const u8, "a");682 const a = @as([]const u8, "a");
688 const b = &a;683 const b = &a;
689 try expect(ptrEql(b, b));684 try expect(ptrEql(b, b));
...@@ -695,7 +690,6 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool {...@@ -695,7 +690,6 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
695test "string concatenation" {690test "string concatenation" {
696 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;691 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
697 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;692 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
698 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
699 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO693 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
700694
701 const a = "OK" ++ " IT " ++ "WORKED";695 const a = "OK" ++ " IT " ++ "WORKED";
...@@ -916,7 +910,6 @@ test "vector initialized with array init syntax has proper type" {...@@ -916,7 +910,6 @@ test "vector initialized with array init syntax has proper type" {
916}910}
917911
918test "weird array and tuple initializations" {912test "weird array and tuple initializations" {
919 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
920 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO913 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
921 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO914 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
922 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO915 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1060,7 +1053,6 @@ test "inline call of function with a switch inside the return statement" {...@@ -1060,7 +1053,6 @@ test "inline call of function with a switch inside the return statement" {
10601053
1061test "namespace lookup ignores decl causing the lookup" {1054test "namespace lookup ignores decl causing the lookup" {
1062 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1055 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1063 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1064 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1056 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1065 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1057 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10661058
test/behavior/bitcast.zig-1
...@@ -20,7 +20,6 @@ test "@bitCast iX -> uX (32, 64)" {...@@ -20,7 +20,6 @@ test "@bitCast iX -> uX (32, 64)" {
2020
21test "@bitCast iX -> uX (8, 16, 128)" {21test "@bitCast iX -> uX (8, 16, 128)" {
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2625
test/behavior/bugs/6047.zig-1
...@@ -11,7 +11,6 @@ fn getError2() !void {...@@ -11,7 +11,6 @@ fn getError2() !void {
1111
12test "`try`ing an if/else expression" {12test "`try`ing an if/else expression" {
13 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO14 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/6905.zig-1
...@@ -3,7 +3,6 @@ const builtin = @import("builtin");...@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33
4test "sentinel-terminated 0-length slices" {4test "sentinel-terminated 0-length slices" {
5 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO5 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/9584.zig-1
...@@ -47,7 +47,6 @@ test {...@@ -47,7 +47,6 @@ test {
47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5150
52 var flags = A{51 var flags = A{
53 .a = false,52 .a = false,
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1
...@@ -8,7 +8,6 @@ var x: u8 = 1;...@@ -8,7 +8,6 @@ var x: u8 = 1;
8test {8test {
9 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/cast.zig-1
...@@ -1178,7 +1178,6 @@ fn castToOptionalSlice() ?[]const u8 {...@@ -1178,7 +1178,6 @@ fn castToOptionalSlice() ?[]const u8 {
1178test "cast u128 to f128 and back" {1178test "cast u128 to f128 and back" {
1179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1181 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1182 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1181 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1183 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1182 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11841183
test/behavior/cast_int.zig-1
...@@ -5,7 +5,6 @@ const maxInt = std.math.maxInt;...@@ -5,7 +5,6 @@ const maxInt = std.math.maxInt;
55
6test "@intCast i32 to u7" {6test "@intCast i32 to u7" {
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/defer.zig-1
...@@ -110,7 +110,6 @@ test "mixing normal and error defers" {...@@ -110,7 +110,6 @@ test "mixing normal and error defers" {
110}110}
111111
112test "errdefer with payload" {112test "errdefer with payload" {
113 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
116 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/error.zig-4
...@@ -561,7 +561,6 @@ test "error union comptime caching" {...@@ -561,7 +561,6 @@ test "error union comptime caching" {
561}561}
562562
563test "@errorName" {563test "@errorName" {
564 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;564 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
566 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
567 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -575,7 +574,6 @@ fn gimmeItBroke() anyerror {...@@ -575,7 +574,6 @@ fn gimmeItBroke() anyerror {
575}574}
576575
577test "@errorName sentinel length matches slice length" {576test "@errorName sentinel length matches slice length" {
578 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
579 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;577 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
580 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;578 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
581 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO579 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -799,7 +797,6 @@ test "error union of noreturn used with catch" {...@@ -799,7 +797,6 @@ test "error union of noreturn used with catch" {
799}797}
800798
801test "alignment of wrapping an error union payload" {799test "alignment of wrapping an error union payload" {
802 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
803 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;800 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
804 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
805 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO802 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -851,7 +848,6 @@ test "catch within a function that calls no errorable functions" {...@@ -851,7 +848,6 @@ test "catch within a function that calls no errorable functions" {
851test "error from comptime string" {848test "error from comptime string" {
852 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO849 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
853 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO850 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
854 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
855 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO851 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
856852
857 const name = "Weird error name!";853 const name = "Weird error name!";
test/behavior/eval.zig-1
...@@ -458,7 +458,6 @@ test "binary math operator in partially inlined function" {...@@ -458,7 +458,6 @@ test "binary math operator in partially inlined function" {
458458
459test "comptime shl" {459test "comptime shl" {
460 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO460 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
461 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
462 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO461 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO462 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO463 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/int128.zig-4
...@@ -5,7 +5,6 @@ const minInt = std.math.minInt;...@@ -5,7 +5,6 @@ const minInt = std.math.minInt;
5const builtin = @import("builtin");5const builtin = @import("builtin");
66
7test "uint128" {7test "uint128" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -24,7 +23,6 @@ test "uint128" {...@@ -24,7 +23,6 @@ test "uint128" {
24}23}
2524
26test "undefined 128 bit int" {25test "undefined 128 bit int" {
27 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO26 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -42,7 +40,6 @@ test "undefined 128 bit int" {...@@ -42,7 +40,6 @@ test "undefined 128 bit int" {
42}40}
4341
44test "int128" {42test "int128" {
45 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -87,7 +84,6 @@ test "truncate int128" {...@@ -87,7 +84,6 @@ test "truncate int128" {
8784
88test "shift int128" {85test "shift int128" {
89 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO86 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
90 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
91 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
93 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO89 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/int_div.zig-1
...@@ -97,7 +97,6 @@ test "large integer division" {...@@ -97,7 +97,6 @@ test "large integer division" {
97 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;97 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
100 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
101100
102 {101 {
103 var numerator: u256 = 99999999999999999997315645440;102 var numerator: u256 = 99999999999999999997315645440;
test/behavior/optional.zig-2
...@@ -412,7 +412,6 @@ test "orelse on C pointer" {...@@ -412,7 +412,6 @@ test "orelse on C pointer" {
412}412}
413413
414test "alignment of wrapping an optional payload" {414test "alignment of wrapping an optional payload" {
415 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
416 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;415 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
417 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
418 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -468,7 +467,6 @@ test "peer type resolution in nested if expressions" {...@@ -468,7 +467,6 @@ test "peer type resolution in nested if expressions" {
468test "cast slice to const slice nested in error union and optional" {467test "cast slice to const slice nested in error union and optional" {
469 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
471 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
472470
473 const S = struct {471 const S = struct {
474 fn inner() !?[]u8 {472 fn inner() !?[]u8 {
test/behavior/packed-struct.zig-2
...@@ -352,7 +352,6 @@ test "byte-aligned field pointer offsets" {...@@ -352,7 +352,6 @@ test "byte-aligned field pointer offsets" {
352}352}
353353
354test "load pointer from packed struct" {354test "load pointer from packed struct" {
355 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
356 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;355 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
357 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
358 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -585,7 +584,6 @@ test "overaligned pointer to packed struct" {...@@ -585,7 +584,6 @@ test "overaligned pointer to packed struct" {
585test "packed struct initialized in bitcast" {584test "packed struct initialized in bitcast" {
586 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
587 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO586 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
588 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
589587
590 const T = packed struct { val: u8 };588 const T = packed struct { val: u8 };
591 var val: u8 = 123;589 var val: u8 = 123;
test/behavior/pointers.zig-1
...@@ -160,7 +160,6 @@ test "implicit casting between C pointer and optional non-C pointer" {...@@ -160,7 +160,6 @@ test "implicit casting between C pointer and optional non-C pointer" {
160}160}
161161
162test "implicit cast error unions with non-optional to optional pointer" {162test "implicit cast error unions with non-optional to optional pointer" {
163 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
164 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
165 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO165 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/struct.zig-2
...@@ -800,7 +800,6 @@ test "fn with C calling convention returns struct by value" {...@@ -800,7 +800,6 @@ test "fn with C calling convention returns struct by value" {
800}800}
801801
802test "non-packed struct with u128 entry in union" {802test "non-packed struct with u128 entry in union" {
803 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
804 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO803 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
805 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO804 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
806 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO805 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1244,7 +1243,6 @@ test "loading a struct pointer perfoms a copy" {...@@ -1244,7 +1243,6 @@ test "loading a struct pointer perfoms a copy" {
1244}1243}
12451244
1246test "packed struct aggregate init" {1245test "packed struct aggregate init" {
1247 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1246 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1247 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1248 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/switch.zig-1
...@@ -419,7 +419,6 @@ test "switch on integer with else capturing expr" {...@@ -419,7 +419,6 @@ test "switch on integer with else capturing expr" {
419}419}
420420
421test "else prong of switch on error set excludes other cases" {421test "else prong of switch on error set excludes other cases" {
422 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO422 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
424 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
425 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO424 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/typename.zig-6
...@@ -12,7 +12,6 @@ const expectStringStartsWith = std.testing.expectStringStartsWith;...@@ -12,7 +12,6 @@ const expectStringStartsWith = std.testing.expectStringStartsWith;
12// failures.12// failures.
1313
14test "anon fn param" {14test "anon fn param" {
15 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -38,7 +37,6 @@ test "anon fn param" {...@@ -38,7 +37,6 @@ test "anon fn param" {
38}37}
3938
40test "anon field init" {39test "anon field init" {
41 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO40 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO41 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -87,7 +85,6 @@ test "basic" {...@@ -87,7 +85,6 @@ test "basic" {
87}85}
8886
89test "top level decl" {87test "top level decl" {
90 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
91 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
93 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO90 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -137,7 +134,6 @@ const B = struct {...@@ -137,7 +134,6 @@ const B = struct {
137};134};
138135
139test "fn param" {136test "fn param" {
140 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
141 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO138 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
143 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO139 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -208,7 +204,6 @@ pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8)...@@ -208,7 +204,6 @@ pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8)
208}204}
209205
210test "local variable" {206test "local variable" {
211 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO207 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO208 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -236,7 +231,6 @@ test "comptime parameters not converted to anytype in function type" {...@@ -236,7 +231,6 @@ test "comptime parameters not converted to anytype in function type" {
236}231}
237232
238test "anon name strategy used in sub expression" {233test "anon name strategy used in sub expression" {
239 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO234 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
241 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO235 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
242 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO236 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/cases/aarch64-macos/hello_world_with_updates.0.zig+1-1
...@@ -2,4 +2,4 @@...@@ -2,4 +2,4 @@
2// output_mode=Exe2// output_mode=Exe
3// target=aarch64-macos3// target=aarch64-macos
4//4//
5// :108:9: error: root struct of file 'tmp' has no member named 'main'5// :110:9: error: root struct of file 'tmp' has no member named 'main'
test/cases/x86_64-linux/hello_world_with_updates.0.zig+1-1
...@@ -2,4 +2,4 @@...@@ -2,4 +2,4 @@
2// output_mode=Exe2// output_mode=Exe
3// target=x86_64-linux3// target=x86_64-linux
4//4//
5// :108:9: error: root struct of file 'tmp' has no member named 'main'5// :110:9: error: root struct of file 'tmp' has no member named 'main'
test/cases/x86_64-macos/hello_world_with_updates.0.zig+1-1
...@@ -2,4 +2,4 @@...@@ -2,4 +2,4 @@
2// output_mode=Exe2// output_mode=Exe
3// target=x86_64-macos3// target=x86_64-macos
4//4//
5// :108:9: error: root struct of file 'tmp' has no member named 'main'5// :110:9: error: root struct of file 'tmp' has no member named 'main'
test/cases/x86_64-windows/hello_world_with_updates.0.zig+1-1
...@@ -2,4 +2,4 @@...@@ -2,4 +2,4 @@
2// output_mode=Exe2// output_mode=Exe
3// target=x86_64-windows3// target=x86_64-windows
4//4//
5// :129:9: error: root struct of file 'tmp' has no member named 'main'5// :131:9: error: root struct of file 'tmp' has no member named 'main'