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 {
19371937 if (builtin.os.tag == .windows) {
19381938 @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.");
19391939 }
1940 // The simplified start logic doesn't populate environ.
1941 if (std.start.simplified_logic) return null;
19401942 // TODO see https://github.com/ziglang/zig/issues/4524
19411943 for (environ) |ptr| {
19421944 var line_i: usize = 0;
lib/std/start.zig+13-11
......@@ -14,22 +14,24 @@ var argc_argv_ptr: [*]usize = undefined;
1414
1515const 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
1729comptime {
1830 // No matter what, we import the root file, so that any export, test, comptime
1931 // decls there get run.
2032 _ = root;
2133
22 // The self-hosted compiler is not fully capable of handling all of this start.zig file.
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 {
34 if (simplified_logic) {
3335 if (builtin.output_mode == .Exe) {
3436 if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) {
3537 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
src/arch/x86_64/CodeGen.zig+784-505
......@@ -316,7 +316,7 @@ pub fn generate(
316316 defer function.mir_extra.deinit(bin_file.allocator);
317317 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) {
320320 error.CodegenFail => return Result{ .fail = function.err_msg.? },
321321 error.OutOfRegisters => return Result{
322322 .fail = try ErrorMsg.create(
......@@ -952,10 +952,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
952952 .neg,
953953 => try self.airUnaryMath(inst),
954954
955 .add_with_overflow => try self.airAddSubShlWithOverflow(inst),
956 .sub_with_overflow => try self.airAddSubShlWithOverflow(inst),
955 .add_with_overflow => try self.airAddSubWithOverflow(inst),
956 .sub_with_overflow => try self.airAddSubWithOverflow(inst),
957957 .mul_with_overflow => try self.airMulWithOverflow(inst),
958 .shl_with_overflow => try self.airAddSubShlWithOverflow(inst),
958 .shl_with_overflow => try self.airShlWithOverflow(inst),
959959
960960 .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
16251625 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
16261626}
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
16281663fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
16291664 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1630 const result = result: {
1631 if (self.liveness.isUnused(inst)) break :result .dead;
1632
1665 const result = if (self.liveness.isUnused(inst)) .dead else result: {
16331666 const tag = self.air.instructions.items(.tag)[inst];
1634 const ty = self.air.typeOfIndex(inst);
1635
1636 if (ty.zigTypeTag() == .Float) {
1667 const dst_ty = self.air.typeOfIndex(inst);
1668 if (dst_ty.zigTypeTag() == .Float)
16371669 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 });
16421687 const lhs = try self.resolveInst(bin_op.lhs);
16431688 const rhs = try self.resolveInst(bin_op.rhs);
1644
1645 break :result try self.genMulDivBinOp(tag, inst, ty, lhs, rhs);
1689 break :result try self.genMulDivBinOp(tag, inst, dst_ty, src_ty, lhs, rhs);
16461690 };
16471691 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
16481692}
......@@ -1795,7 +1839,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
17951839 break :cc .c;
17961840 };
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);
17991843 const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2));
18001844 try self.asmCmovccRegisterRegister(
18011845 registerAlias(dst_mcv.register, abi_size),
......@@ -1807,70 +1851,133 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
18071851 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
18081852}
18091853
1810fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1854fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
18111855 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1812 const tag = self.air.instructions.items(.tag)[inst];
18131856 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];
18151859 const ty = self.air.typeOf(bin_op.lhs);
1816 const abi_size = ty.abiSize(self.target.*);
18171860 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", .{}),
18191862 .Int => {
1820 if (abi_size > 8) {
1821 return self.fail("TODO implement add/sub/shl with overflow for Ints larger than 64bits", .{});
1822 }
1823
18241863 try self.spillEflagsIfOccupied();
18251864
1826 if (tag == .shl_with_overflow) {
1827 try self.spillRegisters(&.{.rcx});
1828 }
1829
1830 const partial: MCValue = switch (tag) {
1865 const partial_mcv = switch (tag) {
18311866 .add_with_overflow => try self.genBinOp(null, .add, bin_op.lhs, bin_op.rhs),
18321867 .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 },
18401868 else => unreachable,
18411869 };
1842
18431870 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) {
1846 self.eflags_inst = inst;
1876 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
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) {
1849 .unsigned => .c,
1850 .signed => .o,
1851 };
1852 break :result MCValue{ .register_overflow = .{
1853 .reg = partial.register,
1854 .eflags = cc,
1855 } };
1885 const abi_size = @intCast(i32, ty.abiSize(self.target.*));
1886 const dst_mcv = try self.allocRegOrMem(inst, false);
1887 try self.genSetStack(
1888 Type.u1,
1889 dst_mcv.stack_offset - abi_size,
1890 .{ .eflags = cc },
1891 .{},
1892 );
1893 try self.genSetStack(ty, dst_mcv.stack_offset, partial_mcv, .{});
1894 break :result dst_mcv;
18561895 }
18571896
1858 self.eflags_inst = null;
1859
18601897 const tuple_ty = self.air.typeOfIndex(inst);
18611898 const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*));
18621899 const tuple_align = tuple_ty.abiAlignment(self.target.*);
18631900 const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*));
18641901 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 };
18691906 },
18701907 else => unreachable,
18711908 }
18721909 };
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 };
18741981 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
18751982}
18761983
......@@ -1880,6 +1987,7 @@ fn genSetStackTruncatedOverflowCompare(
18801987 stack_offset: i32,
18811988 overflow_bit_offset: i32,
18821989 reg: Register,
1990 cc: Condition,
18831991) !void {
18841992 const reg_lock = self.register_manager.lockReg(reg);
18851993 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -1897,10 +2005,6 @@ fn genSetStackTruncatedOverflowCompare(
18972005 };
18982006
18992007 const overflow_reg = temp_regs[0];
1900 const cc: Condition = switch (int_info.signedness) {
1901 .signed => .o,
1902 .unsigned => .c,
1903 };
19042008 try self.asmSetccRegister(overflow_reg.to8(), cc);
19052009
19062010 const scratch_reg = temp_regs[1];
......@@ -1923,7 +2027,7 @@ fn genSetStackTruncatedOverflowCompare(
19232027 );
19242028
19252029 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, .{
19272031 .register = overflow_reg.to8(),
19282032 }, .{});
19292033}
......@@ -1931,48 +2035,56 @@ fn genSetStackTruncatedOverflowCompare(
19312035fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
19322036 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
19332037 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1934
1935 if (self.liveness.isUnused(inst)) {
1936 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
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()) {
2038 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2039 const dst_ty = self.air.typeOf(bin_op.lhs);
2040 switch (dst_ty.zigTypeTag()) {
19432041 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),
19442042 .Int => {
1945 if (abi_size > 8) {
1946 return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{});
1947 }
1948
1949 const int_info = ty.intInfo(self.target.*);
2043 try self.spillEflagsIfOccupied();
19502044
1951 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
1952 try self.spillEflagsIfOccupied();
1953 self.eflags_inst = inst;
2045 const dst_info = dst_ty.intInfo(self.target.*);
2046 const cc: Condition = switch (dst_info.signedness) {
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
19552061 try self.spillRegisters(&.{ .rax, .rdx });
1956
19572062 const lhs = try self.resolveInst(bin_op.lhs);
19582063 const rhs = try self.resolveInst(bin_op.rhs);
19592064
1960 const partial = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs);
1961 const cc: Condition = switch (int_info.signedness) {
1962 .unsigned => .c,
1963 .signed => .o,
1964 };
1965 break :result MCValue{ .register_overflow = .{
1966 .reg = partial.register,
1967 .eflags = cc,
1968 } };
1969 }
2065 const partial_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs);
2066 switch (partial_mcv) {
2067 .register => |reg| {
2068 self.eflags_inst = inst;
2069 break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } };
2070 },
2071 else => {},
2072 }
19702073
1971 try self.spillEflagsIfOccupied();
1972 self.eflags_inst = null;
2074 const dst_abi_size = @intCast(i32, dst_ty.abiSize(self.target.*));
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
19742086 const dst_reg: Register = dst_reg: {
1975 switch (int_info.signedness) {
2087 switch (dst_info.signedness) {
19762088 .signed => {
19772089 const lhs = try self.resolveInst(bin_op.lhs);
19782090 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -1985,14 +2097,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
19852097
19862098 const dst_reg: Register = blk: {
19872099 if (lhs.isRegister()) break :blk lhs.register;
1988 break :blk try self.copyToTmpRegister(ty, lhs);
2100 break :blk try self.copyToTmpRegister(dst_ty, lhs);
19892101 };
19902102 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
19912103 defer self.register_manager.unlockReg(dst_reg_lock);
19922104
19932105 const rhs_mcv: MCValue = blk: {
19942106 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) };
19962108 };
19972109 const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) {
19982110 .register => |reg| self.register_manager.lockReg(reg),
......@@ -2010,7 +2122,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
20102122 const lhs = try self.resolveInst(bin_op.lhs);
20112123 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);
20142126 break :dst_reg dst_mcv.register;
20152127 },
20162128 }
......@@ -2022,14 +2134,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
20222134 const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*));
20232135 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 };
20282140 },
20292141 else => unreachable,
20302142 }
20312143 };
2032
20332144 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
20342145}
20352146
......@@ -2040,7 +2151,6 @@ fn genIntMulDivOpMir(
20402151 self: *Self,
20412152 tag: Mir.Inst.Tag,
20422153 ty: Type,
2043 signedness: std.builtin.Signedness,
20442154 lhs: MCValue,
20452155 rhs: MCValue,
20462156) !void {
......@@ -2057,26 +2167,23 @@ fn genIntMulDivOpMir(
20572167 try self.genSetReg(ty, .rax, lhs);
20582168 }
20592169
2060 switch (signedness) {
2061 .signed => try self.asmOpOnly(.cqo),
2062 .unsigned => try self.asmRegisterRegister(.xor, .rdx, .rdx),
2170 switch (tag) {
2171 else => unreachable,
2172 .mul, .imul => {},
2173 .div => try self.asmRegisterRegister(.xor, .edx, .edx),
2174 .idiv => try self.asmOpOnly(.cqo),
20632175 }
20642176
2065 const factor = switch (rhs) {
2066 .register => rhs,
2067 .stack_offset => rhs,
2068 else => blk: {
2069 const reg = try self.copyToTmpRegister(ty, rhs);
2070 break :blk MCValue{ .register = reg };
2071 },
2177 const factor: MCValue = switch (rhs) {
2178 .register, .stack_offset => rhs,
2179 else => .{ .register = try self.copyToTmpRegister(ty, rhs) },
20722180 };
2073
20742181 switch (factor) {
20752182 .register => |reg| try self.asmRegister(tag, reg),
2076 .stack_offset => |off| try self.asmMemory(tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
2077 .base = .rbp,
2078 .disp = -off,
2079 })),
2183 .stack_offset => |off| try self.asmMemory(tag, Memory.sib(
2184 Memory.PtrSize.fromSize(abi_size),
2185 .{ .base = .rbp, .disp = -off },
2186 )),
20802187 else => unreachable,
20812188 }
20822189}
......@@ -2102,7 +2209,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
21022209 try self.genIntMulDivOpMir(switch (signedness) {
21032210 .signed => .idiv,
21042211 .unsigned => .div,
2105 }, Type.isize, signedness, .{ .register = dividend }, .{ .register = divisor });
2212 }, Type.isize, .{ .register = dividend }, .{ .register = divisor });
21062213
21072214 try self.asmRegisterRegister(.xor, divisor.to64(), dividend.to64());
21082215 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
38183925fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
38193926 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
38203927 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
3821 const operand = extra.struct_operand;
3822 const index = extra.field_index;
3928 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
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)) {
3825 return self.finishAir(inst, .dead, .{ extra.struct_operand, .none, .none });
3826 }
3945 switch (src_mcv) {
3946 .stack_offset => |src_off| {
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);
3829 const container_ty = self.air.typeOf(operand);
3830 const field_ty = container_ty.structFieldType(index);
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 };
3962 if (field_abi_size > 8) {
3963 return self.fail("TODO implement struct_field_val with large packed field", .{});
3964 }
38383965
3839 const result: MCValue = result: {
3840 switch (mcv) {
3841 .stack_offset => |off| {
3842 const byte_offset = std.math.divExact(u32, field_bit_offset, 8) catch
3843 return self.fail("TODO implement struct_field_val for a packed struct", .{});
3844 break :result MCValue{ .stack_offset = off - @intCast(i32, byte_offset) };
3966 const dst_reg = try self.register_manager.allocReg(inst, gp);
3967 const field_extra_bits = self.regExtraBits(field_ty);
3968 const load_abi_size =
3969 if (field_bit_off < field_extra_bits) field_abi_size else field_abi_size * 2;
3970 if (load_abi_size <= 8) {
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 };
38454004 },
38464005 .register => |reg| {
38474006 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
38484007 defer self.register_manager.unlockReg(reg_lock);
38494008
3850 const dst_mcv: MCValue = blk: {
3851 if (self.reuseOperand(inst, operand, 0, mcv)) {
3852 break :blk mcv;
3853 } else {
3854 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, Type.usize, .{
3855 .register = reg.to64(),
3856 });
3857 break :blk dst_mcv;
3858 }
3859 };
4009 const dst_mcv = if (self.reuseOperand(inst, operand, 0, src_mcv))
4010 src_mcv
4011 else
4012 try self.copyToRegisterWithInstTracking(
4013 inst,
4014 Type.usize,
4015 .{ .register = reg.to64() },
4016 );
38604017 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
38614018 .register => |a_reg| self.register_manager.lockReg(a_reg),
38624019 else => null,
......@@ -3864,7 +4021,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
38644021 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
38654022
38664023 // 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
38694026 // Mask to field_bit_size bits
38704027 const field_bit_size = field_ty.bitSize(self.target.*);
......@@ -3883,31 +4040,34 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
38834040 registerAlias(dst_mcv.register, field_byte_size),
38844041 );
38854042 }
3886
38874043 break :result dst_mcv;
38884044 },
38894045 .register_overflow => |ro| {
38904046 switch (index) {
3891 0 => {
3892 // Get wrapped value for overflow operation.
3893 break :result MCValue{ .register = ro.reg };
3894 },
3895 1 => {
3896 // Get overflow bit.
3897 const reg_lock = self.register_manager.lockRegAssumeUnused(ro.reg);
3898 defer self.register_manager.unlockReg(reg_lock);
3899
4047 // Get wrapped value for overflow operation.
4048 0 => break :result if (self.liveness.operandDies(inst, 0))
4049 .{ .register = ro.reg }
4050 else
4051 try self.copyToRegisterWithInstTracking(
4052 inst,
4053 Type.usize,
4054 .{ .register = ro.reg },
4055 ),
4056 // Get overflow bit.
4057 1 => if (self.liveness.operandDies(inst, 0)) {
4058 self.eflags_inst = inst;
4059 break :result .{ .eflags = ro.eflags };
4060 } else {
39004061 const dst_reg = try self.register_manager.allocReg(inst, gp);
39014062 try self.asmSetccRegister(dst_reg.to8(), ro.eflags);
3902 break :result MCValue{ .register = dst_reg.to8() };
4063 break :result .{ .register = dst_reg.to8() };
39034064 },
39044065 else => unreachable,
39054066 }
39064067 },
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}),
39084069 }
39094070 };
3910
39114071 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
39124072}
39134073
......@@ -3986,7 +4146,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
39864146 .eflags => unreachable,
39874147 .register_overflow => unreachable,
39884148 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
3989 .ptr_stack_offset, .stack_offset => |off| {
4149 .stack_offset => |off| {
39904150 if (abi_size > 8) {
39914151 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});
39924152 }
......@@ -3996,20 +4156,13 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
39964156 .disp = -off,
39974157 }));
39984158 },
4159 .ptr_stack_offset => unreachable,
39994160 .memory, .linker_load => {
40004161 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
40014162 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
40024163 defer self.register_manager.unlockReg(addr_reg_lock);
40034164
40044165 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
40134166 try self.asmMemory(
40144167 mir_tag,
40154168 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }),
......@@ -4272,20 +4425,26 @@ fn genMulDivBinOp(
42724425 self: *Self,
42734426 tag: Air.Inst.Tag,
42744427 maybe_inst: ?Air.Inst.Index,
4275 ty: Type,
4428 dst_ty: Type,
4429 src_ty: Type,
42764430 lhs: MCValue,
42774431 rhs: MCValue,
42784432) !MCValue {
4279 if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) {
4280 return self.fail("TODO implement genMulDivBinOp for {}", .{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", .{});
4433 if (dst_ty.zigTypeTag() == .Vector or dst_ty.zigTypeTag() == .Float) {
4434 return self.fail("TODO implement genMulDivBinOp for {}", .{dst_ty.fmtDebug()});
42884435 }
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
42904449 assert(self.register_manager.isRegFree(.rax));
42914450 assert(self.register_manager.isRegFree(.rdx));
......@@ -4293,9 +4452,7 @@ fn genMulDivBinOp(
42934452 const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
42944453 defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
42954454
4296 const int_info = ty.intInfo(self.target.*);
4297 const signedness = int_info.signedness;
4298
4455 const signedness = ty.intInfo(self.target.*).signedness;
42994456 switch (tag) {
43004457 .mul,
43014458 .mulwrap,
......@@ -4303,11 +4460,12 @@ fn genMulDivBinOp(
43034460 .div_trunc,
43044461 .div_exact,
43054462 => {
4306 const track_inst_rax: ?Air.Inst.Index = switch (tag) {
4307 .mul, .mulwrap, .div_exact, .div_trunc => maybe_inst,
4463 const track_inst_rax = switch (tag) {
4464 .mul, .mulwrap => if (dst_abi_size <= 8) maybe_inst else null,
4465 .div_exact, .div_trunc => maybe_inst,
43084466 else => null,
43094467 };
4310 const track_inst_rdx: ?Air.Inst.Index = switch (tag) {
4468 const track_inst_rdx = switch (tag) {
43114469 .rem => maybe_inst,
43124470 else => null,
43134471 };
......@@ -4327,13 +4485,24 @@ fn genMulDivBinOp(
43274485 },
43284486 };
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) {
43334491 .mul, .mulwrap, .div_trunc, .div_exact => .rax,
43344492 .rem => .rdx,
43354493 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;
43374506 },
43384507
43394508 .mod => {
......@@ -4356,7 +4525,7 @@ fn genMulDivBinOp(
43564525 return result;
43574526 },
43584527 .unsigned => {
4359 try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs);
4528 try self.genIntMulDivOpMir(.div, ty, lhs, rhs);
43604529 return .{ .register = registerAlias(.rdx, abi_size) };
43614530 },
43624531 }
......@@ -4395,18 +4564,13 @@ fn genMulDivBinOp(
43954564 };
43964565 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
43974566
4398 const result: MCValue = result: {
4399 switch (signedness) {
4400 .signed => break :result try self.genInlineIntDivFloor(ty, lhs, actual_rhs),
4401 .unsigned => {
4402 try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, actual_rhs);
4403 break :result MCValue{
4404 .register = registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))),
4405 };
4406 },
4407 }
4408 };
4409 return result;
4567 switch (signedness) {
4568 .signed => return try self.genInlineIntDivFloor(ty, lhs, actual_rhs),
4569 .unsigned => {
4570 try self.genIntMulDivOpMir(.div, ty, lhs, actual_rhs);
4571 return .{ .register = registerAlias(.rax, abi_size) };
4572 },
4573 }
44104574 },
44114575
44124576 else => unreachable,
......@@ -4454,7 +4618,7 @@ fn genBinOp(
44544618
44554619 else => false,
44564620 };
4457 const needs_reg_dst = switch (tag) {
4621 const dst_mem_ok = switch (tag) {
44584622 .add,
44594623 .addwrap,
44604624 .sub,
......@@ -4464,9 +4628,9 @@ fn genBinOp(
44644628 .div_exact,
44654629 .div_trunc,
44664630 .div_floor,
4467 => lhs_ty.isRuntimeFloat(),
4631 => !lhs_ty.isRuntimeFloat(),
44684632
4469 else => false,
4633 else => true,
44704634 };
44714635
44724636 const lhs_lock: ?RegisterLock = switch (lhs) {
......@@ -4482,18 +4646,21 @@ fn genBinOp(
44824646 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
44834647
44844648 var flipped: bool = false;
4485 const dst_mcv: MCValue = blk: {
4649 const dst_mcv: MCValue = dst: {
44864650 if (maybe_inst) |inst| {
4487 if ((!needs_reg_dst or lhs.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs)) {
4488 break :blk lhs;
4651 if ((dst_mem_ok or lhs.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs)) {
4652 break :dst lhs;
44894653 }
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 {
44914657 flipped = true;
4492 break :blk rhs;
4658 break :dst rhs;
44934659 }
4494 break :blk try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs);
44954660 }
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;
44974664 };
44984665 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
44994666 .register => |reg| self.register_manager.lockReg(reg),
......@@ -4501,17 +4668,7 @@ fn genBinOp(
45014668 };
45024669 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
45034670
4504 const src_mcv: MCValue = blk: {
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
4671 const src_mcv = if (flipped) lhs else rhs;
45154672 switch (tag) {
45164673 .add,
45174674 .addwrap,
......@@ -4573,14 +4730,18 @@ fn genBinOp(
45734730 .ptr_add,
45744731 .ptr_sub,
45754732 => {
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) {
45774741 .ptr_add => .add,
45784742 .ptr_sub => .sub,
45794743 else => unreachable,
4580 };
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);
4744 }, lhs_ty, dst_mcv, tmp_mcv);
45844745 },
45854746
45864747 .bool_or,
......@@ -4657,16 +4818,8 @@ fn genBinOp(
46574818 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
46584819 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
46594820 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);
46704823 try self.asmCmovccRegisterMemory(
46714824 registerAlias(tmp_reg, abi_size),
46724825 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
47064859 .eflags => unreachable,
47074860 .register_overflow => unreachable,
47084861 .register => |dst_reg| {
4862 const dst_alias = registerAlias(dst_reg, abi_size);
47094863 switch (src_mcv) {
47104864 .none => unreachable,
47114865 .undef => unreachable,
......@@ -4728,41 +4882,47 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
47284882 },
47294883 else => try self.asmRegisterRegister(
47304884 mir_tag,
4731 registerAlias(dst_reg, abi_size),
4885 dst_alias,
47324886 registerAlias(src_reg, abi_size),
47334887 ),
47344888 },
47354889 .immediate => |imm| {
47364890 switch (self.regBitSize(ty)) {
4737 8, 16, 32 => {
4738 try self.asmRegisterImmediate(
4739 mir_tag,
4740 registerAlias(dst_reg, abi_size),
4891 8 => try self.asmRegisterImmediate(
4892 mir_tag,
4893 dst_alias,
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
47414913 Immediate.u(@intCast(u32, imm)),
4742 );
4743 },
4744 64 => {
4745 if (math.cast(i32, @bitCast(i64, imm))) |small| {
4746 try self.asmRegisterImmediate(
4747 mir_tag,
4748 registerAlias(dst_reg, abi_size),
4749 Immediate.s(small),
4750 );
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", .{}),
4914 ),
4915 64 => if (math.cast(i32, @bitCast(i64, imm))) |small|
4916 try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small))
4917 else
4918 try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias(
4919 try self.copyToTmpRegister(ty, src_mcv),
4920 abi_size,
4921 )),
4922 else => unreachable,
47604923 }
47614924 },
4762 .memory,
4763 .linker_load,
4764 .eflags,
4765 => {
4925 .memory, .linker_load, .eflags => {
47664926 assert(abi_size <= 8);
47674927 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
47684928 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
47794939 },
47804940 }
47814941 },
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
47834963 const src: ?struct {
47844964 limb_reg: Register,
47854965 limb_lock: RegisterLock,
......@@ -4787,7 +4967,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
47874967 addr_lock: RegisterLock,
47884968 } = switch (src_mcv) {
47894969 else => null,
4790 .memory, .linker_load => addr: {
4970 .memory, .linker_load => src: {
47914971 const src_limb_reg = try self.register_manager.allocReg(null, gp);
47924972 const src_limb_lock = self.register_manager.lockRegAssumeUnused(src_limb_reg);
47934973 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
47974977 errdefer self.register_manager.unlockReg(src_addr_lock);
47984978
47994979 try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_mcv);
4800 // To get the actual address of the value we want to modify we
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 .{
4980 break :src .{
48094981 .addr_reg = src_addr_reg,
48104982 .addr_lock = src_addr_lock,
48114983 .limb_reg = src_limb_reg,
......@@ -4831,7 +5003,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
48315003 0 => mir_tag,
48325004 else => switch (mir_tag) {
48335005 .add => .adc,
4834 .sub => .sbb,
5006 .sub, .cmp => .sbb,
48355007 .@"or", .@"and", .xor => mir_tag,
48365008 else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{
48375009 @tagName(mir_tag),
......@@ -4840,7 +5012,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
48405012 };
48415013 const dst_limb_mem = Memory.sib(
48425014 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 },
48445023 );
48455024 switch (src_mcv) {
48465025 .none => unreachable,
......@@ -4861,34 +5040,45 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
48615040 .unsigned => 0,
48625041 };
48635042 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|
48655068 try self.asmMemoryImmediate(
48665069 mir_limb_tag,
48675070 dst_limb_mem,
4868 if (math.cast(i32, @bitCast(i64, imm))) |small|
4869 Immediate.s(small)
4870 else
4871 Immediate.u(@intCast(u32, imm)),
4872 );
4873 },
4874 64 => {
4875 if (math.cast(i32, @bitCast(i64, imm))) |small| {
4876 try self.asmMemoryImmediate(
4877 mir_limb_tag,
4878 dst_limb_mem,
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 },
5071 Immediate.s(small),
5072 )
5073 else
5074 try self.asmMemoryRegister(
5075 mir_limb_tag,
5076 dst_limb_mem,
5077 registerAlias(
5078 try self.copyToTmpRegister(limb_ty, .{ .immediate = imm }),
5079 limb_abi_size,
5080 ),
5081 ),
48925082 else => unreachable,
48935083 }
48945084 },
......@@ -4930,12 +5120,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
49305120 }
49315121 }
49325122 },
4933 .memory => {
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 },
5123 .ptr_stack_offset => unreachable,
49395124 }
49405125}
49415126
......@@ -5191,7 +5376,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
51915376 else => unreachable,
51925377 };
51935378
5194 var info = try self.resolveCallingConventionValues(fn_ty);
5379 var info = try self.resolveCallingConventionValues(fn_ty, args[fn_ty.fnParamLen()..]);
51955380 defer info.deinit(self);
51965381
51975382 try self.spillEflagsIfOccupied();
......@@ -5280,8 +5465,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
52805465
52815466 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
52825467 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
5283 const atom = elf_file.getAtom(atom_index);
5284 const got_addr = atom.getOffsetTableAddress(elf_file);
5468 const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file);
52855469 try self.asmMemory(.call, Memory.sib(.qword, .{
52865470 .base = .ds,
52875471 .disp = @intCast(i32, got_addr),
......@@ -5289,22 +5473,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
52895473 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
52905474 const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
52915475 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
5292 try self.genSetReg(Type.initTag(.usize), .rax, .{
5293 .linker_load = .{
5294 .type = .got,
5295 .sym_index = sym_index,
5296 },
5297 });
5476 try self.genSetReg(Type.usize, .rax, .{ .linker_load = .{
5477 .type = .got,
5478 .sym_index = sym_index,
5479 } });
52985480 try self.asmRegister(.call, .rax);
52995481 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
53005482 const atom_index = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
53015483 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
5302 try self.genSetReg(Type.initTag(.usize), .rax, .{
5303 .linker_load = .{
5304 .type = .got,
5305 .sym_index = sym_index,
5306 },
5307 });
5484 try self.genSetReg(Type.usize, .rax, .{ .linker_load = .{
5485 .type = .got,
5486 .sym_index = sym_index,
5487 } });
53085488 try self.asmRegister(.call, .rax);
53095489 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
53105490 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
53255505 const lib_name = mem.sliceTo(extern_fn.lib_name, 0);
53265506 if (self.bin_file.cast(link.File.Coff)) |coff_file| {
53275507 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, .{
53295509 .linker_load = .{
53305510 .type = .import,
53315511 .sym_index = sym_index,
......@@ -5353,7 +5533,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
53535533 } else {
53545534 assert(ty.zigTypeTag() == .Pointer);
53555535 const mcv = try self.resolveInst(callee);
5356 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
5536 try self.genSetReg(Type.usize, .rax, mcv);
53575537 try self.asmRegister(.call, .rax);
53585538 }
53595539
......@@ -5457,79 +5637,61 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
54575637
54585638fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
54595639 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)) {
5462 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
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;
5645 try self.spillEflagsIfOccupied();
5646 self.eflags_inst = inst;
54795647
5480 const result: MCValue = result: {
5481 // There are 2 operands, destination and source.
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) {
5648 const lhs_mcv = try self.resolveInst(bin_op.lhs);
5649 const lhs_lock = switch (lhs_mcv) {
54875650 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
54885651 else => null,
54895652 };
54905653 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
54915654
5492 const dst_reg = try self.copyToTmpRegister(ty, lhs);
5493 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
5494 defer self.register_manager.unlockReg(dst_reg_lock);
5495
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 }
5655 const rhs_mcv = try self.resolveInst(bin_op.rhs);
5656 const rhs_lock = switch (rhs_mcv) {
5657 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
5658 else => null,
55145659 };
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) {
55165678 .register => |reg| self.register_manager.lockReg(reg),
55175679 else => null,
55185680 };
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;
55215684 try self.genBinOpMir(switch (ty.tag()) {
55225685 else => .cmp,
55235686 .f32 => .ucomiss,
55245687 .f64 => .ucomisd,
55255688 }, ty, dst_mcv, src_mcv);
55265689
5527 break :result switch (signedness) {
5528 .signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) },
5529 .unsigned => MCValue{ .eflags = Condition.fromCompareOperatorUnsigned(op) },
5690 const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;
5691 break :result .{
5692 .eflags = Condition.fromCompareOperator(signedness, if (flipped) op.reverse() else op),
55305693 };
55315694 };
5532
55335695 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
55345696}
55355697
......@@ -5790,13 +5952,6 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
57905952
57915953 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
58005955 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
58015956 try self.asmMemoryImmediate(.cmp, Memory.sib(
58025957 Memory.PtrSize.fromSize(some_abi_size),
......@@ -6681,6 +6836,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
66816836}
66826837
66836838fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: InlineMemcpyOpts) InnerError!void {
6839 const base_reg = opts.dest_stack_base orelse .rbp;
66846840 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
66856841 switch (mcv) {
66866842 .dead => unreachable,
......@@ -6696,12 +6852,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
66966852 4 => 0xaaaaaaaa,
66976853 else => unreachable,
66986854 };
6699 return self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
6700 .base = opts.dest_stack_base orelse .rbp,
6701 .disp = -stack_offset,
6702 }), Immediate.u(value));
6855 return self.asmMemoryImmediate(.mov, Memory.sib(
6856 Memory.PtrSize.fromSize(abi_size),
6857 .{ .base = base_reg, .disp = -stack_offset },
6858 ), Immediate.u(value));
67036859 },
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 ),
67056866 else => |x| return self.genInlineMemset(
67066867 .{ .stack_offset = stack_offset },
67076868 .{ .immediate = 0xaa },
......@@ -6729,12 +6890,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
67296890 .{},
67306891 );
67316892 },
6732 .eflags => {
6733 const reg = try self.copyToTmpRegister(ty, mcv);
6734 return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts);
6735 },
6736 .immediate => |x_big| {
6737 const base_reg = opts.dest_stack_base orelse .rbp;
6893 .eflags => |cc| try self.asmSetccMemory(
6894 Memory.sib(.byte, .{ .base = base_reg, .disp = -stack_offset }),
6895 cc,
6896 ),
6897 .immediate => |imm| {
67386898 // TODO
67396899 switch (abi_size) {
67406900 0 => {
......@@ -6742,13 +6902,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
67426902 try self.asmMemoryImmediate(.mov, Memory.sib(.byte, .{
67436903 .base = base_reg,
67446904 .disp = -stack_offset,
6745 }), Immediate.u(@truncate(u8, x_big)));
6905 }), Immediate.u(@truncate(u8, imm)));
67466906 },
67476907 1, 2, 4 => {
67486908 const immediate = if (ty.isSignedInt())
6749 Immediate.s(@truncate(i32, @bitCast(i64, x_big)))
6909 Immediate.s(@truncate(i32, @bitCast(i64, imm)))
67506910 else
6751 Immediate.u(@intCast(u32, x_big));
6911 Immediate.u(@intCast(u32, imm));
67526912 try self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
67536913 .base = base_reg,
67546914 .disp = -stack_offset,
......@@ -6758,27 +6918,32 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
67586918 else => {
67596919 // 64 bit write to memory would take two mov's anyways so we
67606920 // insted just use two 32 bit writes to avoid register allocation
6761 var offset: i32 = 0;
6762 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
6763 .mov,
6764 Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }),
6765 if (ty.isSignedInt())
6766 Immediate.s(@truncate(
6767 i32,
6768 @bitCast(i64, x_big) >> (math.cast(u6, offset * 8) orelse 63),
6769 ))
6770 else
6771 Immediate.u(@truncate(
6772 u32,
6773 if (math.cast(u6, offset * 8)) |shift| x_big >> shift else 0,
6774 )),
6775 );
6921 if (std.math.cast(i32, @bitCast(i64, imm))) |small| {
6922 try self.asmMemoryImmediate(.mov, Memory.sib(
6923 Memory.PtrSize.fromSize(abi_size),
6924 .{ .base = base_reg, .disp = -stack_offset },
6925 ), Immediate.s(small));
6926 } else {
6927 var offset: i32 = 0;
6928 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
6929 .mov,
6930 Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }),
6931 if (ty.isSignedInt())
6932 Immediate.s(@truncate(
6933 i32,
6934 @bitCast(i64, imm) >> (math.cast(u6, offset * 8) orelse 63),
6935 ))
6936 else
6937 Immediate.u(@truncate(
6938 u32,
6939 if (math.cast(u6, offset * 8)) |shift| imm >> shift else 0,
6940 )),
6941 );
6942 }
67766943 },
67776944 }
67786945 },
67796946 .register => |reg| {
6780 const base_reg = opts.dest_stack_base orelse .rbp;
6781
67826947 switch (ty.zigTypeTag()) {
67836948 .Float => {
67846949 if (intrinsicsAllowed(self.target.*, ty)) {
......@@ -6808,22 +6973,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
68086973 },
68096974 }
68106975 },
6811 .memory, .linker_load => {
6812 if (abi_size <= 8) {
6813 const reg = try self.copyToTmpRegister(ty, mcv);
6814 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts);
6815 }
6816
6817 try self.genInlineMemcpy(.{ .stack_offset = stack_offset }, mcv, .{ .immediate = abi_size }, opts);
6818 },
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;
6976 .memory, .linker_load, .stack_offset, .ptr_stack_offset => {
6977 switch (mcv) {
6978 else => unreachable,
6979 .memory, .linker_load, .ptr_stack_offset => {},
6980 .stack_offset => |src_off| if (stack_offset == src_off) {
6981 // Copy stack variable to itself; nothing to do.
6982 return;
6983 },
68276984 }
68286985
68296986 if (abi_size <= 8) {
......@@ -7101,69 +7258,38 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
71017258
71027259 try self.asmRegisterRegister(.mov, registerAlias(reg, abi_size), registerAlias(src_reg, abi_size));
71037260 },
7104 .linker_load => {
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()) {
7261 .memory, .linker_load => switch (ty.zigTypeTag()) {
71417262 .Float => {
71427263 const base_reg = try self.register_manager.allocReg(null, gp);
71437264 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);
71447265
71457266 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 };
71567267 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 },
71587275 reg.to128(),
7159 Memory.sib(ptr_size, .{ .base = base_reg.to64() }),
7276 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base_reg.to64() }),
71607277 );
71617278 }
71627279
71637280 return self.fail("TODO genSetReg from memory for float with no intrinsics", .{});
71647281 },
7165 else => {
7166 if (x <= math.maxInt(i32)) {
7282 else => switch (mcv) {
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)) {
71677293 try self.asmRegisterMemory(
71687294 .mov,
71697295 registerAlias(reg, abi_size),
......@@ -7190,7 +7316,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
71907316 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
71917317 );
71927318 }
7193 }
7319 },
71947320 },
71957321 },
71967322 .stack_offset => |off| {
......@@ -7231,15 +7357,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
72317357 .{ty.fmtDebug()},
72327358 ),
72337359 };
7234 const ptr_size: Memory.PtrSize = switch (ty.tag()) {
7235 .f32 => .dword,
7236 .f64 => .qword,
7237 else => unreachable,
7238 };
7239 return self.asmRegisterMemory(tag, reg.to128(), Memory.sib(ptr_size, .{
7240 .base = .rbp,
7241 .disp = -off,
7242 }));
7360 return self.asmRegisterMemory(tag, reg.to128(), Memory.sib(
7361 Memory.PtrSize.fromSize(abi_size),
7362 .{ .base = .rbp, .disp = -off },
7363 ));
72437364 }
72447365 return self.fail("TODO genSetReg from stack offset for float with no intrinsics", .{});
72457366 },
......@@ -7299,7 +7420,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
72997420 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
73007421 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
73017422 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 }, .{});
73037424 break :blk .{ .stack_offset = stack_offset };
73047425 };
73057426 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -7809,10 +7930,92 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
78097930
78107931fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
78117932 const un_op = self.air.instructions.items(.data)[inst].un_op;
7812 const operand = try self.resolveInst(un_op);
7813 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
7814 _ = operand;
7815 return self.fail("TODO implement airErrorName for x86_64", .{});
7933 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
7934 const err_ty = self.air.typeOf(un_op);
7935 const err_mcv = try self.resolveInst(un_op);
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;
78168019 };
78178020 return self.finishAir(inst, result, .{ un_op, .none, .none });
78188021}
......@@ -7853,19 +8056,88 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
78538056 if (self.liveness.isUnused(inst)) break :res MCValue.dead;
78548057 switch (result_ty.zigTypeTag()) {
78558058 .Struct => {
7856 if (result_ty.containerLayout() == .Packed) {
7857 return self.fail("TODO airAggregateInit implement packed structs", .{});
7858 }
78598059 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
7860 for (elements, 0..) |elem, elem_i| {
7861 if (result_ty.structFieldValueComptime(elem_i) != null) continue; // comptime elem
8060 const dst_mcv = MCValue{ .stack_offset = stack_offset };
8061 if (result_ty.containerLayout() == .Packed) {
8062 const struct_obj = result_ty.castTag(.@"struct").?.data;
8063 try self.genInlineMemset(
8064 dst_mcv,
8065 .{ .immediate = 0 },
8066 .{ .immediate = abi_size },
8067 .{},
8068 );
8069 for (elements, 0..) |elem, elem_i| {
8070 if (result_ty.structFieldValueComptime(elem_i) != null) continue;
8071
8072 const elem_ty = result_ty.structFieldType(elem_i);
8073 const elem_bit_size = @intCast(u32, elem_ty.bitSize(self.target.*));
8074 if (elem_bit_size > 64) {
8075 return self.fail("TODO airAggregateInit implement packed structs with large fields", .{});
8076 }
8077 const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));
8078 const elem_abi_bits = elem_abi_size * 8;
8079 const elem_off = struct_obj.packedFieldBitOffset(self.target.*, elem_i);
8080 const elem_byte_off = @intCast(i32, elem_off / elem_abi_bits * elem_abi_size);
8081 const elem_bit_off = elem_off % elem_abi_bits;
8082 const elem_mcv = try self.resolveInst(elem);
8083 const elem_lock = switch (elem_mcv) {
8084 .register => |reg| self.register_manager.lockReg(reg),
8085 .immediate => |imm| lock: {
8086 if (imm == 0) continue;
8087 break :lock null;
8088 },
8089 else => null,
8090 };
8091 defer if (elem_lock) |lock| self.register_manager.unlockReg(lock);
8092 const elem_reg = registerAlias(
8093 try self.copyToTmpRegister(elem_ty, elem_mcv),
8094 elem_abi_size,
8095 );
8096 const elem_extra_bits = self.regExtraBits(elem_ty);
8097 if (elem_bit_off < elem_extra_bits) {
8098 try self.truncateRegister(elem_ty, elem_reg);
8099 }
8100 if (elem_bit_off > 0) try self.genShiftBinOpMir(
8101 .shl,
8102 elem_ty,
8103 .{ .register = elem_reg },
8104 .{ .immediate = elem_bit_off },
8105 );
8106 try self.genBinOpMir(
8107 .@"or",
8108 elem_ty,
8109 .{ .stack_offset = stack_offset - elem_byte_off },
8110 .{ .register = elem_reg },
8111 );
8112 if (elem_bit_off > elem_extra_bits) {
8113 const reg = try self.copyToTmpRegister(elem_ty, elem_mcv);
8114 if (elem_extra_bits > 0) {
8115 try self.truncateRegister(elem_ty, registerAlias(reg, elem_abi_size));
8116 }
8117 try self.genShiftBinOpMir(
8118 .shr,
8119 elem_ty,
8120 .{ .register = reg },
8121 .{ .immediate = elem_abi_bits - elem_bit_off },
8122 );
8123 try self.genBinOpMir(
8124 .@"or",
8125 elem_ty,
8126 .{ .stack_offset = stack_offset - elem_byte_off -
8127 @intCast(i32, elem_abi_size) },
8128 .{ .register = reg },
8129 );
8130 }
8131 }
8132 } else for (elements, 0..) |elem, elem_i| {
8133 if (result_ty.structFieldValueComptime(elem_i) != null) continue;
78628134
78638135 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.*));
78658137 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, .{});
78678139 }
7868 break :res MCValue{ .stack_offset = stack_offset };
8140 break :res dst_mcv;
78698141 },
78708142 .Array => {
78718143 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
79808252 // This immediate is unsigned.
79818253 const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed));
79828254 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) };
79848256 }
79858257 },
79868258 else => {},
......@@ -8023,11 +8295,18 @@ const CallMCValues = struct {
80238295};
80248296
80258297/// 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 {
80278303 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);
80298306 defer self.gpa.free(param_types);
80308307 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);
80318310 var result: CallMCValues = .{
80328311 .args = try self.gpa.alloc(MCValue, param_types.len),
80338312 // These undefined values must be populated before returning from this function.
......@@ -8248,8 +8527,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
82488527 .unsigned => {
82498528 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
82508529 const mask = (~@as(u64, 0)) >> shift;
8251 if (int_info.bits < 32) {
8252 try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask });
8530 if (int_info.bits <= 32) {
8531 try self.genBinOpMir(.@"and", Type.u32, .{ .register = reg }, .{ .immediate = mask });
82538532 } else {
82548533 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
82558534 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) {
100100 };
101101 }
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
103113 /// Returns the condition which is true iff the given condition is false
104114 pub fn negate(cond: Condition) Condition {
105115 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
9999 mem.writeInt(Int, code[0..@sizeOf(Int)], int, endian);
100100}
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
102143pub fn generateSymbol(
103144 bin_file: *link.File,
104145 src_loc: Module.SrcLoc,
......@@ -118,9 +159,10 @@ pub fn generateSymbol(
118159 const target = bin_file.options.target;
119160 const endian = target.cpu.arch.endian();
120161
162 const mod = bin_file.options.module.?;
121163 log.debug("generateSymbol: ty = {}, val = {}", .{
122 typed_value.ty.fmtDebug(),
123 typed_value.val.fmtDebug(),
164 typed_value.ty.fmt(mod),
165 typed_value.val.fmtValue(typed_value.ty, mod),
124166 });
125167
126168 if (typed_value.val.isUndefDeep()) {
......@@ -170,7 +212,6 @@ pub fn generateSymbol(
170212 },
171213 .str_lit => {
172214 const str_lit = typed_value.val.castTag(.str_lit).?.data;
173 const mod = bin_file.options.module.?;
174215 const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
175216 try code.ensureUnusedCapacity(bytes.len + 1);
176217 code.appendSliceAssumeCapacity(bytes);
......@@ -300,7 +341,6 @@ pub fn generateSymbol(
300341 switch (container_ptr.tag()) {
301342 .decl_ref => {
302343 const decl_index = container_ptr.castTag(.decl_ref).?.data;
303 const mod = bin_file.options.module.?;
304344 const decl = mod.declPtr(decl_index);
305345 const addend = blk: {
306346 switch (decl.ty.zigTypeTag()) {
......@@ -493,7 +533,6 @@ pub fn generateSymbol(
493533 const field_vals = typed_value.val.castTag(.aggregate).?.data;
494534 const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow;
495535 const current_pos = code.items.len;
496 const mod = bin_file.options.module.?;
497536 try code.resize(current_pos + abi_size);
498537 var bits: u16 = 0;
499538
......@@ -570,7 +609,6 @@ pub fn generateSymbol(
570609 }
571610
572611 const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;
573 const mod = bin_file.options.module.?;
574612 const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?;
575613 assert(union_ty.haveFieldTypes());
576614 const field_ty = union_ty.fields.values()[field_index].ty;
......@@ -776,7 +814,6 @@ pub fn generateSymbol(
776814 },
777815 .str_lit => {
778816 const str_lit = typed_value.val.castTag(.str_lit).?.data;
779 const mod = bin_file.options.module.?;
780817 const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
781818 try code.ensureUnusedCapacity(str_lit.len);
782819 code.appendSliceAssumeCapacity(bytes);
src/link.zig+21
......@@ -687,6 +687,7 @@ pub const File = struct {
687687 FrameworkNotFound,
688688 FunctionSignatureMismatch,
689689 GlobalTypeMismatch,
690 HotSwapUnavailableOnHostOperatingSystem,
690691 InvalidCharacter,
691692 InvalidEntryKind,
692693 InvalidFeatureSet,
......@@ -1104,6 +1105,26 @@ pub const File = struct {
11041105 missing_libc: bool = false,
11051106 };
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
11071128 pub const C = @import("link/C.zig");
11081129 pub const Coff = @import("link/Coff.zig");
11091130 pub const Plan9 = @import("link/Plan9.zig");
src/link/Coff.zig+122
......@@ -49,6 +49,9 @@ imports_count_dirty: bool = true,
4949/// Virtual address of the entry point procedure relative to image base.
5050entry_addr: ?u32 = null,
5151
52/// Table of tracked LazySymbols.
53lazy_syms: LazySymbolTable = .{},
54
5255/// Table of tracked Decls.
5356decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
5457
......@@ -142,6 +145,18 @@ const Section = struct {
142145 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
143146};
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
145160const DeclMetadata = struct {
146161 atom: Atom.Index,
147162 section: u16,
......@@ -1168,6 +1183,100 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
11681183 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
11691184}
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
11711280pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {
11721281 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
11731282 if (!gop.found_existing) {
......@@ -1498,6 +1607,19 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
14981607 sub_prog_node.activate();
14991608 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
15011623 const gpa = self.base.allocator;
15021624
15031625 while (self.unresolved.popOrNull()) |entry| {
src/link/Elf.zig+114
......@@ -63,6 +63,12 @@ const Section = struct {
6363 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
6464};
6565
66const LazySymbolMetadata = struct {
67 atom: Atom.Index,
68 shdr: u16,
69 alignment: u32,
70};
71
6672const DeclMetadata = struct {
6773 atom: Atom.Index,
6874 shdr: u16,
......@@ -157,6 +163,9 @@ debug_line_header_dirty: bool = false,
157163
158164error_flags: File.ErrorFlags = File.ErrorFlags{},
159165
166/// Table of tracked LazySymbols.
167lazy_syms: LazySymbolTable = .{},
168
160169/// Table of tracked Decls.
161170decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
162171
......@@ -194,6 +203,7 @@ relocs: RelocTable = .{},
194203
195204const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));
196205const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
206const LazySymbolTable = std.ArrayHashMapUnmanaged(File.LazySymbol, LazySymbolMetadata, File.LazySymbol.Context, true);
197207
198208/// When allocating, the ideal_capacity is calculated by
199209/// actual_capacity + (actual_capacity / ideal_factor)
......@@ -1011,6 +1021,19 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10111021 sub_prog_node.activate();
10121022 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
10141037 // TODO This linker code currently assumes there is only 1 compilation unit and it
10151038 // corresponds to the Zig source code.
10161039 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 {
23442367 }
23452368}
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
23472388pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {
23482389 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
23492390 if (!gop.found_existing) {
......@@ -2610,6 +2651,79 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
26102651 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
26112652}
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
26132727pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
26142728 const gpa = self.base.allocator;
26152729
src/link/MachO.zig+126-4
......@@ -218,6 +218,9 @@ bindings: BindingTable = .{},
218218/// this will be a table indexed by index into the list of Atoms.
219219lazy_bindings: BindingTable = .{},
220220
221/// Table of tracked LazySymbols.
222lazy_syms: LazySymbolTable = .{},
223
221224/// Table of tracked Decls.
222225decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
223226
......@@ -229,6 +232,18 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
229232 else => false,
230233};
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
232247const DeclMetadata = struct {
233248 atom: Atom.Index,
234249 section: u8,
......@@ -497,6 +512,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
497512 sub_prog_node.activate();
498513 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
500528 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
501529
502530 if (self.d_sym) |*d_sym| {
......@@ -2163,13 +2191,13 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
21632191
21642192 const name_str_index = blk: {
21652193 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 });
21672195 defer gpa.free(name);
21682196 break :blk try self.strtab.insert(gpa, name);
21692197 };
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
21742202 const atom_index = try self.createAtom();
21752203
......@@ -2202,7 +2230,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
22022230
22032231 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 });
22062234 log.debug(" (required alignment 0x{x})", .{required_alignment});
22072235
22082236 try self.writeAtom(atom_index, code);
......@@ -2282,6 +2310,100 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
22822310 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
22832311}
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
22852407pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index {
22862408 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
22872409 if (!gop.found_existing) {
test/behavior/align.zig-3
......@@ -271,7 +271,6 @@ fn sliceExpects4(slice: []align(4) u32) void {
271271
272272test "return error union with 128-bit integer" {
273273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
274 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
275274 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
276275 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
277276
......@@ -477,7 +476,6 @@ const DefaultAligned = struct {
477476
478477test "read 128-bit field from default aligned struct in stack memory" {
479478 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
480 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
481479 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
482480 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
483481
......@@ -494,7 +492,6 @@ var default_aligned_global = DefaultAligned{
494492};
495493
496494test "read 128-bit field from default aligned struct in global memory" {
497 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
498495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
499496 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
500497 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" {
3939
4040test "truncate to non-power-of-two integers from 128-bit" {
4141 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
4342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4443 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4544 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -345,7 +344,6 @@ fn copy(src: *const u64, dst: *u64) void {
345344test "call result of if else expression" {
346345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
347346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
348 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
349347 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350348
351349 try expect(mem.eql(u8, f2(true), "a"));
......@@ -663,7 +661,6 @@ test "multiline string literal is null terminated" {
663661test "string escapes" {
664662 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
665663 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
666 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
667664 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
668665
669666 try expectEqualStrings("\"", "\x22");
......@@ -682,8 +679,6 @@ test "explicit cast optional pointers" {
682679}
683680
684681test "pointer comparison" {
685 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
686
687682 const a = @as([]const u8, "a");
688683 const b = &a;
689684 try expect(ptrEql(b, b));
......@@ -695,7 +690,6 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
695690test "string concatenation" {
696691 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
697692 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
698 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
699693 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
700694
701695 const a = "OK" ++ " IT " ++ "WORKED";
......@@ -916,7 +910,6 @@ test "vector initialized with array init syntax has proper type" {
916910}
917911
918912test "weird array and tuple initializations" {
919 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
920913 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
921914 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
922915 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" {
10601053
10611054test "namespace lookup ignores decl causing the lookup" {
10621055 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1063 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10641056 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10651057 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)" {
2020
2121test "@bitCast iX -> uX (8, 16, 128)" {
2222 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
2423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2524 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2625
test/behavior/bugs/6047.zig-1
......@@ -11,7 +11,6 @@ fn getError2() !void {
1111
1212test "`try`ing an if/else expression" {
1313 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1514 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
1615 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1716 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/6905.zig-1
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33
44test "sentinel-terminated 0-length slices" {
55 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/9584.zig-1
......@@ -47,7 +47,6 @@ test {
4747 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4848 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4949 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5150
5251 var flags = A{
5352 .a = false,
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1
......@@ -8,7 +8,6 @@ var x: u8 = 1;
88test {
99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1312 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1413 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/cast.zig-1
......@@ -1178,7 +1178,6 @@ fn castToOptionalSlice() ?[]const u8 {
11781178test "cast u128 to f128 and back" {
11791179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11801180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1181 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11821181 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11831182 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;
55
66test "@intCast i32 to u7" {
77 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110 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" {
110110}
111111
112112test "errdefer with payload" {
113 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
114113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
116115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/error.zig-4
......@@ -561,7 +561,6 @@ test "error union comptime caching" {
561561}
562562
563563test "@errorName" {
564 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
565564 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
566565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
567566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -575,7 +574,6 @@ fn gimmeItBroke() anyerror {
575574}
576575
577576test "@errorName sentinel length matches slice length" {
578 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
579577 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
580578 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
581579 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -799,7 +797,6 @@ test "error union of noreturn used with catch" {
799797}
800798
801799test "alignment of wrapping an error union payload" {
802 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
803800 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
804801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
805802 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -851,7 +848,6 @@ test "catch within a function that calls no errorable functions" {
851848test "error from comptime string" {
852849 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
853850 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
854 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
855851 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
856852
857853 const name = "Weird error name!";
test/behavior/eval.zig-1
......@@ -458,7 +458,6 @@ test "binary math operator in partially inlined function" {
458458
459459test "comptime shl" {
460460 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
461 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
462461 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
463462 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
464463 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/int128.zig-4
......@@ -5,7 +5,6 @@ const minInt = std.math.minInt;
55const builtin = @import("builtin");
66
77test "uint128" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -24,7 +23,6 @@ test "uint128" {
2423}
2524
2625test "undefined 128 bit int" {
27 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2826 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2927 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -42,7 +40,6 @@ test "undefined 128 bit int" {
4240}
4341
4442test "int128" {
45 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
4643 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4744 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4845 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -87,7 +84,6 @@ test "truncate int128" {
8784
8885test "shift int128" {
8986 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
90 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9187 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9288 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9389 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/int_div.zig-1
......@@ -97,7 +97,6 @@ test "large integer division" {
9797 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9898 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
9999 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
100 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
101100
102101 {
103102 var numerator: u256 = 99999999999999999997315645440;
test/behavior/optional.zig-2
......@@ -412,7 +412,6 @@ test "orelse on C pointer" {
412412}
413413
414414test "alignment of wrapping an optional payload" {
415 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
416415 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
417416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
418417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -468,7 +467,6 @@ test "peer type resolution in nested if expressions" {
468467test "cast slice to const slice nested in error union and optional" {
469468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
470469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
471 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
472470
473471 const S = struct {
474472 fn inner() !?[]u8 {
test/behavior/packed-struct.zig-2
......@@ -352,7 +352,6 @@ test "byte-aligned field pointer offsets" {
352352}
353353
354354test "load pointer from packed struct" {
355 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
356355 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
357356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
358357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -585,7 +584,6 @@ test "overaligned pointer to packed struct" {
585584test "packed struct initialized in bitcast" {
586585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
587586 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
588 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
589587
590588 const T = packed struct { val: u8 };
591589 var val: u8 = 123;
test/behavior/pointers.zig-1
......@@ -160,7 +160,6 @@ test "implicit casting between C pointer and optional non-C pointer" {
160160}
161161
162162test "implicit cast error unions with non-optional to optional pointer" {
163 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
164163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
165164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
166165 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" {
800800}
801801
802802test "non-packed struct with u128 entry in union" {
803 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
804803 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
805804 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
806805 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1244,7 +1243,6 @@ test "loading a struct pointer perfoms a copy" {
12441243}
12451244
12461245test "packed struct aggregate init" {
1247 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12481246 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12491247 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12501248 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" {
419419}
420420
421421test "else prong of switch on error set excludes other cases" {
422 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
423422 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
424423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
425424 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/typename.zig-6
......@@ -12,7 +12,6 @@ const expectStringStartsWith = std.testing.expectStringStartsWith;
1212// failures.
1313
1414test "anon fn param" {
15 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1615 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1716 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1817 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -38,7 +37,6 @@ test "anon fn param" {
3837}
3938
4039test "anon field init" {
41 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
4240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4442 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -87,7 +85,6 @@ test "basic" {
8785}
8886
8987test "top level decl" {
90 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9289 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9390 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -137,7 +134,6 @@ const B = struct {
137134};
138135
139136test "fn param" {
140 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
141137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
142138 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
143139 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -208,7 +204,6 @@ pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8)
208204}
209205
210206test "local variable" {
211 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
212207 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
213208 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
214209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -236,7 +231,6 @@ test "comptime parameters not converted to anytype in function type" {
236231}
237232
238233test "anon name strategy used in sub expression" {
239 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
240234 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
241235 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
242236 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 @@
22// output_mode=Exe
33// target=aarch64-macos
44//
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 @@
22// output_mode=Exe
33// target=x86_64-linux
44//
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 @@
22// output_mode=Exe
33// target=x86_64-macos
44//
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 @@
22// output_mode=Exe
33// target=x86_64-windows
44//
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'