authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-01 03:08:55-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-02 04:49:53-04:00
log677427bc3ac839629654175f0a2aaaec9fd6fb6c
treedeb37ed3275cfef97f9d49d7e8a1eeea5a3c64db
parentccefa9dbf5369e0fadc75b9e705e74ec96a02859

x86_64: implement error name


11 files changed, 529 insertions(+), 42 deletions(-)

src/arch/x86_64/CodeGen.zig+102-25
......@@ -1923,7 +1923,7 @@ fn genSetStackTruncatedOverflowCompare(
19231923 );
19241924
19251925 try self.genSetStack(ty, stack_offset, .{ .register = scratch_reg }, .{});
1926 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{
1926 try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{
19271927 .register = overflow_reg.to8(),
19281928 }, .{});
19291929}
......@@ -5280,8 +5280,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
52805280
52815281 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
52825282 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);
5283 const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file);
52855284 try self.asmMemory(.call, Memory.sib(.qword, .{
52865285 .base = .ds,
52875286 .disp = @intCast(i32, got_addr),
......@@ -5289,22 +5288,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
52895288 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
52905289 const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
52915290 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 });
5291 try self.genSetReg(Type.usize, .rax, .{ .linker_load = .{
5292 .type = .got,
5293 .sym_index = sym_index,
5294 } });
52985295 try self.asmRegister(.call, .rax);
52995296 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
53005297 const atom_index = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
53015298 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 });
5299 try self.genSetReg(Type.usize, .rax, .{ .linker_load = .{
5300 .type = .got,
5301 .sym_index = sym_index,
5302 } });
53085303 try self.asmRegister(.call, .rax);
53095304 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
53105305 const decl_block_index = try p9.seeDecl(func.owner_decl);
......@@ -5325,7 +5320,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
53255320 const lib_name = mem.sliceTo(extern_fn.lib_name, 0);
53265321 if (self.bin_file.cast(link.File.Coff)) |coff_file| {
53275322 const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);
5328 try self.genSetReg(Type.initTag(.usize), .rax, .{
5323 try self.genSetReg(Type.usize, .rax, .{
53295324 .linker_load = .{
53305325 .type = .import,
53315326 .sym_index = sym_index,
......@@ -5353,7 +5348,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
53535348 } else {
53545349 assert(ty.zigTypeTag() == .Pointer);
53555350 const mcv = try self.resolveInst(callee);
5356 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
5351 try self.genSetReg(Type.usize, .rax, mcv);
53575352 try self.asmRegister(.call, .rax);
53585353 }
53595354
......@@ -7299,7 +7294,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
72997294 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
73007295 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
73017296 try self.genSetStack(ptr_ty, stack_offset, ptr, .{});
7302 try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len }, .{});
7297 try self.genSetStack(Type.u64, stack_offset - 8, .{ .immediate = array_len }, .{});
73037298 break :blk .{ .stack_offset = stack_offset };
73047299 };
73057300 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -7809,10 +7804,92 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
78097804
78107805fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
78117806 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", .{});
7807 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
7808 const err_ty = self.air.typeOf(un_op);
7809 const err_mcv = try self.resolveInst(un_op);
7810 const err_reg = try self.copyToTmpRegister(err_ty, err_mcv);
7811 const err_lock = self.register_manager.lockRegAssumeUnused(err_reg);
7812 defer self.register_manager.unlockReg(err_lock);
7813
7814 const addr_reg = try self.register_manager.allocReg(null, gp);
7815 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
7816 defer self.register_manager.unlockReg(addr_lock);
7817
7818 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
7819 const atom_index = try elf_file.getOrCreateAtomForLazySymbol(
7820 .{ .kind = .const_data, .ty = Type.anyerror },
7821 4, // dword alignment
7822 );
7823 const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file);
7824 try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{
7825 .base = .ds,
7826 .disp = @intCast(i32, got_addr),
7827 }));
7828 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
7829 const atom_index = try coff_file.getOrCreateAtomForLazySymbol(
7830 .{ .kind = .const_data, .ty = Type.anyerror },
7831 4, // dword alignment
7832 );
7833 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
7834 try self.genSetReg(Type.usize, addr_reg, .{ .linker_load = .{
7835 .type = .got,
7836 .sym_index = sym_index,
7837 } });
7838 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
7839 const atom_index = try macho_file.getOrCreateAtomForLazySymbol(
7840 .{ .kind = .const_data, .ty = Type.anyerror },
7841 4, // dword alignment
7842 );
7843 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
7844 try self.genSetReg(Type.usize, addr_reg, .{ .linker_load = .{
7845 .type = .got,
7846 .sym_index = sym_index,
7847 } });
7848 } else {
7849 return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)});
7850 }
7851
7852 const start_reg = try self.register_manager.allocReg(null, gp);
7853 const start_lock = self.register_manager.lockRegAssumeUnused(start_reg);
7854 defer self.register_manager.unlockReg(start_lock);
7855
7856 const end_reg = try self.register_manager.allocReg(null, gp);
7857 const end_lock = self.register_manager.lockRegAssumeUnused(end_reg);
7858 defer self.register_manager.unlockReg(end_lock);
7859
7860 try self.truncateRegister(err_ty, err_reg.to32());
7861
7862 try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{
7863 .base = addr_reg.to64(),
7864 .scale_index = .{ .scale = 4, .index = err_reg.to64() },
7865 .disp = 0,
7866 }));
7867 try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{
7868 .base = addr_reg.to64(),
7869 .scale_index = .{ .scale = 4, .index = err_reg.to64() },
7870 .disp = 4,
7871 }));
7872 try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32());
7873 try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{
7874 .base = addr_reg.to64(),
7875 .scale_index = .{ .scale = 1, .index = start_reg.to64() },
7876 .disp = 0,
7877 }));
7878 try self.asmRegisterMemory(.lea, end_reg.to32(), Memory.sib(.byte, .{
7879 .base = end_reg.to64(),
7880 .disp = -1,
7881 }));
7882
7883 const dst_mcv = try self.allocRegOrMem(inst, false);
7884 try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{
7885 .base = .rbp,
7886 .disp = 0 - dst_mcv.stack_offset,
7887 }), start_reg.to64());
7888 try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{
7889 .base = .rbp,
7890 .disp = 8 - dst_mcv.stack_offset,
7891 }), end_reg.to64());
7892 break :result dst_mcv;
78167893 };
78177894 return self.finishAir(inst, result, .{ un_op, .none, .none });
78187895}
......@@ -8046,7 +8123,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
80468123 // This immediate is unsigned.
80478124 const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed));
80488125 if (imm >= math.maxInt(U)) {
8049 return MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.usize), mcv) };
8126 return MCValue{ .register = try self.copyToTmpRegister(Type.usize, mcv) };
80508127 }
80518128 },
80528129 else => {},
......@@ -8321,8 +8398,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
83218398 .unsigned => {
83228399 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
83238400 const mask = (~@as(u64, 0)) >> shift;
8324 if (int_info.bits < 32) {
8325 try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask });
8401 if (int_info.bits <= 32) {
8402 try self.genBinOpMir(.@"and", Type.u32, .{ .register = reg }, .{ .immediate = mask });
83268403 } else {
83278404 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
83288405 try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg });
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/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/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-2
......@@ -575,7 +575,6 @@ fn gimmeItBroke() anyerror {
575575}
576576
577577test "@errorName sentinel length matches slice length" {
578 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
579578 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
580579 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
581580 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -851,7 +850,6 @@ test "catch within a function that calls no errorable functions" {
851850test "error from comptime string" {
852851 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
853852 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
854 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
855853 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
856854
857855 const name = "Weird error name!";
test/behavior/optional.zig-1
......@@ -468,7 +468,6 @@ test "peer type resolution in nested if expressions" {
468468test "cast slice to const slice nested in error union and optional" {
469469 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
470470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
471 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
472471
473472 const S = struct {
474473 fn inner() !?[]u8 {
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