Merge pull request #20964 from mlugg/the-great-decl-split-mk2

compiler: split `Decl` into `Nav` and `Cau`
This commit is contained in:
Andrew Kelley 2024-08-11 15:07:06 -07:00 committed by GitHub
commit fc29240806
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 6458 additions and 7291 deletions

View File

@ -354,28 +354,25 @@ pub const RcIncludes = enum {
const Job = union(enum) {
/// Write the constant value for a Decl to the output file.
codegen_decl: InternPool.DeclIndex,
codegen_nav: InternPool.Nav.Index,
/// Write the machine code for a function to the output file.
/// This will either be a non-generic `func_decl` or a `func_instance`.
codegen_func: struct {
/// This will either be a non-generic `func_decl` or a `func_instance`.
func: InternPool.Index,
/// This `Air` is owned by the `Job` and allocated with `gpa`.
/// It must be deinited when the job is processed.
air: Air,
},
/// Render the .h file snippet for the Decl.
emit_h_decl: InternPool.DeclIndex,
/// The Decl needs to be analyzed and possibly export itself.
/// It may have already be analyzed, or it may have been determined
/// to be outdated; in this case perform semantic analysis again.
analyze_decl: InternPool.DeclIndex,
/// The `Cau` must be semantically analyzed (and possibly export itself).
/// This may be its first time being analyzed, or it may be outdated.
analyze_cau: InternPool.Cau.Index,
/// Analyze the body of a runtime function.
/// After analysis, a `codegen_func` job will be queued.
/// These must be separate jobs to ensure any needed type resolution occurs *before* codegen.
analyze_func: InternPool.Index,
/// The source file containing the Decl has been updated, and so the
/// Decl may need its line number information updated in the debug info.
update_line_number: InternPool.DeclIndex,
update_line_number: void, // TODO
/// The main source file for the module needs to be analyzed.
analyze_mod: *Package.Module,
/// Fully resolve the given `struct` or `union` type.
@ -419,7 +416,7 @@ const Job = union(enum) {
};
const CodegenJob = union(enum) {
decl: InternPool.DeclIndex,
nav: InternPool.Nav.Index,
func: struct {
func: InternPool.Index,
/// This `Air` is owned by the `Job` and allocated with `gpa`.
@ -1445,12 +1442,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
.path = try options.global_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}),
};
const emit_h: ?*Zcu.GlobalEmitH = if (options.emit_h) |loc| eh: {
const eh = try arena.create(Zcu.GlobalEmitH);
eh.* = .{ .loc = loc };
break :eh eh;
} else null;
const std_mod = options.std_mod orelse try Package.Module.create(arena, .{
.global_cache_directory = options.global_cache_directory,
.paths = .{
@ -1478,7 +1469,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
.std_mod = std_mod,
.global_zir_cache = global_zir_cache,
.local_zir_cache = local_zir_cache,
.emit_h = emit_h,
.error_limit = error_limit,
.llvm_object = null,
};
@ -2581,7 +2571,7 @@ fn addNonIncrementalStuffToCacheManifest(
man.hash.addOptionalBytes(comp.test_name_prefix);
man.hash.add(comp.skip_linker_dependencies);
man.hash.add(comp.formatted_panics);
man.hash.add(mod.emit_h != null);
//man.hash.add(mod.emit_h != null);
man.hash.add(mod.error_limit);
} else {
cache_helpers.addModule(&man.hash, comp.root_mod);
@ -2930,7 +2920,7 @@ const Header = extern struct {
intern_pool: extern struct {
thread_count: u32,
src_hash_deps_len: u32,
decl_val_deps_len: u32,
nav_val_deps_len: u32,
namespace_deps_len: u32,
namespace_name_deps_len: u32,
first_dependency_len: u32,
@ -2972,7 +2962,7 @@ pub fn saveState(comp: *Compilation) !void {
.intern_pool = .{
.thread_count = @intCast(ip.locals.len),
.src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
.decl_val_deps_len = @intCast(ip.decl_val_deps.count()),
.nav_val_deps_len = @intCast(ip.nav_val_deps.count()),
.namespace_deps_len = @intCast(ip.namespace_deps.count()),
.namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()),
.first_dependency_len = @intCast(ip.first_dependency.count()),
@ -2999,8 +2989,8 @@ pub fn saveState(comp: *Compilation) !void {
addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys()));
addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));
addBuf(&bufs, mem.sliceAsBytes(ip.decl_val_deps.keys()));
addBuf(&bufs, mem.sliceAsBytes(ip.decl_val_deps.values()));
addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));
addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values()));
addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys()));
addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values()));
addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys()));
@ -3019,7 +3009,7 @@ pub fn saveState(comp: *Compilation) !void {
addBuf(&bufs, local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]);
addBuf(&bufs, mem.sliceAsBytes(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len]));
addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len]));
addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.root_decl)[0..pt_header.intern_pool.files_len]));
addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len]));
}
//// TODO: compilation errors
@ -3065,6 +3055,8 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
}
if (comp.module) |zcu| {
const ip = &zcu.intern_pool;
total += zcu.failed_exports.count();
total += zcu.failed_embed_files.count();
@ -3084,25 +3076,18 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
// When a parse error is introduced, we keep all the semantic analysis for
// the previous parse success, including compile errors, but we cannot
// emit them until the file succeeds parsing.
for (zcu.failed_analysis.keys()) |key| {
const decl_index = switch (key.unwrap()) {
.decl => |d| d,
.func => |ip_index| zcu.funcInfo(ip_index).owner_decl,
for (zcu.failed_analysis.keys()) |anal_unit| {
const file_index = switch (anal_unit.unwrap()) {
.cau => |cau| zcu.namespacePtr(ip.getCau(cau).namespace).file_scope,
.func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip).file,
};
if (zcu.declFileScope(decl_index).okToReportErrors()) {
if (zcu.fileByIndex(file_index).okToReportErrors()) {
total += 1;
if (zcu.cimport_errors.get(key)) |errors| {
if (zcu.cimport_errors.get(anal_unit)) |errors| {
total += errors.errorMessageCount();
}
}
}
if (zcu.emit_h) |emit_h| {
for (emit_h.failed_decls.keys()) |key| {
if (zcu.declFileScope(key).okToReportErrors()) {
total += 1;
}
}
}
if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) {
total += 1;
@ -3169,6 +3154,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
});
}
if (comp.module) |zcu| {
const ip = &zcu.intern_pool;
var all_references = try zcu.resolveReferences();
defer all_references.deinit(gpa);
@ -3219,14 +3206,14 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
if (err) |e| return e;
}
for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| {
const decl_index = switch (anal_unit.unwrap()) {
.decl => |d| d,
.func => |ip_index| zcu.funcInfo(ip_index).owner_decl,
const file_index = switch (anal_unit.unwrap()) {
.cau => |cau| zcu.namespacePtr(ip.getCau(cau).namespace).file_scope,
.func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip).file,
};
// Skip errors for Decls within files that had a parse failure.
// Skip errors for AnalUnits within files that had a parse failure.
// We'll try again once parsing succeeds.
if (!zcu.declFileScope(decl_index).okToReportErrors()) continue;
if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;
try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
if (zcu.cimport_errors.get(anal_unit)) |errors| {
@ -3250,15 +3237,6 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
}
}
}
if (zcu.emit_h) |emit_h| {
for (emit_h.failed_decls.keys(), emit_h.failed_decls.values()) |decl_index, error_msg| {
// Skip errors for Decls within files that had a parse failure.
// We'll try again once parsing succeeds.
if (zcu.declFileScope(decl_index).okToReportErrors()) {
try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
}
}
}
for (zcu.failed_exports.values()) |value| {
try addModuleErrorMsg(zcu, &bundle, value.*, &all_references);
}
@ -3437,11 +3415,15 @@ pub fn addModuleErrorMsg(
const loc = std.zig.findLineColumn(source.bytes, span.main);
const rt_file_path = try src.file_scope.fullPath(gpa);
const name = switch (ref.referencer.unwrap()) {
.decl => |d| mod.declPtr(d).name,
.func => |f| mod.funcOwnerDeclPtr(f).name,
.cau => |cau| switch (ip.getCau(cau).owner.unwrap()) {
.nav => |nav| ip.getNav(nav).name.toSlice(ip),
.type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
.none => "comptime",
},
.func => |f| ip.getNav(mod.funcInfo(f).owner_nav).name.toSlice(ip),
};
try ref_traces.append(gpa, .{
.decl_name = try eb.addString(name.toSlice(ip)),
.decl_name = try eb.addString(name),
.src_loc = try eb.addSourceLocation(.{
.src_path = try eb.addString(rt_file_path),
.span_start = span.start,
@ -3617,10 +3599,10 @@ fn performAllTheWorkInner(
// Pre-load these things from our single-threaded context since they
// will be needed by the worker threads.
const path_digest = zcu.filePathDigest(file_index);
const root_decl = zcu.fileRootDecl(file_index);
const old_root_type = zcu.fileRootType(file_index);
const file = zcu.fileByIndex(file_index);
comp.thread_pool.spawnWgId(&astgen_wait_group, workerAstGenFile, .{
comp, file, file_index, path_digest, root_decl, zir_prog_node, &astgen_wait_group, .root,
comp, file, file_index, path_digest, old_root_type, zir_prog_node, &astgen_wait_group, .root,
});
}
}
@ -3682,7 +3664,7 @@ fn performAllTheWorkInner(
// which we need to work on, and queue it if so.
if (try zcu.findOutdatedToAnalyze()) |outdated| {
switch (outdated.unwrap()) {
.decl => |decl| try comp.queueJob(.{ .analyze_decl = decl }),
.cau => |cau| try comp.queueJob(.{ .analyze_cau = cau }),
.func => |func| try comp.queueJob(.{ .analyze_func = func }),
}
continue;
@ -3704,24 +3686,17 @@ pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void {
fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progress.Node) JobError!void {
switch (job) {
.codegen_decl => |decl_index| {
const decl = comp.module.?.declPtr(decl_index);
switch (decl.analysis) {
.unreferenced => unreachable,
.in_progress => unreachable,
.file_failure,
.sema_failure,
.codegen_failure,
.dependency_failure,
=> {},
.complete => {
assert(decl.has_tv);
try comp.queueCodegenJob(tid, .{ .decl = decl_index });
},
.codegen_nav => |nav_index| {
const zcu = comp.module.?;
const nav = zcu.intern_pool.getNav(nav_index);
if (nav.analysis_owner.unwrap()) |cau| {
const unit = InternPool.AnalUnit.wrap(.{ .cau = cau });
if (zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit)) {
return;
}
}
assert(nav.status == .resolved);
try comp.queueCodegenJob(tid, .{ .nav = nav_index });
},
.codegen_func => |func| {
// This call takes ownership of `func.air`.
@ -3740,82 +3715,30 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
error.AnalysisFail => return,
};
},
.emit_h_decl => |decl_index| {
if (true) @panic("regressed compiler feature: emit-h should hook into updateExports, " ++
"not decl analysis, which is too early to know about @export calls");
.analyze_cau => |cau_index| {
const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
const decl = pt.zcu.declPtr(decl_index);
switch (decl.analysis) {
.unreferenced => unreachable,
.in_progress => unreachable,
.file_failure,
.sema_failure,
.dependency_failure,
=> return,
// emit-h only requires semantic analysis of the Decl to be complete,
// it does not depend on machine code generation to succeed.
.codegen_failure, .complete => {
const named_frame = tracy.namedFrame("emit_h_decl");
defer named_frame.end();
const gpa = comp.gpa;
const emit_h = pt.zcu.emit_h.?;
_ = try emit_h.decl_table.getOrPut(gpa, decl_index);
const decl_emit_h = emit_h.declPtr(decl_index);
const fwd_decl = &decl_emit_h.fwd_decl;
fwd_decl.shrinkRetainingCapacity(0);
var ctypes_arena = std.heap.ArenaAllocator.init(gpa);
defer ctypes_arena.deinit();
const file_scope = pt.zcu.namespacePtr(decl.src_namespace).fileScope(pt.zcu);
var dg: c_codegen.DeclGen = .{
.gpa = gpa,
.pt = pt,
.mod = file_scope.mod,
.error_msg = null,
.pass = .{ .decl = decl_index },
.is_naked_fn = false,
.fwd_decl = fwd_decl.toManaged(gpa),
.ctype_pool = c_codegen.CType.Pool.empty,
.scratch = .{},
.anon_decl_deps = .{},
.aligned_anon_decls = .{},
};
defer {
fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
dg.ctype_pool.deinit(gpa);
dg.scratch.deinit(gpa);
}
try dg.ctype_pool.init(gpa);
c_codegen.genHeader(&dg) catch |err| switch (err) {
error.AnalysisFail => {
try emit_h.failed_decls.put(gpa, decl_index, dg.error_msg.?);
return;
},
else => |e| return e,
};
},
}
},
.analyze_decl => |decl_index| {
const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
pt.ensureDeclAnalyzed(decl_index) catch |err| switch (err) {
pt.ensureCauAnalyzed(cau_index) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => return,
};
const decl = pt.zcu.declPtr(decl_index);
if (decl.kind == .@"test" and comp.config.is_test) {
queue_test_analysis: {
if (!comp.config.is_test) break :queue_test_analysis;
// Check if this is a test function.
const ip = &pt.zcu.intern_pool;
const cau = ip.getCau(cau_index);
const nav_index = switch (cau.owner.unwrap()) {
.none, .type => break :queue_test_analysis,
.nav => |nav| nav,
};
if (!pt.zcu.test_functions.contains(nav_index)) {
break :queue_test_analysis;
}
// Tests are always emitted in test binaries. The decl_refs are created by
// Zcu.populateTestFunctions, but this will not queue body analysis, so do
// that now.
try pt.zcu.ensureFuncBodyAnalysisQueued(decl.val.toIntern());
try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav_index).status.resolved.val);
}
},
.resolve_type_fully => |ty| {
@ -3832,6 +3755,8 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
const named_frame = tracy.namedFrame("update_line_number");
defer named_frame.end();
if (true) @panic("TODO: update_line_number");
const gpa = comp.gpa;
const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
const decl = pt.zcu.declPtr(decl_index);
@ -4054,12 +3979,12 @@ fn codegenThread(tid: usize, comp: *Compilation) void {
fn processOneCodegenJob(tid: usize, comp: *Compilation, codegen_job: CodegenJob) JobError!void {
switch (codegen_job) {
.decl => |decl_index| {
const named_frame = tracy.namedFrame("codegen_decl");
.nav => |nav_index| {
const named_frame = tracy.namedFrame("codegen_nav");
defer named_frame.end();
const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
try pt.linkerUpdateDecl(decl_index);
try pt.linkerUpdateNav(nav_index);
},
.func => |func| {
const named_frame = tracy.namedFrame("codegen_func");
@ -4366,7 +4291,7 @@ fn workerAstGenFile(
file: *Zcu.File,
file_index: Zcu.File.Index,
path_digest: Cache.BinDigest,
root_decl: Zcu.Decl.OptionalIndex,
old_root_type: InternPool.Index,
prog_node: std.Progress.Node,
wg: *WaitGroup,
src: Zcu.AstGenSrc,
@ -4375,7 +4300,7 @@ fn workerAstGenFile(
defer child_prog_node.end();
const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
pt.astGenFile(file, path_digest, root_decl) catch |err| switch (err) {
pt.astGenFile(file, path_digest, old_root_type) catch |err| switch (err) {
error.AnalysisFail => return,
else => {
file.status = .retryable_failure;
@ -4406,7 +4331,7 @@ fn workerAstGenFile(
// `@import("builtin")` is handled specially.
if (mem.eql(u8, import_path, "builtin")) continue;
const import_result, const imported_path_digest, const imported_root_decl = blk: {
const import_result, const imported_path_digest, const imported_root_type = blk: {
comp.mutex.lock();
defer comp.mutex.unlock();
@ -4421,8 +4346,8 @@ fn workerAstGenFile(
comp.appendFileSystemInput(fsi, res.file.mod.root, res.file.sub_file_path) catch continue;
};
const imported_path_digest = pt.zcu.filePathDigest(res.file_index);
const imported_root_decl = pt.zcu.fileRootDecl(res.file_index);
break :blk .{ res, imported_path_digest, imported_root_decl };
const imported_root_type = pt.zcu.fileRootType(res.file_index);
break :blk .{ res, imported_path_digest, imported_root_type };
};
if (import_result.is_new) {
log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
@ -4433,7 +4358,7 @@ fn workerAstGenFile(
.import_tok = item.data.token,
} };
comp.thread_pool.spawnWgId(wg, workerAstGenFile, .{
comp, import_result.file, import_result.file_index, imported_path_digest, imported_root_decl, prog_node, wg, sub_src,
comp, import_result.file, import_result.file_index, imported_path_digest, imported_root_type, prog_node, wg, sub_src,
});
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -254,7 +254,7 @@ const UnpackValueBits = struct {
.error_set_type,
.inferred_error_set_type,
.variable,
.extern_func,
.@"extern",
.func,
.err,
.error_union,

View File

@ -217,15 +217,23 @@ fn loadComptimePtrInner(
};
const base_val: MutableValue = switch (ptr.base_addr) {
.decl => |decl_index| val: {
try sema.declareDependency(.{ .decl_val = decl_index });
try sema.ensureDeclAnalyzed(decl_index);
const decl = zcu.declPtr(decl_index);
if (decl.val.getVariable(zcu) != null) return .runtime_load;
break :val .{ .interned = decl.val.toIntern() };
.nav => |nav| val: {
try sema.declareDependency(.{ .nav_val = nav });
try sema.ensureNavResolved(src, nav);
const val = ip.getNav(nav).status.resolved.val;
switch (ip.indexToKey(val)) {
.variable => return .runtime_load,
// We let `.@"extern"` through here if it's a function.
// This allows you to alias `extern fn`s.
.@"extern" => |e| if (Type.fromInterned(e.ty).zigTypeTag(zcu) == .Fn)
break :val .{ .interned = val }
else
return .runtime_load,
else => break :val .{ .interned = val },
}
},
.comptime_alloc => |alloc_index| sema.getComptimeAlloc(alloc_index).val,
.anon_decl => |anon_decl| .{ .interned = anon_decl.val },
.uav => |uav| .{ .interned = uav.val },
.comptime_field => |val| .{ .interned = val },
.int => return .runtime_load,
.eu_payload => |base_ptr_ip| val: {
@ -580,7 +588,7 @@ fn prepareComptimePtrStore(
// `base_strat` will not be an error case.
const base_strat: ComptimeStoreStrategy = switch (ptr.base_addr) {
.decl, .anon_decl, .int => return .runtime_store,
.nav, .uav, .int => return .runtime_store,
.comptime_field => return .comptime_field,
.comptime_alloc => |alloc_index| .{ .direct = .{
.alloc = alloc_index,

View File

@ -268,9 +268,9 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
return;
},
.inferred_error_set_type => |func_index| {
const owner_decl = mod.funcOwnerDeclPtr(func_index);
const func_nav = ip.getNav(mod.funcInfo(func_index).owner_nav);
try writer.print("@typeInfo(@typeInfo(@TypeOf({})).Fn.return_type.?).ErrorUnion.error_set", .{
owner_decl.fqn.fmt(ip),
func_nav.fqn.fmt(ip),
});
},
.error_set_type => |error_set_type| {
@ -331,15 +331,11 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
.generic_poison => unreachable,
},
.struct_type => {
const struct_type = ip.loadStructType(ty.toIntern());
if (struct_type.decl.unwrap()) |decl_index| {
const decl = mod.declPtr(decl_index);
try writer.print("{}", .{decl.fqn.fmt(ip)});
} else if (ip.loadStructType(ty.toIntern()).namespace.unwrap()) |namespace_index| {
const namespace = mod.namespacePtr(namespace_index);
try namespace.renderFullyQualifiedName(ip, .empty, writer);
} else {
const name = ip.loadStructType(ty.toIntern()).name;
if (name == .empty) {
try writer.writeAll("@TypeOf(.{})");
} else {
try writer.print("{}", .{name.fmt(ip)});
}
},
.anon_struct_type => |anon_struct| {
@ -366,16 +362,16 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
},
.union_type => {
const decl = mod.declPtr(ip.loadUnionType(ty.toIntern()).decl);
try writer.print("{}", .{decl.fqn.fmt(ip)});
const name = ip.loadUnionType(ty.toIntern()).name;
try writer.print("{}", .{name.fmt(ip)});
},
.opaque_type => {
const decl = mod.declPtr(ip.loadOpaqueType(ty.toIntern()).decl);
try writer.print("{}", .{decl.fqn.fmt(ip)});
const name = ip.loadOpaqueType(ty.toIntern()).name;
try writer.print("{}", .{name.fmt(ip)});
},
.enum_type => {
const decl = mod.declPtr(ip.loadEnumType(ty.toIntern()).decl);
try writer.print("{}", .{decl.fqn.fmt(ip)});
const name = ip.loadEnumType(ty.toIntern()).name;
try writer.print("{}", .{name.fmt(ip)});
},
.func_type => |fn_info| {
if (fn_info.is_noinline) {
@ -427,7 +423,7 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -645,7 +641,7 @@ pub fn hasRuntimeBitsAdvanced(
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -757,7 +753,7 @@ pub fn hasWellDefinedLayout(ty: Type, mod: *Module) bool {
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -1108,7 +1104,7 @@ pub fn abiAlignmentAdvanced(
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -1483,7 +1479,7 @@ pub fn abiSizeAdvanced(
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -1813,7 +1809,7 @@ pub fn bitSizeAdvanced(
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -2351,7 +2347,7 @@ pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType {
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -2700,7 +2696,7 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -2899,7 +2895,7 @@ pub fn comptimeOnlyAdvanced(ty: Type, pt: Zcu.PerThread, comptime strat: Resolve
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -2972,41 +2968,27 @@ pub fn indexableHasLen(ty: Type, mod: *Module) bool {
}
/// Asserts that the type can have a namespace.
pub fn getNamespaceIndex(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex {
return ty.getNamespace(zcu).?;
pub fn getNamespaceIndex(ty: Type, zcu: *Zcu) InternPool.NamespaceIndex {
return ty.getNamespace(zcu).unwrap().?;
}
/// Returns null if the type has no namespace.
pub fn getNamespace(ty: Type, zcu: *Zcu) ?InternPool.OptionalNamespaceIndex {
pub fn getNamespace(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex {
const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
.opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace,
.opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace.toOptional(),
.struct_type => ip.loadStructType(ty.toIntern()).namespace,
.union_type => ip.loadUnionType(ty.toIntern()).namespace,
.enum_type => ip.loadEnumType(ty.toIntern()).namespace,
.anon_struct_type => .none,
.simple_type => |s| switch (s) {
.anyopaque,
.atomic_order,
.atomic_rmw_op,
.calling_convention,
.address_space,
.float_mode,
.reduce_op,
.call_modifier,
.prefetch_options,
.export_options,
.extern_options,
.type_info,
=> .none,
else => null,
},
else => null,
.union_type => ip.loadUnionType(ty.toIntern()).namespace.toOptional(),
.enum_type => ip.loadEnumType(ty.toIntern()).namespace.toOptional(),
else => .none,
};
}
// TODO: new dwarf structure will also need the enclosing code block for types created in imperative scopes
pub fn getParentNamespace(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex {
return zcu.namespacePtr(ty.getNamespace(zcu).unwrap() orelse return .none).parent;
}
// Works for vectors and vectors of integers.
pub fn minInt(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value {
const mod = pt.zcu;
@ -3321,21 +3303,6 @@ pub fn structFieldOffset(ty: Type, index: usize, pt: Zcu.PerThread) u64 {
}
}
pub fn getOwnerDecl(ty: Type, mod: *Module) InternPool.DeclIndex {
return ty.getOwnerDeclOrNull(mod) orelse unreachable;
}
pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?InternPool.DeclIndex {
const ip = &mod.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => ip.loadStructType(ty.toIntern()).decl.unwrap(),
.union_type => ip.loadUnionType(ty.toIntern()).decl,
.opaque_type => ip.loadOpaqueType(ty.toIntern()).decl,
.enum_type => ip.loadEnumType(ty.toIntern()).decl,
else => null,
};
}
pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Module.LazySrcLoc {
const ip = &zcu.intern_pool;
return .{
@ -3366,7 +3333,7 @@ pub fn isTuple(ty: Type, mod: *Module) bool {
.struct_type => {
const struct_type = ip.loadStructType(ty.toIntern());
if (struct_type.layout == .@"packed") return false;
if (struct_type.decl == .none) return false;
if (struct_type.cau == .none) return false;
return struct_type.flagsUnordered(ip).is_tuple;
},
.anon_struct_type => |anon_struct| anon_struct.names.len == 0,
@ -3388,7 +3355,7 @@ pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool {
.struct_type => {
const struct_type = ip.loadStructType(ty.toIntern());
if (struct_type.layout == .@"packed") return false;
if (struct_type.decl == .none) return false;
if (struct_type.cau == .none) return false;
return struct_type.flagsUnordered(ip).is_tuple;
},
.anon_struct_type => true,
@ -3444,6 +3411,21 @@ pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
};
}
pub fn typeDeclInstAllowGeneratedTag(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => ip.loadStructType(ty.toIntern()).zir_index.unwrap(),
.union_type => ip.loadUnionType(ty.toIntern()).zir_index,
.enum_type => |e| switch (e) {
.declared, .reified => ip.loadEnumType(ty.toIntern()).zir_index.unwrap().?,
.generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
.empty_struct => unreachable,
},
.opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
else => null,
};
}
pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
const ip = &zcu.intern_pool;
const tracked = switch (ip.indexToKey(ty.toIntern())) {
@ -3471,7 +3453,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
};
}
/// Given a namespace type, returns its list of caotured values.
/// Given a namespace type, returns its list of captured values.
pub fn getCaptures(ty: Type, zcu: *const Zcu) InternPool.CaptureValue.Slice {
const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
@ -3773,7 +3755,11 @@ fn resolveStructInner(
const gpa = zcu.gpa;
const struct_obj = zcu.typeToStruct(ty).?;
const owner_decl_index = struct_obj.decl.unwrap() orelse return;
const owner = InternPool.AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap() orelse return });
if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
return error.AnalysisFail;
}
var analysis_arena = std.heap.ArenaAllocator.init(gpa);
defer analysis_arena.deinit();
@ -3786,24 +3772,30 @@ fn resolveStructInner(
.gpa = gpa,
.arena = analysis_arena.allocator(),
.code = undefined, // This ZIR will not be used.
.owner_decl = zcu.declPtr(owner_decl_index),
.owner_decl_index = owner_decl_index,
.owner = owner,
.func_index = .none,
.func_is_naked = false,
.fn_ret_ty = Type.void,
.fn_ret_ty_ies = null,
.owner_func_index = .none,
.comptime_err_ret_trace = &comptime_err_ret_trace,
};
defer sema.deinit();
switch (resolution) {
.fields => return sema.resolveTypeFieldsStruct(ty.toIntern(), struct_obj),
.inits => return sema.resolveStructFieldInits(ty),
.alignment => return sema.resolveStructAlignment(ty.toIntern(), struct_obj),
.layout => return sema.resolveStructLayout(ty),
.full => return sema.resolveStructFully(ty),
}
(switch (resolution) {
.fields => sema.resolveTypeFieldsStruct(ty.toIntern(), struct_obj),
.inits => sema.resolveStructFieldInits(ty),
.alignment => sema.resolveStructAlignment(ty.toIntern(), struct_obj),
.layout => sema.resolveStructLayout(ty),
.full => sema.resolveStructFully(ty),
}) catch |err| switch (err) {
error.AnalysisFail => {
if (!zcu.failed_analysis.contains(owner)) {
try zcu.transitive_failed_analysis.put(gpa, owner, {});
}
return error.AnalysisFail;
},
error.OutOfMemory => |e| return e,
};
}
/// `ty` must be a union.
@ -3816,7 +3808,11 @@ fn resolveUnionInner(
const gpa = zcu.gpa;
const union_obj = zcu.typeToUnion(ty).?;
const owner_decl_index = union_obj.decl;
const owner = InternPool.AnalUnit.wrap(.{ .cau = union_obj.cau });
if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
return error.AnalysisFail;
}
var analysis_arena = std.heap.ArenaAllocator.init(gpa);
defer analysis_arena.deinit();
@ -3829,23 +3825,29 @@ fn resolveUnionInner(
.gpa = gpa,
.arena = analysis_arena.allocator(),
.code = undefined, // This ZIR will not be used.
.owner_decl = zcu.declPtr(owner_decl_index),
.owner_decl_index = owner_decl_index,
.owner = owner,
.func_index = .none,
.func_is_naked = false,
.fn_ret_ty = Type.void,
.fn_ret_ty_ies = null,
.owner_func_index = .none,
.comptime_err_ret_trace = &comptime_err_ret_trace,
};
defer sema.deinit();
switch (resolution) {
.fields => return sema.resolveTypeFieldsUnion(ty, union_obj),
.alignment => return sema.resolveUnionAlignment(ty, union_obj),
.layout => return sema.resolveUnionLayout(ty),
.full => return sema.resolveUnionFully(ty),
}
(switch (resolution) {
.fields => sema.resolveTypeFieldsUnion(ty, union_obj),
.alignment => sema.resolveUnionAlignment(ty, union_obj),
.layout => sema.resolveUnionLayout(ty),
.full => sema.resolveUnionFully(ty),
}) catch |err| switch (err) {
error.AnalysisFail => {
if (!zcu.failed_analysis.contains(owner)) {
try zcu.transitive_failed_analysis.put(gpa, owner, {});
}
return error.AnalysisFail;
},
error.OutOfMemory => |e| return e,
};
}
/// Fully resolves a simple type. This is usually a nop, but for builtin types with
@ -3945,6 +3947,16 @@ pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type {
});
}
pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTerminatedString {
return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => ip.loadStructType(ty.toIntern()).name,
.union_type => ip.loadUnionType(ty.toIntern()).name,
.enum_type => ip.loadEnumType(ty.toIntern()).name,
.opaque_type => ip.loadOpaqueType(ty.toIntern()).name,
else => unreachable,
};
}
pub const @"u1": Type = .{ .ip_index = .u1_type };
pub const @"u8": Type = .{ .ip_index = .u8_type };
pub const @"u16": Type = .{ .ip_index = .u16_type };

View File

@ -227,13 +227,6 @@ pub fn getFunction(val: Value, mod: *Module) ?InternPool.Key.Func {
};
}
pub fn getExternFunc(val: Value, mod: *Module) ?InternPool.Key.ExternFunc {
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
.extern_func => |extern_func| extern_func,
else => null,
};
}
pub fn getVariable(val: Value, mod: *Module) ?InternPool.Key.Variable {
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
.variable => |variable| variable,
@ -319,17 +312,8 @@ pub fn toBool(val: Value) bool {
};
}
fn ptrHasIntAddr(val: Value, mod: *Module) bool {
var check = val;
while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) {
.ptr => |ptr| switch (ptr.base_addr) {
.decl, .comptime_alloc, .comptime_field, .anon_decl => return false,
.int => return true,
.eu_payload, .opt_payload => |base| check = Value.fromInterned(base),
.arr_elem, .field => |base_index| check = Value.fromInterned(base_index.base),
},
else => unreachable,
};
fn ptrHasIntAddr(val: Value, zcu: *Zcu) bool {
return zcu.intern_pool.getBackingAddrTag(val.toIntern()).? == .int;
}
/// Write a Value's contents to `buffer`.
@ -1058,7 +1042,7 @@ pub fn orderAgainstZeroAdvanced(
.bool_true => .gt,
else => switch (pt.zcu.intern_pool.indexToKey(lhs.toIntern())) {
.ptr => |ptr| if (ptr.byte_offset > 0) .gt else switch (ptr.base_addr) {
.decl, .comptime_alloc, .comptime_field => .gt,
.nav, .comptime_alloc, .comptime_field => .gt,
.int => .eq,
else => unreachable,
},
@ -1130,11 +1114,11 @@ pub fn compareHeteroAdvanced(
pt: Zcu.PerThread,
comptime strat: ResolveStrat,
) !bool {
if (lhs.pointerDecl(pt.zcu)) |lhs_decl| {
if (rhs.pointerDecl(pt.zcu)) |rhs_decl| {
if (lhs.pointerNav(pt.zcu)) |lhs_nav| {
if (rhs.pointerNav(pt.zcu)) |rhs_nav| {
switch (op) {
.eq => return lhs_decl == rhs_decl,
.neq => return lhs_decl != rhs_decl,
.eq => return lhs_nav == rhs_nav,
.neq => return lhs_nav != rhs_nav,
else => {},
}
} else {
@ -1144,7 +1128,7 @@ pub fn compareHeteroAdvanced(
else => {},
}
}
} else if (rhs.pointerDecl(pt.zcu)) |_| {
} else if (rhs.pointerNav(pt.zcu)) |_| {
switch (op) {
.eq => return false,
.neq => return true,
@ -1252,12 +1236,12 @@ pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool {
.payload => |payload| Value.fromInterned(payload).canMutateComptimeVarState(zcu),
},
.ptr => |ptr| switch (ptr.base_addr) {
.decl => false, // The value of a Decl can never reference a comptime alloc.
.nav => false, // The value of a Nav can never reference a comptime alloc.
.int => false,
.comptime_alloc => true, // A comptime alloc is either mutable or references comptime-mutable memory.
.comptime_field => true, // Comptime field pointers are comptime-mutable, albeit only to the "correct" value.
.eu_payload, .opt_payload => |base| Value.fromInterned(base).canMutateComptimeVarState(zcu),
.anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).canMutateComptimeVarState(zcu),
.uav => |uav| Value.fromInterned(uav.val).canMutateComptimeVarState(zcu),
.arr_elem, .field => |base_index| Value.fromInterned(base_index.base).canMutateComptimeVarState(zcu),
},
.slice => |slice| return Value.fromInterned(slice.ptr).canMutateComptimeVarState(zcu),
@ -1273,16 +1257,17 @@ pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool {
};
}
/// Gets the decl referenced by this pointer. If the pointer does not point
/// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr),
/// this function returns null.
pub fn pointerDecl(val: Value, mod: *Module) ?InternPool.DeclIndex {
/// Gets the `Nav` referenced by this pointer. If the pointer does not point
/// to a `Nav`, or if it points to some part of one (like a field or element),
/// returns null.
pub fn pointerNav(val: Value, mod: *Module) ?InternPool.Nav.Index {
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
.variable => |variable| variable.decl,
.extern_func => |extern_func| extern_func.decl,
.func => |func| func.owner_decl,
// TODO: these 3 cases are weird; these aren't pointer values!
.variable => |v| v.owner_nav,
.@"extern" => |e| e.owner_nav,
.func => |func| func.owner_nav,
.ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
.decl => |decl| decl,
.nav => |nav| nav,
else => null,
} else null,
else => null,
@ -1341,10 +1326,14 @@ pub fn isLazySize(val: Value, mod: *Module) bool {
};
}
pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {
const backing_decl = mod.intern_pool.getBackingDecl(val.toIntern()).unwrap() orelse return false;
const variable = mod.declPtr(backing_decl).getOwnedVariable(mod) orelse return false;
return variable.is_threadlocal;
pub fn isPtrToThreadLocal(val: Value, zcu: *Zcu) bool {
const ip = &zcu.intern_pool;
const nav = ip.getBackingNav(val.toIntern()).unwrap() orelse return false;
return switch (ip.indexToKey(ip.getNav(nav).status.resolved.val)) {
.@"extern" => |e| e.is_threadlocal,
.variable => |v| v.is_threadlocal,
else => false,
};
}
// Asserts that the provided start/end are in-bounds.
@ -4031,8 +4020,8 @@ pub const PointerDeriveStep = union(enum) {
addr: u64,
ptr_ty: Type,
},
decl_ptr: InternPool.DeclIndex,
anon_decl_ptr: InternPool.Key.Ptr.BaseAddr.AnonDecl,
nav_ptr: InternPool.Nav.Index,
uav_ptr: InternPool.Key.Ptr.BaseAddr.Uav,
comptime_alloc_ptr: struct {
val: Value,
ptr_ty: Type,
@ -4069,8 +4058,8 @@ pub const PointerDeriveStep = union(enum) {
pub fn ptrType(step: PointerDeriveStep, pt: Zcu.PerThread) !Type {
return switch (step) {
.int => |int| int.ptr_ty,
.decl_ptr => |decl| try pt.zcu.declPtr(decl).declPtrType(pt),
.anon_decl_ptr => |ad| Type.fromInterned(ad.orig_ty),
.nav_ptr => |nav| try pt.navPtrType(nav),
.uav_ptr => |uav| Type.fromInterned(uav.orig_ty),
.comptime_alloc_ptr => |info| info.ptr_ty,
.comptime_field_ptr => |val| try pt.singleConstPtrType(val.typeOf(pt.zcu)),
.offset_and_cast => |oac| oac.new_ptr_ty,
@ -4098,17 +4087,17 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
.addr = ptr.byte_offset,
.ptr_ty = Type.fromInterned(ptr.ty),
} },
.decl => |decl| .{ .decl_ptr = decl },
.anon_decl => |ad| base: {
.nav => |nav| .{ .nav_ptr = nav },
.uav => |uav| base: {
// A slight tweak: `orig_ty` here is sometimes not `const`, but it ought to be.
// TODO: fix this in the sites interning anon decls!
const const_ty = try pt.ptrType(info: {
var info = Type.fromInterned(ad.orig_ty).ptrInfo(zcu);
var info = Type.fromInterned(uav.orig_ty).ptrInfo(zcu);
info.flags.is_const = true;
break :info info;
});
break :base .{ .anon_decl_ptr = .{
.val = ad.val,
break :base .{ .uav_ptr = .{
.val = uav.val,
.orig_ty = const_ty.toIntern(),
} };
},
@ -4357,7 +4346,7 @@ pub fn resolveLazy(val: Value, arena: Allocator, pt: Zcu.PerThread) Zcu.SemaErro
},
.ptr => |ptr| {
switch (ptr.base_addr) {
.decl, .comptime_alloc, .anon_decl, .int => return val,
.nav, .comptime_alloc, .uav, .int => return val,
.comptime_field => |field_val| {
const resolved_field_val = (try Value.fromInterned(field_val).resolveLazy(arena, pt)).toIntern();
return if (resolved_field_val == field_val)

View File

@ -118,8 +118,15 @@ embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},
/// is not yet implemented.
intern_pool: InternPool = .{},
analysis_in_progress: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{},
/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, *ErrorMsg) = .{},
/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed.
transitive_failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{},
/// This `Nav` succeeded analysis, but failed codegen.
/// This may be a simple "value" `Nav`, or it may be a function.
/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
failed_codegen: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, *ErrorMsg) = .{},
/// Keep track of one `@compileLog` callsite per `AnalUnit`.
/// The value is the source location of the `@compileLog` call, convertible to a `LazySrcLoc`.
compile_log_sources: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
@ -155,12 +162,12 @@ outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
/// Such `AnalUnit`s are ready for immediate re-analysis.
/// See `findOutdatedToAnalyze` for details.
outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{},
/// This contains a set of Decls which may not be in `outdated`, but are the
/// root Decls of files which have updated source and thus must be re-analyzed.
/// If such a Decl is only in this set, the struct type index may be preserved
/// (only the namespace might change). If such a Decl is also `outdated`, the
/// struct type index must be recreated.
outdated_file_root: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
/// This contains a set of struct types whose corresponding `Cau` may not be in
/// `outdated`, but are the root types of files which have updated source and
/// thus must be re-analyzed. If such a type is only in this set, the struct type
/// index may be preserved (only the namespace might change). If its owned `Cau`
/// is also outdated, the struct type index must be recreated.
outdated_file_root: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{},
/// This contains a list of AnalUnit whose analysis or codegen failed, but the
/// failure was something like running out of disk space, and trying again may
/// succeed. On the next update, we will flush this list, marking all members of
@ -179,12 +186,9 @@ stage1_flags: packed struct {
compile_log_text: std.ArrayListUnmanaged(u8) = .{},
emit_h: ?*GlobalEmitH,
test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .{},
test_functions: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
/// TODO: the key here will be a `Cau.Index`.
global_assembly: std.AutoArrayHashMapUnmanaged(Decl.Index, []u8) = .{},
global_assembly: std.AutoArrayHashMapUnmanaged(InternPool.Cau.Index, []u8) = .{},
/// Key is the `AnalUnit` *performing* the reference. This representation allows
/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
@ -196,7 +200,7 @@ all_references: std.ArrayListUnmanaged(Reference) = .{},
/// Freelist of indices in `all_references`.
free_references: std.ArrayListUnmanaged(u32) = .{},
panic_messages: [PanicId.len]Decl.OptionalIndex = .{.none} ** PanicId.len,
panic_messages: [PanicId.len]InternPool.Nav.Index.Optional = .{.none} ** PanicId.len,
/// The panic function body.
panic_func_index: InternPool.Index = .none,
null_stack_trace: InternPool.Index = .none,
@ -250,45 +254,25 @@ pub const CImportError = struct {
}
};
/// A `Module` has zero or one of these depending on whether `-femit-h` is enabled.
pub const GlobalEmitH = struct {
/// Where to put the output.
loc: Compilation.EmitLoc,
/// When emit_h is non-null, each Decl gets one more compile error slot for
/// emit-h failing for that Decl. This table is also how we tell if a Decl has
/// failed emit-h or succeeded.
failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{},
/// Tracks all decls in order to iterate over them and emit .h code for them.
decl_table: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
/// Similar to the allocated_decls field of Module, this is where `EmitH` objects
/// are allocated. There will be exactly one EmitH object per Decl object, with
/// identical indexes.
allocated_emit_h: std.SegmentedList(EmitH, 0) = .{},
pub fn declPtr(global_emit_h: *GlobalEmitH, decl_index: Decl.Index) *EmitH {
return global_emit_h.allocated_emit_h.at(@intFromEnum(decl_index));
}
};
pub const ErrorInt = u32;
pub const Exported = union(enum) {
/// The Decl being exported. Note this is *not* the Decl performing the export.
decl_index: Decl.Index,
/// The Nav being exported. Note this is *not* the Nav corresponding to the AnalUnit performing the export.
nav: InternPool.Nav.Index,
/// Constant value being exported.
value: InternPool.Index,
uav: InternPool.Index,
pub fn getValue(exported: Exported, zcu: *Zcu) Value {
return switch (exported) {
.decl_index => |decl_index| zcu.declPtr(decl_index).val,
.value => |value| Value.fromInterned(value),
.nav => |nav| zcu.navValue(nav),
.uav => |uav| Value.fromInterned(uav),
};
}
pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment {
return switch (exported) {
.decl_index => |decl_index| zcu.declPtr(decl_index).alignment,
.value => .none,
.nav => |nav| zcu.intern_pool.getNav(nav).status.resolved.alignment,
.uav => .none,
};
}
};
@ -324,302 +308,54 @@ pub const Reference = struct {
src: LazySrcLoc,
};
pub const Decl = struct {
/// Equal to `fqn` if already fully qualified.
name: InternPool.NullTerminatedString,
/// Fully qualified name.
fqn: InternPool.NullTerminatedString,
/// The most recent Value of the Decl after a successful semantic analysis.
/// Populated when `has_tv`.
val: Value,
/// Populated when `has_tv`.
@"linksection": InternPool.OptionalNullTerminatedString,
/// Populated when `has_tv`.
alignment: Alignment,
/// Populated when `has_tv`.
@"addrspace": std.builtin.AddressSpace,
/// The direct parent namespace of the Decl. In the case of the Decl
/// corresponding to a file, this is the namespace of the struct, since
/// there is no parent.
src_namespace: Namespace.Index,
/// Index of the ZIR `declaration` instruction from which this `Decl` was created.
/// For the root `Decl` of a `File` and legacy anonymous decls, this is `.none`.
zir_decl_index: InternPool.TrackedInst.Index.Optional,
/// Represents the "shallow" analysis status. For example, for decls that are functions,
/// the function type is analyzed with this set to `in_progress`, however, the semantic
/// analysis of the function body is performed with this value set to `success`. Functions
/// have their own analysis status field.
analysis: enum {
/// This Decl corresponds to an AST Node that has not been referenced yet, and therefore
/// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced.
unreferenced,
/// Semantic analysis for this Decl is running right now.
/// This state detects dependency loops.
in_progress,
/// The file corresponding to this Decl had a parse error or ZIR error.
/// There will be a corresponding ErrorMsg in Zcu.failed_files.
file_failure,
/// This Decl might be OK but it depends on another one which did not
/// successfully complete semantic analysis.
dependency_failure,
/// Semantic analysis failure.
/// There will be a corresponding ErrorMsg in Zcu.failed_analysis.
sema_failure,
/// There will be a corresponding ErrorMsg in Zcu.failed_analysis.
codegen_failure,
/// Sematic analysis and constant value codegen of this Decl has
/// succeeded. However, the Decl may be outdated due to an in-progress
/// update. Note that for a function, this does not mean codegen of the
/// function body succeded: that state is indicated by the function's
/// `analysis` field.
complete,
},
/// Whether `typed_value`, `align`, `linksection` and `addrspace` are populated.
has_tv: bool,
/// If `true` it means the `Decl` is the resource owner of the type/value associated
/// with it. That means when `Decl` is destroyed, the cleanup code should additionally
/// check if the value owns a `Namespace`, and destroy that too.
owns_tv: bool,
/// Whether the corresponding AST decl has a `pub` keyword.
is_pub: bool,
/// Whether the corresponding AST decl has a `export` keyword.
is_exported: bool,
/// What kind of a declaration is this.
kind: Kind,
pub const Kind = enum {
@"usingnamespace",
@"test",
@"comptime",
named,
anon,
};
pub const Index = InternPool.DeclIndex;
pub const OptionalIndex = InternPool.OptionalDeclIndex;
pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {
const zir = decl.getFileScope(zcu).zir;
const zir_index = decl.zir_decl_index.unwrap().?.resolve(&zcu.intern_pool);
const declaration = zir.instructions.items(.data)[@intFromEnum(zir_index)].declaration;
const extra = zir.extraData(Zir.Inst.Declaration, declaration.payload_index);
return extra.data.getBodies(@intCast(extra.end), zir);
}
pub fn typeOf(decl: Decl, zcu: *const Zcu) Type {
assert(decl.has_tv);
return decl.val.typeOf(zcu);
}
/// Small wrapper for Sema to use over direct access to the `val` field.
/// If the value is not populated, instead returns `error.AnalysisFail`.
pub fn valueOrFail(decl: Decl) error{AnalysisFail}!Value {
if (!decl.has_tv) return error.AnalysisFail;
return decl.val;
}
pub fn getOwnedFunction(decl: Decl, zcu: *Zcu) ?InternPool.Key.Func {
const i = decl.getOwnedFunctionIndex();
if (i == .none) return null;
return switch (zcu.intern_pool.indexToKey(i)) {
.func => |func| func,
else => null,
};
}
/// This returns an InternPool.Index even when the value is not a function.
pub fn getOwnedFunctionIndex(decl: Decl) InternPool.Index {
return if (decl.owns_tv) decl.val.toIntern() else .none;
}
/// If the Decl owns its value and it is an extern function, returns it,
/// otherwise null.
pub fn getOwnedExternFunc(decl: Decl, zcu: *Zcu) ?InternPool.Key.ExternFunc {
return if (decl.owns_tv) decl.val.getExternFunc(zcu) else null;
}
/// If the Decl owns its value and it is a variable, returns it,
/// otherwise null.
pub fn getOwnedVariable(decl: Decl, zcu: *Zcu) ?InternPool.Key.Variable {
return if (decl.owns_tv) decl.val.getVariable(zcu) else null;
}
/// Gets the namespace that this Decl creates by being a struct, union,
/// enum, or opaque.
pub fn getInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex {
if (!decl.has_tv) return .none;
const ip = &zcu.intern_pool;
return switch (decl.val.ip_index) {
.empty_struct_type => .none,
.none => .none,
else => switch (ip.indexToKey(decl.val.toIntern())) {
.opaque_type => ip.loadOpaqueType(decl.val.toIntern()).namespace,
.struct_type => ip.loadStructType(decl.val.toIntern()).namespace,
.union_type => ip.loadUnionType(decl.val.toIntern()).namespace,
.enum_type => ip.loadEnumType(decl.val.toIntern()).namespace,
else => .none,
},
};
}
/// Like `getInnerNamespaceIndex`, but only returns it if the Decl is the owner.
pub fn getOwnedInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex {
if (!decl.owns_tv) return .none;
return decl.getInnerNamespaceIndex(zcu);
}
/// Same as `getOwnedInnerNamespaceIndex` but additionally obtains the pointer.
pub fn getOwnedInnerNamespace(decl: Decl, zcu: *Zcu) ?*Namespace {
return zcu.namespacePtrUnwrap(decl.getOwnedInnerNamespaceIndex(zcu));
}
/// Same as `getInnerNamespaceIndex` but additionally obtains the pointer.
pub fn getInnerNamespace(decl: Decl, zcu: *Zcu) ?*Namespace {
return zcu.namespacePtrUnwrap(decl.getInnerNamespaceIndex(zcu));
}
pub fn getFileScope(decl: Decl, zcu: *Zcu) *File {
return zcu.fileByIndex(getFileScopeIndex(decl, zcu));
}
pub fn getFileScopeIndex(decl: Decl, zcu: *Zcu) File.Index {
return zcu.namespacePtr(decl.src_namespace).file_scope;
}
pub fn getExternDecl(decl: Decl, zcu: *Zcu) OptionalIndex {
assert(decl.has_tv);
return switch (zcu.intern_pool.indexToKey(decl.val.toIntern())) {
.variable => |variable| if (variable.is_extern) variable.decl.toOptional() else .none,
.extern_func => |extern_func| extern_func.decl.toOptional(),
else => .none,
};
}
pub fn isExtern(decl: Decl, zcu: *Zcu) bool {
return decl.getExternDecl(zcu) != .none;
}
pub fn getAlignment(decl: Decl, pt: Zcu.PerThread) Alignment {
assert(decl.has_tv);
if (decl.alignment != .none) return decl.alignment;
return decl.typeOf(pt.zcu).abiAlignment(pt);
}
pub fn declPtrType(decl: Decl, pt: Zcu.PerThread) !Type {
assert(decl.has_tv);
const decl_ty = decl.typeOf(pt.zcu);
return pt.ptrType(.{
.child = decl_ty.toIntern(),
.flags = .{
.alignment = if (decl.alignment == decl_ty.abiAlignment(pt))
.none
else
decl.alignment,
.address_space = decl.@"addrspace",
.is_const = decl.getOwnedVariable(pt.zcu) == null,
},
});
}
/// Returns the source location of this `Decl`.
/// Asserts that this `Decl` corresponds to what will in future be a `Nav` (Named
/// Addressable Value): a source-level declaration or generic instantiation.
pub fn navSrcLoc(decl: Decl, zcu: *Zcu) LazySrcLoc {
return .{
.base_node_inst = decl.zir_decl_index.unwrap() orelse inst: {
// generic instantiation
assert(decl.has_tv);
assert(decl.owns_tv);
const owner = zcu.funcInfo(decl.val.toIntern()).generic_owner;
const generic_owner_decl = zcu.declPtr(zcu.funcInfo(owner).owner_decl);
break :inst generic_owner_decl.zir_decl_index.unwrap().?;
},
.offset = LazySrcLoc.Offset.nodeOffset(0),
};
}
pub fn navSrcLine(decl: Decl, zcu: *Zcu) u32 {
const ip = &zcu.intern_pool;
const tracked = decl.zir_decl_index.unwrap() orelse inst: {
// generic instantiation
assert(decl.has_tv);
assert(decl.owns_tv);
const generic_owner_func = switch (ip.indexToKey(decl.val.toIntern())) {
.func => |func| func.generic_owner,
else => return 0, // TODO: this is probably a `variable` or something; figure this out when we finish sorting out `Decl`.
};
const generic_owner_decl = zcu.declPtr(zcu.funcInfo(generic_owner_func).owner_decl);
break :inst generic_owner_decl.zir_decl_index.unwrap().?;
};
const info = tracked.resolveFull(ip);
const file = zcu.fileByIndex(info.file);
assert(file.zir_loaded);
const zir = file.zir;
const inst = zir.instructions.get(@intFromEnum(info.inst));
assert(inst.tag == .declaration);
return zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line;
}
pub fn typeSrcLine(decl: Decl, zcu: *Zcu) u32 {
assert(decl.has_tv);
assert(decl.owns_tv);
return decl.val.toType().typeDeclSrcLine(zcu).?;
}
};
/// This state is attached to every Decl when Module emit_h is non-null.
pub const EmitH = struct {
fwd_decl: std.ArrayListUnmanaged(u8) = .{},
};
pub const DeclAdapter = struct {
zcu: *Zcu,
pub fn hash(self: @This(), s: InternPool.NullTerminatedString) u32 {
_ = self;
return std.hash.uint32(@intFromEnum(s));
}
pub fn eql(self: @This(), a: InternPool.NullTerminatedString, b_decl_index: Decl.Index, b_index: usize) bool {
_ = b_index;
return a == self.zcu.declPtr(b_decl_index).name;
}
};
/// The container that structs, enums, unions, and opaques have.
pub const Namespace = struct {
parent: OptionalIndex,
file_scope: File.Index,
/// Will be a struct, enum, union, or opaque.
decl_index: Decl.Index,
/// Direct children of the namespace.
/// Declaration order is preserved via entry order.
/// These are only declarations named directly by the AST; anonymous
/// declarations are not stored here.
decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{},
/// Key is usingnamespace Decl itself. To find the namespace being included,
/// the Decl Value has to be resolved as a Type which has a Namespace.
/// Value is whether the usingnamespace decl is marked `pub`.
usingnamespace_set: std.AutoHashMapUnmanaged(Decl.Index, bool) = .{},
owner_type: InternPool.Index,
/// Members of the namespace which are marked `pub`.
pub_decls: std.ArrayHashMapUnmanaged(InternPool.Nav.Index, void, NavNameContext, true) = .{},
/// Members of the namespace which are *not* marked `pub`.
priv_decls: std.ArrayHashMapUnmanaged(InternPool.Nav.Index, void, NavNameContext, true) = .{},
/// All `usingnamespace` declarations in this namespace which are marked `pub`.
pub_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .{},
/// All `usingnamespace` declarations in this namespace which are *not* marked `pub`.
priv_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .{},
/// All `comptime` and `test` declarations in this namespace. We store these purely so that
/// incremental compilation can re-use the existing `Cau`s when a namespace changes.
other_decls: std.ArrayListUnmanaged(InternPool.Cau.Index) = .{},
pub const Index = InternPool.NamespaceIndex;
pub const OptionalIndex = InternPool.OptionalNamespaceIndex;
const DeclContext = struct {
const NavNameContext = struct {
zcu: *Zcu,
pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 {
const decl = ctx.zcu.declPtr(decl_index);
return std.hash.uint32(@intFromEnum(decl.name));
pub fn hash(ctx: NavNameContext, nav: InternPool.Nav.Index) u32 {
const name = ctx.zcu.intern_pool.getNav(nav).name;
return std.hash.uint32(@intFromEnum(name));
}
pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool {
pub fn eql(ctx: NavNameContext, a_nav: InternPool.Nav.Index, b_nav: InternPool.Nav.Index, b_index: usize) bool {
_ = b_index;
const a_decl = ctx.zcu.declPtr(a_decl_index);
const b_decl = ctx.zcu.declPtr(b_decl_index);
return a_decl.name == b_decl.name;
const a_name = ctx.zcu.intern_pool.getNav(a_nav).name;
const b_name = ctx.zcu.intern_pool.getNav(b_nav).name;
return a_name == b_name;
}
};
pub const NameAdapter = struct {
zcu: *Zcu,
pub fn hash(ctx: NameAdapter, s: InternPool.NullTerminatedString) u32 {
_ = ctx;
return std.hash.uint32(@intFromEnum(s));
}
pub fn eql(ctx: NameAdapter, a: InternPool.NullTerminatedString, b_nav: InternPool.Nav.Index, b_index: usize) bool {
_ = b_index;
return a == ctx.zcu.intern_pool.getNav(b_nav).name;
}
};
@ -631,25 +367,6 @@ pub const Namespace = struct {
return ip.filePtr(ns.file_scope);
}
// This renders e.g. "std.fs.Dir.OpenOptions"
pub fn renderFullyQualifiedName(
ns: Namespace,
ip: *InternPool,
name: InternPool.NullTerminatedString,
writer: anytype,
) @TypeOf(writer).Error!void {
if (ns.parent.unwrap()) |parent| {
try ip.namespacePtr(parent).renderFullyQualifiedName(
ip,
ip.declPtr(ns.decl_index).name,
writer,
);
} else {
try ns.fileScopeIp(ip).renderFullyQualifiedName(writer);
}
if (name != .empty) try writer.print(".{}", .{name.fmt(ip)});
}
/// This renders e.g. "std/fs.zig:Dir.OpenOptions"
pub fn renderFullyQualifiedDebugName(
ns: Namespace,
@ -678,44 +395,9 @@ pub const Namespace = struct {
tid: Zcu.PerThread.Id,
name: InternPool.NullTerminatedString,
) !InternPool.NullTerminatedString {
const strings = ip.getLocal(tid).getMutableStrings(gpa);
// Protects reads of interned strings from being reallocated during the call to
// renderFullyQualifiedName.
const slice = try strings.addManyAsSlice(count: {
var count: usize = name.length(ip) + 1;
var cur_ns = &ns;
while (true) {
const decl = ip.declPtr(cur_ns.decl_index);
cur_ns = ip.namespacePtr(cur_ns.parent.unwrap() orelse {
count += ns.fileScopeIp(ip).fullyQualifiedNameLen();
break :count count;
});
count += decl.name.length(ip) + 1;
}
});
var fbs = std.io.fixedBufferStream(slice[0]);
ns.renderFullyQualifiedName(ip, name, fbs.writer()) catch unreachable;
assert(fbs.pos == slice[0].len);
// Sanitize the name for nvptx which is more restrictive.
// TODO This should be handled by the backend, not the frontend. Have a
// look at how the C backend does it for inspiration.
// FIXME This has bitrotted and is no longer able to be implemented here.
//const cpu_arch = zcu.root_mod.resolved_target.result.cpu.arch;
//if (cpu_arch.isNvptx()) {
// for (slice[0]) |*byte| switch (byte.*) {
// '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_',
// else => {},
// };
//}
return ip.getOrPutTrailingString(gpa, tid, @intCast(slice[0].len), .no_embedded_nulls);
}
pub fn getType(ns: Namespace, zcu: *Zcu) Type {
const decl = zcu.declPtr(ns.decl_index);
assert(decl.has_tv);
return decl.val.toType();
const ns_name = Type.fromInterned(ns.owner_type).containerTypeName(ip);
if (name == .empty) return ns_name;
return ip.getOrPutStringFmt(gpa, tid, "{}.{}", .{ ns_name.fmt(ip), name.fmt(ip) }, .no_embedded_nulls);
}
};
@ -2428,16 +2110,13 @@ pub fn deinit(zcu: *Zcu) void {
for (zcu.failed_analysis.values()) |value| {
value.destroy(gpa);
}
zcu.failed_analysis.deinit(gpa);
if (zcu.emit_h) |emit_h| {
for (emit_h.failed_decls.values()) |value| {
value.destroy(gpa);
}
emit_h.failed_decls.deinit(gpa);
emit_h.decl_table.deinit(gpa);
emit_h.allocated_emit_h.deinit(gpa);
for (zcu.failed_codegen.values()) |value| {
value.destroy(gpa);
}
zcu.analysis_in_progress.deinit(gpa);
zcu.failed_analysis.deinit(gpa);
zcu.transitive_failed_analysis.deinit(gpa);
zcu.failed_codegen.deinit(gpa);
for (zcu.failed_files.values()) |value| {
if (value) |msg| msg.destroy(gpa);
@ -2486,26 +2165,14 @@ pub fn deinit(zcu: *Zcu) void {
zcu.intern_pool.deinit(gpa);
}
pub fn declPtr(mod: *Zcu, index: Decl.Index) *Decl {
return mod.intern_pool.declPtr(index);
}
pub fn namespacePtr(mod: *Zcu, index: Namespace.Index) *Namespace {
return mod.intern_pool.namespacePtr(index);
pub fn namespacePtr(zcu: *Zcu, index: Namespace.Index) *Namespace {
return zcu.intern_pool.namespacePtr(index);
}
pub fn namespacePtrUnwrap(mod: *Zcu, index: Namespace.OptionalIndex) ?*Namespace {
return mod.namespacePtr(index.unwrap() orelse return null);
}
/// Returns true if and only if the Decl is the top level struct associated with a File.
pub fn declIsRoot(mod: *Zcu, decl_index: Decl.Index) bool {
const decl = mod.declPtr(decl_index);
const namespace = mod.namespacePtr(decl.src_namespace);
if (namespace.parent != .none) return false;
return decl_index == namespace.decl_index;
}
// TODO https://github.com/ziglang/zig/issues/8643
pub const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
pub const HackDataLayout = extern struct {
@ -2642,8 +2309,12 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
// If this is a Decl, we must recursively mark dependencies on its tyval
// as no longer PO.
switch (depender.unwrap()) {
.decl => |decl_index| try zcu.markPoDependeeUpToDate(.{ .decl_val = decl_index }),
.func => |func_index| try zcu.markPoDependeeUpToDate(.{ .func_ies = func_index }),
.cau => |cau| switch (zcu.intern_pool.getCau(cau).owner.unwrap()) {
.nav => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
.type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),
.none => {},
},
.func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }),
}
}
}
@ -2651,9 +2322,13 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
/// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may
/// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES.
fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void {
var it = zcu.intern_pool.dependencyIterator(switch (maybe_outdated.unwrap()) {
.decl => |decl_index| .{ .decl_val = decl_index }, // TODO: also `decl_ref` deps when introduced
.func => |func_index| .{ .func_ies = func_index },
const ip = &zcu.intern_pool;
var it = ip.dependencyIterator(switch (maybe_outdated.unwrap()) {
.cau => |cau| switch (ip.getCau(cau).owner.unwrap()) {
.nav => |nav| .{ .nav_val = nav }, // TODO: also `nav_ref` deps when introduced
.none, .type => return, // analysis of this `Cau` can't outdate any dependencies
},
.func => |func_index| .{ .interned = func_index }, // IES
});
while (it.next()) |po| {
@ -2680,6 +2355,8 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
if (!zcu.comp.incremental) return null;
if (true) @panic("TODO: findOutdatedToAnalyze");
if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {
log.debug("findOutdatedToAnalyze: no outdated depender", .{});
return null;
@ -2742,6 +2419,8 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
zcu.potentially_outdated.count(),
});
const Decl = {};
var chosen_decl_idx: ?Decl.Index = null;
var chosen_decl_dependers: u32 = undefined;
@ -2939,65 +2618,20 @@ pub fn mapOldZirToNew(
/// analyzed, and for ensuring it can exist at runtime (see
/// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body
/// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`.
pub fn ensureFuncBodyAnalysisQueued(mod: *Zcu, func_index: InternPool.Index) !void {
const ip = &mod.intern_pool;
const func = mod.funcInfo(func_index);
const decl_index = func.owner_decl;
const decl = mod.declPtr(decl_index);
switch (decl.analysis) {
.unreferenced => unreachable,
.in_progress => unreachable,
.file_failure,
.sema_failure,
.codegen_failure,
.dependency_failure,
// Analysis of the function Decl itself failed, but we've already
// emitted an error for that. The callee doesn't need the function to be
// analyzed right now, so its analysis can safely continue.
=> return,
.complete => {},
}
assert(decl.has_tv);
const func_as_depender = AnalUnit.wrap(.{ .func = func_index });
const is_outdated = mod.outdated.contains(func_as_depender) or
mod.potentially_outdated.contains(func_as_depender);
pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !void {
const ip = &zcu.intern_pool;
const func = zcu.funcInfo(func_index);
switch (func.analysisUnordered(ip).state) {
.none => {},
.queued => return,
// As above, we don't need to forward errors here.
.sema_failure,
.dependency_failure,
.codegen_failure,
.success,
=> if (!is_outdated) return,
.in_progress => return,
.inline_only => unreachable, // don't queue work for this
.unreferenced => {}, // We're the first reference!
.queued => return, // Analysis is already queued.
.analyzed => return, // Analysis is complete; if it's out-of-date, it'll be re-analyzed later this update.
}
// Decl itself is safely analyzed, and body analysis is not yet queued
try mod.comp.queueJob(.{ .analyze_func = func_index });
if (mod.emit_h != null) {
// TODO: we ideally only want to do this if the function's type changed
// since the last update
try mod.comp.queueJob(.{ .emit_h_decl = decl_index });
}
try zcu.comp.queueJob(.{ .analyze_func = func_index });
func.setAnalysisState(ip, .queued);
}
pub const SemaDeclResult = packed struct {
/// Whether the value of a `decl_val` of this Decl changed.
invalidate_decl_val: bool,
/// Whether the type of a `decl_ref` of this Decl changed.
invalidate_decl_ref: bool,
};
pub const ImportFileResult = struct {
file: *File,
file_index: File.Index,
@ -3171,14 +2805,15 @@ pub fn handleUpdateExports(
};
}
pub fn addGlobalAssembly(mod: *Zcu, decl_index: Decl.Index, source: []const u8) !void {
const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index);
pub fn addGlobalAssembly(zcu: *Zcu, cau: InternPool.Cau.Index, source: []const u8) !void {
const gpa = zcu.gpa;
const gop = try zcu.global_assembly.getOrPut(gpa, cau);
if (gop.found_existing) {
const new_value = try std.fmt.allocPrint(mod.gpa, "{s}\n{s}", .{ gop.value_ptr.*, source });
mod.gpa.free(gop.value_ptr.*);
const new_value = try std.fmt.allocPrint(gpa, "{s}\n{s}", .{ gop.value_ptr.*, source });
gpa.free(gop.value_ptr.*);
gop.value_ptr.* = new_value;
} else {
gop.value_ptr.* = try mod.gpa.dupe(u8, source);
gop.value_ptr.* = try gpa.dupe(u8, source);
}
}
@ -3315,10 +2950,6 @@ pub fn atomicPtrAlignment(
return error.BadType;
}
pub fn declFileScope(mod: *Zcu, decl_index: Decl.Index) *File {
return mod.declPtr(decl_index).getFileScope(mod);
}
/// Returns null in the following cases:
/// * `@TypeOf(.{})`
/// * A struct which has no fields (`struct {}`).
@ -3352,16 +2983,8 @@ pub fn typeToFunc(mod: *Zcu, ty: Type) ?InternPool.Key.FuncType {
return mod.intern_pool.indexToFuncType(ty.toIntern());
}
pub fn funcOwnerDeclPtr(mod: *Zcu, func_index: InternPool.Index) *Decl {
return mod.declPtr(mod.funcOwnerDeclIndex(func_index));
}
pub fn funcOwnerDeclIndex(mod: *Zcu, func_index: InternPool.Index) Decl.Index {
return mod.funcInfo(func_index).owner_decl;
}
pub fn iesFuncIndex(mod: *const Zcu, ies_index: InternPool.Index) InternPool.Index {
return mod.intern_pool.iesFuncIndex(ies_index);
pub fn iesFuncIndex(zcu: *const Zcu, ies_index: InternPool.Index) InternPool.Index {
return zcu.intern_pool.iesFuncIndex(ies_index);
}
pub fn funcInfo(mod: *Zcu, func_index: InternPool.Index) InternPool.Key.Func {
@ -3372,44 +2995,6 @@ pub fn toEnum(mod: *Zcu, comptime E: type, val: Value) E {
return mod.intern_pool.toEnum(E, val.toIntern());
}
pub fn isAnytypeParam(mod: *Zcu, func: InternPool.Index, index: u32) bool {
const file = mod.declPtr(func.owner_decl).getFileScope(mod);
const tags = file.zir.instructions.items(.tag);
const param_body = file.zir.getParamBody(func.zir_body_inst);
const param = param_body[index];
return switch (tags[param]) {
.param, .param_comptime => false,
.param_anytype, .param_anytype_comptime => true,
else => unreachable,
};
}
pub fn getParamName(mod: *Zcu, func_index: InternPool.Index, index: u32) [:0]const u8 {
const func = mod.funcInfo(func_index);
const file = mod.declPtr(func.owner_decl).getFileScope(mod);
const tags = file.zir.instructions.items(.tag);
const data = file.zir.instructions.items(.data);
const param_body = file.zir.getParamBody(func.zir_body_inst.resolve(&mod.intern_pool));
const param = param_body[index];
return switch (tags[@intFromEnum(param)]) {
.param, .param_comptime => blk: {
const extra = file.zir.extraData(Zir.Inst.Param, data[@intFromEnum(param)].pl_tok.payload_index);
break :blk file.zir.nullTerminatedString(extra.data.name);
},
.param_anytype, .param_anytype_comptime => blk: {
const param_data = data[@intFromEnum(param)].str_tok;
break :blk param_data.get(file.zir);
},
else => unreachable,
};
}
pub const UnionLayout = struct {
abi_size: u64,
abi_align: Alignment,
@ -3468,19 +3053,20 @@ pub fn fileByIndex(zcu: *Zcu, file_index: File.Index) *File {
return zcu.intern_pool.filePtr(file_index);
}
/// Returns the `Decl` of the struct that represents this `File`.
pub fn fileRootDecl(zcu: *const Zcu, file_index: File.Index) Decl.OptionalIndex {
/// Returns the struct that represents this `File`.
/// If the struct has not been created, returns `.none`.
pub fn fileRootType(zcu: *const Zcu, file_index: File.Index) InternPool.Index {
const ip = &zcu.intern_pool;
const file_index_unwrapped = file_index.unwrap(ip);
const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire();
return files.view().items(.root_decl)[file_index_unwrapped.index];
return files.view().items(.root_type)[file_index_unwrapped.index];
}
pub fn setFileRootDecl(zcu: *Zcu, file_index: File.Index, root_decl: Decl.OptionalIndex) void {
pub fn setFileRootType(zcu: *Zcu, file_index: File.Index, root_type: InternPool.Index) void {
const ip = &zcu.intern_pool;
const file_index_unwrapped = file_index.unwrap(ip);
const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire();
files.view().items(.root_decl)[file_index_unwrapped.index] = root_decl;
files.view().items(.root_type)[file_index_unwrapped.index] = root_type;
}
pub fn filePathDigest(zcu: *const Zcu, file_index: File.Index) Cache.BinDigest {
@ -3489,3 +3075,39 @@ pub fn filePathDigest(zcu: *const Zcu, file_index: File.Index) Cache.BinDigest {
const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire();
return files.view().items(.bin_digest)[file_index_unwrapped.index];
}
pub fn navSrcLoc(zcu: *const Zcu, nav_index: InternPool.Nav.Index) LazySrcLoc {
const ip = &zcu.intern_pool;
return .{
.base_node_inst = ip.getNav(nav_index).srcInst(ip),
.offset = LazySrcLoc.Offset.nodeOffset(0),
};
}
pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 {
const ip = &zcu.intern_pool;
const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip);
const zir = zcu.fileByIndex(inst_info.file).zir;
const inst = zir.instructions.get(@intFromEnum(inst_info.inst));
assert(inst.tag == .declaration);
return zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line;
}
pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value {
return Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.resolved.val);
}
pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index {
const ip = &zcu.intern_pool;
return ip.getNav(nav).srcInst(ip).resolveFull(ip).file;
}
pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
return zcu.fileByIndex(zcu.navFileScopeIndex(nav));
}
pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File {
const ip = &zcu.intern_pool;
const file_index = ip.getCau(cau).zir_index.resolveFull(ip).file;
return zcu.fileByIndex(file_index);
}

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,7 @@ bin_file: *link.File,
debug_output: DebugInfoOutput,
target: *const std.Target,
func_index: InternPool.Index,
owner_decl: InternPool.DeclIndex,
owner_nav: InternPool.Nav.Index,
err_msg: ?*ErrorMsg,
args: []MCValue,
ret_mcv: MCValue,
@ -184,7 +184,7 @@ const DbgInfoReloc = struct {
fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {
switch (function.debug_output) {
.dwarf => |dw| {
const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) {
const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {
.register => |reg| .{ .register = reg.dwarfLocOp() },
.stack_offset,
.stack_argument_offset,
@ -202,7 +202,7 @@ const DbgInfoReloc = struct {
else => unreachable, // not a possible argument
};
try dw.genArgDbgInfo(reloc.name, reloc.ty, function.owner_decl, loc);
try dw.genArgDbgInfo(reloc.name, reloc.ty, function.owner_nav, loc);
},
.plan9 => {},
.none => {},
@ -218,7 +218,7 @@ const DbgInfoReloc = struct {
switch (function.debug_output) {
.dwarf => |dw| {
const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) {
const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {
.register => |reg| .{ .register = reg.dwarfLocOp() },
.ptr_stack_offset,
.stack_offset,
@ -248,7 +248,7 @@ const DbgInfoReloc = struct {
break :blk .nop;
},
};
try dw.genVarDbgInfo(reloc.name, reloc.ty, function.owner_decl, is_ptr, loc);
try dw.genVarDbgInfo(reloc.name, reloc.ty, function.owner_nav, is_ptr, loc);
},
.plan9 => {},
.none => {},
@ -341,11 +341,9 @@ pub fn generate(
const zcu = pt.zcu;
const gpa = zcu.gpa;
const func = zcu.funcInfo(func_index);
const fn_owner_decl = zcu.declPtr(func.owner_decl);
assert(fn_owner_decl.has_tv);
const fn_type = fn_owner_decl.typeOf(zcu);
const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace);
const target = &namespace.fileScope(zcu).mod.resolved_target.result;
const fn_type = Type.fromInterned(func.ty);
const file_scope = zcu.navFileScope(func.owner_nav);
const target = &file_scope.mod.resolved_target.result;
var branch_stack = std.ArrayList(Branch).init(gpa);
defer {
@ -364,7 +362,7 @@ pub fn generate(
.target = target,
.bin_file = lf,
.func_index = func_index,
.owner_decl = func.owner_decl,
.owner_nav = func.owner_nav,
.err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues`
.ret_mcv = undefined, // populated after `resolveCallingConventionValues`
@ -4053,8 +4051,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
@panic("TODO store");
},
.coff => blk: {
const coff_file = self.bin_file.cast(link.File.Coff).?;
const atom = try coff_file.getOrCreateAtomForDecl(self.owner_decl);
const coff_file = self.bin_file.cast(.coff).?;
const atom = try coff_file.getOrCreateAtomForNav(self.owner_nav);
break :blk coff_file.getAtom(atom).getSymbolIndex().?;
},
else => unreachable, // unsupported target format
@ -4289,6 +4287,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
const ty = self.typeOf(callee);
const pt = self.pt;
const mod = pt.zcu;
const ip = &mod.intern_pool;
const fn_ty = switch (ty.zigTypeTag(mod)) {
.Fn => ty,
@ -4351,19 +4350,19 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
// Due to incremental compilation, how function calls are generated depends
// on linking.
if (try self.air.value(callee, pt)) |func_value| {
if (func_value.getFunction(mod)) |func| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
.func => |func| {
if (self.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
const sym = zo.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));
try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr });
} else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
} else if (self.bin_file.cast(.macho)) |macho_file| {
_ = macho_file;
@panic("TODO airCall");
// const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
// const atom = try macho_file.getOrCreateAtomForNav(func.owner_nav);
// const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
// try self.genSetReg(Type.u64, .x30, .{
// .linker_load = .{
@ -4371,8 +4370,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
// .sym_index = sym_index,
// },
// });
} else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
} else if (self.bin_file.cast(.coff)) |coff_file| {
const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);
const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
try self.genSetReg(Type.u64, .x30, .{
.linker_load = .{
@ -4380,8 +4379,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
.sym_index = sym_index,
},
});
} else if (self.bin_file.cast(link.File.Plan9)) |p9| {
const atom_index = try p9.seeDecl(func.owner_decl);
} else if (self.bin_file.cast(.plan9)) |p9| {
const atom_index = try p9.seeNav(pt, func.owner_nav);
const atom = p9.getAtom(atom_index);
try self.genSetReg(Type.usize, .x30, .{ .memory = atom.getOffsetTableAddress(p9) });
} else unreachable;
@ -4390,14 +4389,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
.tag = .blr,
.data = .{ .reg = .x30 },
});
} else if (func_value.getExternFunc(mod)) |extern_func| {
const decl_name = mod.declPtr(extern_func.decl).name.toSlice(&mod.intern_pool);
const lib_name = extern_func.lib_name.toSlice(&mod.intern_pool);
if (self.bin_file.cast(link.File.MachO)) |macho_file| {
},
.@"extern" => |@"extern"| {
const nav_name = ip.getNav(@"extern".owner_nav).name.toSlice(ip);
const lib_name = @"extern".lib_name.toSlice(ip);
if (self.bin_file.cast(.macho)) |macho_file| {
_ = macho_file;
@panic("TODO airCall");
// const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);
// const atom = try macho_file.getOrCreateAtomForDecl(self.owner_decl);
// const sym_index = try macho_file.getGlobalSymbol(nav_name, lib_name);
// const atom = try macho_file.getOrCreateAtomForNav(self.owner_nav);
// const atom_index = macho_file.getAtom(atom).getSymbolIndex().?;
// _ = try self.addInst(.{
// .tag = .call_extern,
@ -4408,8 +4408,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
// },
// },
// });
} else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);
} else if (self.bin_file.cast(.coff)) |coff_file| {
const sym_index = try coff_file.getGlobalSymbol(nav_name, lib_name);
try self.genSetReg(Type.u64, .x30, .{
.linker_load = .{
.type = .import,
@ -4423,9 +4423,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
} else {
return self.fail("TODO implement calling extern functions", .{});
}
} else {
return self.fail("TODO implement calling bitcasted functions", .{});
}
},
else => return self.fail("TODO implement calling bitcasted functions", .{}),
} else {
assert(ty.zigTypeTag(mod) == .Pointer);
const mcv = try self.resolveInst(callee);
@ -5594,8 +5593,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
@panic("TODO genSetStack");
},
.coff => blk: {
const coff_file = self.bin_file.cast(link.File.Coff).?;
const atom = try coff_file.getOrCreateAtomForDecl(self.owner_decl);
const coff_file = self.bin_file.cast(.coff).?;
const atom = try coff_file.getOrCreateAtomForNav(self.owner_nav);
break :blk coff_file.getAtom(atom).getSymbolIndex().?;
},
else => unreachable, // unsupported target format
@ -5717,8 +5716,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
// break :blk macho_file.getAtom(atom).getSymbolIndex().?;
},
.coff => blk: {
const coff_file = self.bin_file.cast(link.File.Coff).?;
const atom = try coff_file.getOrCreateAtomForDecl(self.owner_decl);
const coff_file = self.bin_file.cast(.coff).?;
const atom = try coff_file.getOrCreateAtomForNav(self.owner_nav);
break :blk coff_file.getAtom(atom).getSymbolIndex().?;
},
else => unreachable, // unsupported target format
@ -5915,8 +5914,8 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
// break :blk macho_file.getAtom(atom).getSymbolIndex().?;
},
.coff => blk: {
const coff_file = self.bin_file.cast(link.File.Coff).?;
const atom = try coff_file.getOrCreateAtomForDecl(self.owner_decl);
const coff_file = self.bin_file.cast(.coff).?;
const atom = try coff_file.getOrCreateAtomForNav(self.owner_nav);
break :blk coff_file.getAtom(atom).getSymbolIndex().?;
},
else => unreachable, // unsupported target format
@ -6226,7 +6225,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
self.pt,
self.src_loc,
val,
self.owner_decl,
self.target.*,
)) {
.mcv => |mcv| switch (mcv) {
.none => .none,

View File

@ -687,7 +687,7 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
};
_ = offset;
if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
if (emit.bin_file.cast(.macho)) |macho_file| {
_ = macho_file;
@panic("TODO mirCallExtern");
// // Add relocation to the decl.
@ -701,7 +701,7 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
// .pcrel = true,
// .length = 2,
// });
} else if (emit.bin_file.cast(link.File.Coff)) |_| {
} else if (emit.bin_file.cast(.coff)) |_| {
unreachable; // Calling imports is handled via `.load_memory_import`
} else {
return emit.fail("Implement call_extern for linking backends != {{ COFF, MachO }}", .{});
@ -903,7 +903,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
else => unreachable,
}
if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
if (emit.bin_file.cast(.macho)) |macho_file| {
_ = macho_file;
@panic("TODO mirLoadMemoryPie");
// const Atom = link.File.MachO.Atom;
@ -932,7 +932,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
// else => unreachable,
// },
// } });
} else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
} else if (emit.bin_file.cast(.coff)) |coff_file| {
const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;
const target = switch (tag) {
.load_memory_got,

View File

@ -262,7 +262,7 @@ const DbgInfoReloc = struct {
fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {
switch (function.debug_output) {
.dwarf => |dw| {
const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) {
const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {
.register => |reg| .{ .register = reg.dwarfLocOp() },
.stack_offset,
.stack_argument_offset,
@ -280,7 +280,7 @@ const DbgInfoReloc = struct {
else => unreachable, // not a possible argument
};
try dw.genArgDbgInfo(reloc.name, reloc.ty, function.pt.zcu.funcOwnerDeclIndex(function.func_index), loc);
try dw.genArgDbgInfo(reloc.name, reloc.ty, function.pt.zcu.funcInfo(function.func_index).owner_nav, loc);
},
.plan9 => {},
.none => {},
@ -296,7 +296,7 @@ const DbgInfoReloc = struct {
switch (function.debug_output) {
.dwarf => |dw| {
const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) {
const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (reloc.mcv) {
.register => |reg| .{ .register = reg.dwarfLocOp() },
.ptr_stack_offset,
.stack_offset,
@ -323,7 +323,7 @@ const DbgInfoReloc = struct {
break :blk .nop;
},
};
try dw.genVarDbgInfo(reloc.name, reloc.ty, function.pt.zcu.funcOwnerDeclIndex(function.func_index), is_ptr, loc);
try dw.genVarDbgInfo(reloc.name, reloc.ty, function.pt.zcu.funcInfo(function.func_index).owner_nav, is_ptr, loc);
},
.plan9 => {},
.none => {},
@ -346,11 +346,9 @@ pub fn generate(
const zcu = pt.zcu;
const gpa = zcu.gpa;
const func = zcu.funcInfo(func_index);
const fn_owner_decl = zcu.declPtr(func.owner_decl);
assert(fn_owner_decl.has_tv);
const fn_type = fn_owner_decl.typeOf(zcu);
const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace);
const target = &namespace.fileScope(zcu).mod.resolved_target.result;
const func_ty = Type.fromInterned(func.ty);
const file_scope = zcu.navFileScope(func.owner_nav);
const target = &file_scope.mod.resolved_target.result;
var branch_stack = std.ArrayList(Branch).init(gpa);
defer {
@ -372,7 +370,7 @@ pub fn generate(
.err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues`
.ret_mcv = undefined, // populated after `resolveCallingConventionValues`
.fn_type = fn_type,
.fn_type = func_ty,
.arg_index = 0,
.branch_stack = &branch_stack,
.src_loc = src_loc,
@ -385,7 +383,7 @@ pub fn generate(
defer function.exitlude_jump_relocs.deinit(gpa);
defer function.dbg_info_relocs.deinit(gpa);
var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) {
var call_info = function.resolveCallingConventionValues(func_ty) catch |err| switch (err) {
error.CodegenFail => return Result{ .fail = function.err_msg.? },
error.OutOfRegisters => return Result{
.fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}),
@ -4264,6 +4262,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
const ty = self.typeOf(callee);
const pt = self.pt;
const mod = pt.zcu;
const ip = &mod.intern_pool;
const fn_ty = switch (ty.zigTypeTag(mod)) {
.Fn => ty,
@ -4333,16 +4332,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
// Due to incremental compilation, how function calls are generated depends
// on linking.
if (try self.air.value(callee, pt)) |func_value| {
if (func_value.getFunction(mod)) |func| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
.func => |func| {
if (self.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
const sym = zo.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
const got_addr: u32 = @intCast(sym.zigGotAddress(elf_file));
try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr });
} else if (self.bin_file.cast(link.File.MachO)) |_| {
} else if (self.bin_file.cast(.macho)) |_| {
unreachable; // unsupported architecture for MachO
} else {
return self.fail("TODO implement call on {s} for {s}", .{
@ -4350,11 +4349,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
@tagName(self.target.cpu.arch),
});
}
} else if (func_value.getExternFunc(mod)) |_| {
},
.@"extern" => {
return self.fail("TODO implement calling extern functions", .{});
} else {
},
else => {
return self.fail("TODO implement calling bitcasted functions", .{});
}
},
} else {
assert(ty.zigTypeTag(mod) == .Pointer);
const mcv = try self.resolveInst(callee);
@ -6178,7 +6179,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
pt,
self.src_loc,
val,
pt.zcu.funcOwnerDeclIndex(self.func_index),
self.target.*,
)) {
.mcv => |mcv| switch (mcv) {
.none => .none,

View File

@ -118,26 +118,18 @@ const RegisterOffset = struct { reg: Register, off: i32 = 0 };
pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };
const Owner = union(enum) {
func_index: InternPool.Index,
nav_index: InternPool.Nav.Index,
lazy_sym: link.File.LazySymbol,
fn getDecl(owner: Owner, zcu: *Zcu) InternPool.DeclIndex {
return switch (owner) {
.func_index => |func_index| zcu.funcOwnerDeclIndex(func_index),
.lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(zcu),
};
}
fn getSymbolIndex(owner: Owner, func: *Func) !u32 {
const pt = func.pt;
switch (owner) {
.func_index => |func_index| {
const decl_index = func.pt.zcu.funcOwnerDeclIndex(func_index);
const elf_file = func.bin_file.cast(link.File.Elf).?;
return elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
.nav_index => |nav_index| {
const elf_file = func.bin_file.cast(.elf).?;
return elf_file.zigObjectPtr().?.getOrCreateMetadataForNav(elf_file, nav_index);
},
.lazy_sym => |lazy_sym| {
const elf_file = func.bin_file.cast(link.File.Elf).?;
const elf_file = func.bin_file.cast(.elf).?;
return elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
func.fail("{s} creating lazy symbol", .{@errorName(err)});
},
@ -767,12 +759,8 @@ pub fn generate(
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
const func = zcu.funcInfo(func_index);
const fn_owner_decl = zcu.declPtr(func.owner_decl);
assert(fn_owner_decl.has_tv);
const fn_type = fn_owner_decl.typeOf(zcu);
const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace);
const target = &namespace.fileScope(zcu).mod.resolved_target.result;
const mod = namespace.fileScope(zcu).mod;
const fn_type = Type.fromInterned(func.ty);
const mod = zcu.navFileScope(func.owner_nav).mod;
var branch_stack = std.ArrayList(Branch).init(gpa);
defer {
@ -789,9 +777,9 @@ pub fn generate(
.mod = mod,
.bin_file = bin_file,
.liveness = liveness,
.target = target,
.target = &mod.resolved_target.result,
.debug_output = debug_output,
.owner = .{ .func_index = func_index },
.owner = .{ .nav_index = func.owner_nav },
.err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues`
.ret_mcv = undefined, // populated after `resolveCallingConventionValues`
@ -818,7 +806,7 @@ pub fn generate(
function.mir_instructions.deinit(gpa);
}
wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)});
wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)});
try function.frame_allocs.resize(gpa, FrameIndex.named_count);
function.frame_allocs.set(
@ -1074,22 +1062,22 @@ fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir)
return .{ .data = .{ .func = func, .inst = inst } };
}
const FormatDeclData = struct {
zcu: *Zcu,
decl_index: InternPool.DeclIndex,
const FormatNavData = struct {
ip: *const InternPool,
nav_index: InternPool.Nav.Index,
};
fn formatDecl(
data: FormatDeclData,
fn formatNav(
data: FormatNavData,
comptime _: []const u8,
_: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
try writer.print("{}", .{data.zcu.declPtr(data.decl_index).fqn.fmt(&data.zcu.intern_pool)});
try writer.print("{}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)});
}
fn fmtDecl(func: *Func, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) {
fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(formatNav) {
return .{ .data = .{
.zcu = func.pt.zcu,
.decl_index = decl_index,
.ip = ip,
.nav_index = nav_index,
} };
}
@ -1393,9 +1381,9 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
const pt = func.pt;
const mod = pt.zcu;
const ip = &mod.intern_pool;
switch (lazy_sym.ty.zigTypeTag(mod)) {
switch (Type.fromInterned(lazy_sym.ty).zigTypeTag(mod)) {
.Enum => {
const enum_ty = lazy_sym.ty;
const enum_ty = Type.fromInterned(lazy_sym.ty);
wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)});
const param_regs = abi.Registers.Integer.function_arg_regs;
@ -1408,11 +1396,11 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
const data_reg, const data_lock = try func.allocReg(.int);
defer func.register_manager.unlockReg(data_lock);
const elf_file = func.bin_file.cast(link.File.Elf).?;
const elf_file = func.bin_file.cast(.elf).?;
const zo = elf_file.zigObjectPtr().?;
const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, .{
.kind = .const_data,
.ty = enum_ty,
.ty = enum_ty.toIntern(),
}) catch |err|
return func.fail("{s} creating lazy symbol", .{@errorName(err)});
@ -1479,7 +1467,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
},
else => return func.fail(
"TODO implement {s} for {}",
.{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(pt) },
.{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt) },
),
}
}
@ -4682,17 +4670,14 @@ fn airFieldParentPtr(func: *Func, inst: Air.Inst.Index) !void {
}
fn genArgDbgInfo(func: Func, inst: Air.Inst.Index, mcv: MCValue) !void {
const pt = func.pt;
const zcu = pt.zcu;
const arg = func.air.instructions.items(.data)[@intFromEnum(inst)].arg;
const ty = arg.ty.toType();
const owner_decl = func.owner.getDecl(zcu);
if (arg.name == .none) return;
const name = func.air.nullTerminatedString(@intFromEnum(arg.name));
switch (func.debug_output) {
.dwarf => |dw| switch (mcv) {
.register => |reg| try dw.genArgDbgInfo(name, ty, owner_decl, .{
.register => |reg| try dw.genArgDbgInfo(name, ty, func.owner.nav_index, .{
.register = reg.dwarfLocOp(),
}),
.load_frame => {},
@ -4940,14 +4925,14 @@ fn genCall(
switch (switch (func_key) {
else => func_key,
.ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
.decl => |decl| zcu.intern_pool.indexToKey(zcu.declPtr(decl).val.toIntern()),
.nav => |nav| zcu.intern_pool.indexToKey(zcu.navValue(nav).toIntern()),
else => func_key,
} else func_key,
}) {
.func => |func_val| {
if (func.bin_file.cast(link.File.Elf)) |elf_file| {
if (func.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func_val.owner_decl);
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func_val.owner_nav);
if (func.mod.pic) {
return func.fail("TODO: genCall pic", .{});
@ -4964,19 +4949,18 @@ fn genCall(
}
} else unreachable; // not a valid riscv64 format
},
.extern_func => |extern_func| {
const owner_decl = zcu.declPtr(extern_func.decl);
const lib_name = extern_func.lib_name.toSlice(&zcu.intern_pool);
const decl_name = owner_decl.name.toSlice(&zcu.intern_pool);
.@"extern" => |@"extern"| {
const lib_name = @"extern".lib_name.toSlice(&zcu.intern_pool);
const name = @"extern".name.toSlice(&zcu.intern_pool);
const atom_index = try func.owner.getSymbolIndex(func);
const elf_file = func.bin_file.cast(link.File.Elf).?;
const elf_file = func.bin_file.cast(.elf).?;
_ = try func.addInst(.{
.tag = .pseudo_extern_fn_reloc,
.data = .{ .reloc = .{
.register = .ra,
.atom_index = atom_index,
.sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name),
.sym_index = try elf_file.getGlobalSymbol(name, lib_name),
} },
});
},
@ -5213,8 +5197,6 @@ fn genVarDbgInfo(
mcv: MCValue,
name: [:0]const u8,
) !void {
const pt = func.pt;
const zcu = pt.zcu;
const is_ptr = switch (tag) {
.dbg_var_ptr => true,
.dbg_var_val => false,
@ -5223,7 +5205,7 @@ fn genVarDbgInfo(
switch (func.debug_output) {
.dwarf => |dw| {
const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (mcv) {
.register => |reg| .{ .register = reg.dwarfLocOp() },
.memory => |address| .{ .memory = address },
.load_symbol => |sym_off| loc: {
@ -5238,7 +5220,7 @@ fn genVarDbgInfo(
break :blk .nop;
},
};
try dw.genVarDbgInfo(name, ty, func.owner.getDecl(zcu), is_ptr, loc);
try dw.genVarDbgInfo(name, ty, func.owner.nav_index, is_ptr, loc);
},
.plan9 => {},
.none => {},
@ -7804,7 +7786,6 @@ fn airMemcpy(func: *Func, inst: Air.Inst.Index) !void {
fn airTagName(func: *Func, inst: Air.Inst.Index) !void {
const pt = func.pt;
const zcu = pt.zcu;
const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
@ -7820,7 +7801,7 @@ fn airTagName(func: *Func, inst: Air.Inst.Index) !void {
const operand = try func.resolveInst(un_op);
try func.genSetReg(enum_ty, param_regs[1], operand);
const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(zcu), zcu);
const lazy_sym: link.File.LazySymbol = .{ .kind = .code, .ty = enum_ty.toIntern() };
const elf_file = func.bin_file.cast(link.File.Elf).?;
const zo = elf_file.zigObjectPtr().?;
const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
@ -8033,32 +8014,14 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking {
fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
const pt = func.pt;
const zcu = pt.zcu;
const gpa = func.gpa;
const owner_decl_index = func.owner.getDecl(zcu);
const lf = func.bin_file;
const src_loc = func.src_loc;
if (val.isUndef(pt.zcu)) {
const local_sym_index = lf.lowerUnnamedConst(pt, val, owner_decl_index) catch |err| {
const msg = try ErrorMsg.create(gpa, src_loc, "lowering unnamed undefined constant failed: {s}", .{@errorName(err)});
func.err_msg = msg;
return error.CodegenFail;
};
switch (lf.tag) {
.elf => return MCValue{ .undef = local_sym_index },
else => unreachable,
}
}
const result = try codegen.genTypedValue(
lf,
pt,
src_loc,
val,
owner_decl_index,
);
const result = if (val.isUndef(pt.zcu))
try lf.lowerUav(pt, val.toIntern(), .none, src_loc)
else
try codegen.genTypedValue(lf, pt, src_loc, val, func.target.*);
const mcv: MCValue = switch (result) {
.mcv => |mcv| switch (mcv) {
.none => .none,

View File

@ -49,7 +49,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.Lib => emit.lower.link_mode == .static,
};
const elf_file = emit.bin_file.cast(link.File.Elf).?;
const elf_file = emit.bin_file.cast(.elf).?;
const zo = elf_file.zigObjectPtr().?;
const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
@ -81,7 +81,7 @@ pub fn emitMir(emit: *Emit) Error!void {
});
},
.load_tlv_reloc => |symbol| {
const elf_file = emit.bin_file.cast(link.File.Elf).?;
const elf_file = emit.bin_file.cast(.elf).?;
const zo = elf_file.zigObjectPtr().?;
const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
@ -107,7 +107,7 @@ pub fn emitMir(emit: *Emit) Error!void {
});
},
.call_extern_fn_reloc => |symbol| {
const elf_file = emit.bin_file.cast(link.File.Elf).?;
const elf_file = emit.bin_file.cast(.elf).?;
const zo = elf_file.zigObjectPtr().?;
const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;

View File

@ -273,11 +273,9 @@ pub fn generate(
const zcu = pt.zcu;
const gpa = zcu.gpa;
const func = zcu.funcInfo(func_index);
const fn_owner_decl = zcu.declPtr(func.owner_decl);
assert(fn_owner_decl.has_tv);
const fn_type = fn_owner_decl.typeOf(zcu);
const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace);
const target = &namespace.fileScope(zcu).mod.resolved_target.result;
const func_ty = Type.fromInterned(func.ty);
const file_scope = zcu.navFileScope(func.owner_nav);
const target = &file_scope.mod.resolved_target.result;
var branch_stack = std.ArrayList(Branch).init(gpa);
defer {
@ -300,7 +298,7 @@ pub fn generate(
.err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues`
.ret_mcv = undefined, // populated after `resolveCallingConventionValues`
.fn_type = fn_type,
.fn_type = func_ty,
.arg_index = 0,
.branch_stack = &branch_stack,
.src_loc = src_loc,
@ -312,7 +310,7 @@ pub fn generate(
defer function.blocks.deinit(gpa);
defer function.exitlude_jump_relocs.deinit(gpa);
var call_info = function.resolveCallingConventionValues(fn_type, .callee) catch |err| switch (err) {
var call_info = function.resolveCallingConventionValues(func_ty, .callee) catch |err| switch (err) {
error.CodegenFail => return Result{ .fail = function.err_msg.? },
error.OutOfRegisters => return Result{
.fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}),
@ -1306,6 +1304,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
const ty = self.typeOf(callee);
const pt = self.pt;
const mod = pt.zcu;
const ip = &mod.intern_pool;
const fn_ty = switch (ty.zigTypeTag(mod)) {
.Fn => ty,
.Pointer => ty.childType(mod),
@ -1349,46 +1348,42 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
// Due to incremental compilation, how function calls are generated depends
// on linking.
if (try self.air.value(callee, pt)) |func_value| {
if (self.bin_file.tag == link.File.Elf.base_tag) {
switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
.func => |func| {
const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = zo.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));
} else unreachable;
if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
.func => |func| {
const got_addr = if (self.bin_file.cast(.elf)) |elf_file| blk: {
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
const sym = zo.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));
} else @panic("TODO SPARCv9 currently does not support non-ELF binaries");
try self.genSetReg(Type.usize, .o7, .{ .memory = got_addr });
try self.genSetReg(Type.usize, .o7, .{ .memory = got_addr });
_ = try self.addInst(.{
.tag = .jmpl,
.data = .{
.arithmetic_3op = .{
.is_imm = false,
.rd = .o7,
.rs1 = .o7,
.rs2_or_imm = .{ .rs2 = .g0 },
},
},
});
_ = try self.addInst(.{
.tag = .jmpl,
.data = .{
.arithmetic_3op = .{
.is_imm = false,
.rd = .o7,
.rs1 = .o7,
.rs2_or_imm = .{ .rs2 = .g0 },
},
},
});
// TODO Find a way to fill this delay slot
_ = try self.addInst(.{
.tag = .nop,
.data = .{ .nop = {} },
});
},
.extern_func => {
return self.fail("TODO implement calling extern functions", .{});
},
else => {
return self.fail("TODO implement calling bitcasted functions", .{});
},
}
} else @panic("TODO SPARCv9 currently does not support non-ELF binaries");
// TODO Find a way to fill this delay slot
_ = try self.addInst(.{
.tag = .nop,
.data = .{ .nop = {} },
});
},
.@"extern" => {
return self.fail("TODO implement calling extern functions", .{});
},
else => {
return self.fail("TODO implement calling bitcasted functions", .{});
},
} else {
assert(ty.zigTypeTag(mod) == .Pointer);
const mcv = try self.resolveInst(callee);
@ -3614,13 +3609,13 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
const mod = pt.zcu;
const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg;
const ty = arg.ty.toType();
const owner_decl = mod.funcOwnerDeclIndex(self.func_index);
const owner_nav = mod.funcInfo(self.func_index).owner_nav;
if (arg.name == .none) return;
const name = self.air.nullTerminatedString(@intFromEnum(arg.name));
switch (self.debug_output) {
.dwarf => |dw| switch (mcv) {
.register => |reg| try dw.genArgDbgInfo(name, ty, owner_decl, .{
.register => |reg| try dw.genArgDbgInfo(name, ty, owner_nav, .{
.register = reg.dwarfLocOp(),
}),
else => {},
@ -4153,7 +4148,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
pt,
self.src_loc,
val,
pt.zcu.funcOwnerDeclIndex(self.func_index),
self.target.*,
)) {
.mcv => |mcv| switch (mcv) {
.none => .none,

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ code: *std.ArrayList(u8),
/// List of allocated locals.
locals: []const u8,
/// The declaration that code is being generated for.
decl_index: InternPool.DeclIndex,
owner_nav: InternPool.Nav.Index,
// Debug information
/// Holds the debug information for this emission
@ -257,7 +257,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
const comp = emit.bin_file.base.comp;
const zcu = comp.module.?;
const gpa = comp.gpa;
emit.error_msg = try Zcu.ErrorMsg.create(gpa, zcu.declPtr(emit.decl_index).navSrcLoc(zcu), format, args);
emit.error_msg = try Zcu.ErrorMsg.create(gpa, zcu.navSrcLoc(emit.owner_nav), format, args);
return error.EmitFail;
}
@ -310,7 +310,7 @@ fn emitGlobal(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void {
const global_offset = emit.offset();
try emit.code.appendSlice(&buf);
const atom_index = emit.bin_file.zigObjectPtr().?.decls_map.get(emit.decl_index).?.atom;
const atom_index = emit.bin_file.zigObjectPtr().?.navs.get(emit.owner_nav).?.atom;
const atom = emit.bin_file.getAtomPtr(atom_index);
try atom.relocs.append(gpa, .{
.index = label,
@ -370,7 +370,7 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void {
try emit.code.appendSlice(&buf);
if (label != 0) {
const atom_index = emit.bin_file.zigObjectPtr().?.decls_map.get(emit.decl_index).?.atom;
const atom_index = emit.bin_file.zigObjectPtr().?.navs.get(emit.owner_nav).?.atom;
const atom = emit.bin_file.getAtomPtr(atom_index);
try atom.relocs.append(gpa, .{
.offset = call_offset,
@ -390,7 +390,7 @@ fn emitCallIndirect(emit: *Emit, inst: Mir.Inst.Index) !void {
leb128.writeUnsignedFixed(5, &buf, type_index);
try emit.code.appendSlice(&buf);
if (type_index != 0) {
const atom_index = emit.bin_file.zigObjectPtr().?.decls_map.get(emit.decl_index).?.atom;
const atom_index = emit.bin_file.zigObjectPtr().?.navs.get(emit.owner_nav).?.atom;
const atom = emit.bin_file.getAtomPtr(atom_index);
try atom.relocs.append(emit.bin_file.base.comp.gpa, .{
.offset = call_offset,
@ -412,7 +412,7 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
try emit.code.appendSlice(&buf);
if (symbol_index != 0) {
const atom_index = emit.bin_file.zigObjectPtr().?.decls_map.get(emit.decl_index).?.atom;
const atom_index = emit.bin_file.zigObjectPtr().?.navs.get(emit.owner_nav).?.atom;
const atom = emit.bin_file.getAtomPtr(atom_index);
try atom.relocs.append(gpa, .{
.offset = index_offset,
@ -443,7 +443,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
}
if (mem.pointer != 0) {
const atom_index = emit.bin_file.zigObjectPtr().?.decls_map.get(emit.decl_index).?.atom;
const atom_index = emit.bin_file.zigObjectPtr().?.navs.get(emit.owner_nav).?.atom;
const atom = emit.bin_file.getAtomPtr(atom_index);
try atom.relocs.append(gpa, .{
.offset = mem_offset,

View File

@ -116,48 +116,36 @@ const RegisterOffset = struct { reg: Register, off: i32 = 0 };
const SymbolOffset = struct { sym: u32, off: i32 = 0 };
const Owner = union(enum) {
func_index: InternPool.Index,
nav_index: InternPool.Nav.Index,
lazy_sym: link.File.LazySymbol,
fn getDecl(owner: Owner, zcu: *Zcu) InternPool.DeclIndex {
return switch (owner) {
.func_index => |func_index| zcu.funcOwnerDeclIndex(func_index),
.lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(zcu),
};
}
fn getSymbolIndex(owner: Owner, ctx: *Self) !u32 {
const pt = ctx.pt;
switch (owner) {
.func_index => |func_index| {
const decl_index = ctx.pt.zcu.funcOwnerDeclIndex(func_index);
if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {
return elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
} else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
return macho_file.getZigObject().?.getOrCreateMetadataForDecl(macho_file, decl_index);
} else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| {
const atom = try coff_file.getOrCreateAtomForDecl(decl_index);
return coff_file.getAtom(atom).getSymbolIndex().?;
} else if (ctx.bin_file.cast(link.File.Plan9)) |p9_file| {
return p9_file.seeDecl(decl_index);
} else unreachable;
},
.lazy_sym => |lazy_sym| {
if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {
return elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
} else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
return macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err|
ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
} else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| {
const atom = coff_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
return coff_file.getAtom(atom).getSymbolIndex().?;
} else if (ctx.bin_file.cast(link.File.Plan9)) |p9_file| {
return p9_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
} else unreachable;
},
.nav_index => |nav_index| if (ctx.bin_file.cast(.elf)) |elf_file| {
return elf_file.zigObjectPtr().?.getOrCreateMetadataForNav(elf_file, nav_index);
} else if (ctx.bin_file.cast(.macho)) |macho_file| {
return macho_file.getZigObject().?.getOrCreateMetadataForNav(macho_file, nav_index);
} else if (ctx.bin_file.cast(.coff)) |coff_file| {
const atom = try coff_file.getOrCreateAtomForNav(nav_index);
return coff_file.getAtom(atom).getSymbolIndex().?;
} else if (ctx.bin_file.cast(.plan9)) |p9_file| {
return p9_file.seeNav(pt, nav_index);
} else unreachable,
.lazy_sym => |lazy_sym| if (ctx.bin_file.cast(.elf)) |elf_file| {
return elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
} else if (ctx.bin_file.cast(.macho)) |macho_file| {
return macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err|
ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
} else if (ctx.bin_file.cast(.coff)) |coff_file| {
const atom = coff_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
return coff_file.getAtom(atom).getSymbolIndex().?;
} else if (ctx.bin_file.cast(.plan9)) |p9_file| {
return p9_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
} else unreachable,
}
}
};
@ -803,14 +791,12 @@ pub fn generate(
debug_output: DebugInfoOutput,
) CodeGenError!Result {
const zcu = pt.zcu;
const gpa = zcu.gpa;
const comp = zcu.comp;
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
const func = zcu.funcInfo(func_index);
const fn_owner_decl = zcu.declPtr(func.owner_decl);
assert(fn_owner_decl.has_tv);
const fn_type = fn_owner_decl.typeOf(zcu);
const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace);
const mod = namespace.fileScope(zcu).mod;
const fn_type = Type.fromInterned(func.ty);
const mod = zcu.navFileScope(func.owner_nav).mod;
var function: Self = .{
.gpa = gpa,
@ -821,7 +807,7 @@ pub fn generate(
.mod = mod,
.bin_file = bin_file,
.debug_output = debug_output,
.owner = .{ .func_index = func_index },
.owner = .{ .nav_index = func.owner_nav },
.inline_func = func_index,
.err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues`
@ -847,9 +833,7 @@ pub fn generate(
function.mir_extra.deinit(gpa);
}
wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)});
const ip = &zcu.intern_pool;
wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)});
try function.frame_allocs.resize(gpa, FrameIndex.named_count);
function.frame_allocs.set(
@ -1067,22 +1051,22 @@ pub fn generateLazy(
}
}
const FormatDeclData = struct {
zcu: *Zcu,
decl_index: InternPool.DeclIndex,
const FormatNavData = struct {
ip: *const InternPool,
nav_index: InternPool.Nav.Index,
};
fn formatDecl(
data: FormatDeclData,
fn formatNav(
data: FormatNavData,
comptime _: []const u8,
_: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
try writer.print("{}", .{data.zcu.declPtr(data.decl_index).fqn.fmt(&data.zcu.intern_pool)});
try writer.print("{}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)});
}
fn fmtDecl(self: *Self, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) {
fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(formatNav) {
return .{ .data = .{
.zcu = self.pt.zcu,
.decl_index = decl_index,
.ip = ip,
.nav_index = nav_index,
} };
}
@ -2230,9 +2214,9 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
const pt = self.pt;
const mod = pt.zcu;
const ip = &mod.intern_pool;
switch (lazy_sym.ty.zigTypeTag(mod)) {
switch (Type.fromInterned(lazy_sym.ty).zigTypeTag(mod)) {
.Enum => {
const enum_ty = lazy_sym.ty;
const enum_ty = Type.fromInterned(lazy_sym.ty);
wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)});
const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*);
@ -2249,7 +2233,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
const data_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
const data_lock = self.register_manager.lockRegAssumeUnused(data_reg);
defer self.register_manager.unlockReg(data_lock);
try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty });
try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty.toIntern() });
var data_off: i32 = 0;
const tag_names = enum_ty.enumFields(mod);
@ -2288,7 +2272,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
},
else => return self.fail(
"TODO implement {s} for {}",
.{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(pt) },
.{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt) },
),
}
}
@ -11932,11 +11916,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
}
fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
const pt = self.pt;
const mod = pt.zcu;
switch (self.debug_output) {
.dwarf => |dw| {
const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (mcv) {
.register => |reg| .{ .register = reg.dwarfNum() },
.register_pair => |regs| .{ .register_pair = .{
regs[0].dwarfNum(), regs[1].dwarfNum(),
@ -11955,7 +11937,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
// TODO: this might need adjusting like the linkers do.
// Instead of flattening the owner and passing Decl.Index here we may
// want to special case LazySymbol in DWARF linker too.
try dw.genArgDbgInfo(name, ty, self.owner.getDecl(mod), loc);
try dw.genArgDbgInfo(name, ty, self.owner.nav_index, loc);
},
.plan9 => {},
.none => {},
@ -11969,8 +11951,6 @@ fn genVarDbgInfo(
mcv: MCValue,
name: [:0]const u8,
) !void {
const pt = self.pt;
const mod = pt.zcu;
const is_ptr = switch (tag) {
.dbg_var_ptr => true,
.dbg_var_val => false,
@ -11979,7 +11959,7 @@ fn genVarDbgInfo(
switch (self.debug_output) {
.dwarf => |dw| {
const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
const loc: link.File.Dwarf.NavState.DbgInfoLoc = switch (mcv) {
.register => |reg| .{ .register = reg.dwarfNum() },
// TODO use a frame index
.load_frame, .lea_frame => return,
@ -12007,7 +11987,7 @@ fn genVarDbgInfo(
// TODO: this might need adjusting like the linkers do.
// Instead of flattening the owner and passing Decl.Index here we may
// want to special case LazySymbol in DWARF linker too.
try dw.genVarDbgInfo(name, ty, self.owner.getDecl(mod), is_ptr, loc);
try dw.genVarDbgInfo(name, ty, self.owner.nav_index, is_ptr, loc);
},
.plan9 => {},
.none => {},
@ -12090,14 +12070,15 @@ fn genCall(self: *Self, info: union(enum) {
},
}, arg_types: []const Type, args: []const MCValue) !MCValue {
const pt = self.pt;
const mod = pt.zcu;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const fn_ty = switch (info) {
.air => |callee| fn_info: {
const callee_ty = self.typeOf(callee);
break :fn_info switch (callee_ty.zigTypeTag(mod)) {
break :fn_info switch (callee_ty.zigTypeTag(zcu)) {
.Fn => callee_ty,
.Pointer => callee_ty.childType(mod),
.Pointer => callee_ty.childType(zcu),
else => unreachable,
};
},
@ -12107,7 +12088,7 @@ fn genCall(self: *Self, info: union(enum) {
.cc = .C,
}),
};
const fn_info = mod.typeToFunc(fn_ty).?;
const fn_info = zcu.typeToFunc(fn_ty).?;
const resolved_cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);
const ExpectedContents = extern struct {
@ -12225,7 +12206,7 @@ fn genCall(self: *Self, info: union(enum) {
try self.asmRegisterImmediate(
.{ ._, .cmp },
index_reg.to32(),
Immediate.u(arg_ty.vectorLen(mod)),
Immediate.u(arg_ty.vectorLen(zcu)),
);
_ = try self.asmJccReloc(.b, loop);
@ -12317,18 +12298,18 @@ fn genCall(self: *Self, info: union(enum) {
// on linking.
switch (info) {
.air => |callee| if (try self.air.value(callee, pt)) |func_value| {
const func_key = mod.intern_pool.indexToKey(func_value.ip_index);
const func_key = ip.indexToKey(func_value.ip_index);
switch (switch (func_key) {
else => func_key,
.ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
.decl => |decl| mod.intern_pool.indexToKey(mod.declPtr(decl).val.toIntern()),
.nav => |nav| ip.indexToKey(zcu.navValue(nav).toIntern()),
else => func_key,
} else func_key,
}) {
.func => |func| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
if (self.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
if (self.mod.pic) {
const callee_reg: Register = switch (resolved_cc) {
.SysV => callee: {
@ -12356,14 +12337,14 @@ fn genCall(self: *Self, info: union(enum) {
} },
.mod = .{ .rm = .{ .size = .qword } },
});
} else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
} else if (self.bin_file.cast(.coff)) |coff_file| {
const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);
const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }, .{});
try self.asmRegister(.{ ._, .call }, .rax);
} else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
} else if (self.bin_file.cast(.macho)) |macho_file| {
const zo = macho_file.getZigObject().?;
const sym_index = try zo.getOrCreateMetadataForDecl(macho_file, func.owner_decl);
const sym_index = try zo.getOrCreateMetadataForNav(macho_file, func.owner_nav);
const sym = zo.symbols.items[sym_index];
try self.genSetReg(
.rax,
@ -12372,8 +12353,8 @@ fn genCall(self: *Self, info: union(enum) {
.{},
);
try self.asmRegister(.{ ._, .call }, .rax);
} else if (self.bin_file.cast(link.File.Plan9)) |p9| {
const atom_index = try p9.seeDecl(func.owner_decl);
} else if (self.bin_file.cast(.plan9)) |p9| {
const atom_index = try p9.seeNav(pt, func.owner_nav);
const atom = p9.getAtom(atom_index);
try self.asmMemory(.{ ._, .call }, .{
.base = .{ .reg = .ds },
@ -12384,16 +12365,15 @@ fn genCall(self: *Self, info: union(enum) {
});
} else unreachable;
},
.extern_func => |extern_func| {
const owner_decl = mod.declPtr(extern_func.decl);
const lib_name = extern_func.lib_name.toSlice(&mod.intern_pool);
const decl_name = owner_decl.name.toSlice(&mod.intern_pool);
try self.genExternSymbolRef(.call, lib_name, decl_name);
},
.@"extern" => |@"extern"| try self.genExternSymbolRef(
.call,
@"extern".lib_name.toSlice(ip),
@"extern".name.toSlice(ip),
),
else => return self.fail("TODO implement calling bitcasted functions", .{}),
}
} else {
assert(self.typeOf(callee).zigTypeTag(mod) == .Pointer);
assert(self.typeOf(callee).zigTypeTag(zcu) == .Pointer);
try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee }, .{});
try self.asmRegister(.{ ._, .call }, .rax);
},
@ -12919,13 +12899,13 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
const pt = self.pt;
const mod = pt.zcu;
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
defer self.register_manager.unlockReg(addr_lock);
try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
const anyerror_lazy_sym: link.File.LazySymbol = .{ .kind = .const_data, .ty = .anyerror_type };
try self.genLazySymbolRef(.lea, addr_reg, anyerror_lazy_sym);
try self.spillEflagsIfOccupied();
@ -15273,7 +15253,7 @@ fn genExternSymbolRef(
callee: []const u8,
) InnerError!void {
const atom_index = try self.owner.getSymbolIndex(self);
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
if (self.bin_file.cast(.elf)) |elf_file| {
_ = try self.addInst(.{
.tag = tag,
.ops = .extern_fn_reloc,
@ -15282,7 +15262,7 @@ fn genExternSymbolRef(
.sym_index = try elf_file.getGlobalSymbol(callee, lib),
} },
});
} else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
} else if (self.bin_file.cast(.coff)) |coff_file| {
const global_index = try coff_file.getGlobalSymbol(callee, lib);
_ = try self.addInst(.{
.tag = .mov,
@ -15300,7 +15280,7 @@ fn genExternSymbolRef(
.call => try self.asmRegister(.{ ._, .call }, .rax),
else => unreachable,
}
} else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
} else if (self.bin_file.cast(.macho)) |macho_file| {
_ = try self.addInst(.{
.tag = .call,
.ops = .extern_fn_reloc,
@ -15319,7 +15299,7 @@ fn genLazySymbolRef(
lazy_sym: link.File.LazySymbol,
) InnerError!void {
const pt = self.pt;
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
if (self.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
return self.fail("{s} creating lazy symbol", .{@errorName(err)});
@ -15355,7 +15335,7 @@ fn genLazySymbolRef(
else => unreachable,
}
}
} else if (self.bin_file.cast(link.File.Plan9)) |p9_file| {
} else if (self.bin_file.cast(.plan9)) |p9_file| {
const atom_index = p9_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
return self.fail("{s} creating lazy symbol", .{@errorName(err)});
var atom = p9_file.getAtom(atom_index);
@ -15382,7 +15362,7 @@ fn genLazySymbolRef(
),
else => unreachable,
}
} else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
} else if (self.bin_file.cast(.coff)) |coff_file| {
const atom_index = coff_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
return self.fail("{s} creating lazy symbol", .{@errorName(err)});
const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
@ -15396,7 +15376,7 @@ fn genLazySymbolRef(
.call => try self.asmRegister(.{ ._, .call }, reg),
else => unreachable,
}
} else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
} else if (self.bin_file.cast(.macho)) |macho_file| {
const zo = macho_file.getZigObject().?;
const sym_index = zo.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err|
return self.fail("{s} creating lazy symbol", .{@errorName(err)});
@ -16361,7 +16341,6 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
const pt = self.pt;
const mod = pt.zcu;
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const inst_ty = self.typeOfIndex(inst);
const enum_ty = self.typeOf(un_op);
@ -16393,18 +16372,13 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
const operand = try self.resolveInst(un_op);
try self.genSetReg(param_regs[1], enum_ty, operand, .{});
try self.genLazySymbolRef(
.call,
.rax,
link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(mod), mod),
);
const enum_lazy_sym: link.File.LazySymbol = .{ .kind = .code, .ty = enum_ty.toIntern() };
try self.genLazySymbolRef(.call, .rax, enum_lazy_sym);
return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
}
fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
const pt = self.pt;
const mod = pt.zcu;
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const err_ty = self.typeOf(un_op);
@ -16416,7 +16390,8 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
defer self.register_manager.unlockReg(addr_lock);
try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
const anyerror_lazy_sym: link.File.LazySymbol = .{ .kind = .const_data, .ty = .anyerror_type };
try self.genLazySymbolRef(.lea, addr_reg, anyerror_lazy_sym);
const start_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
const start_lock = self.register_manager.lockRegAssumeUnused(start_reg);
@ -18808,7 +18783,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
const pt = self.pt;
return switch (try codegen.genTypedValue(self.bin_file, pt, self.src_loc, val, self.owner.getDecl(pt.zcu))) {
return switch (try codegen.genTypedValue(self.bin_file, pt, self.src_loc, val, self.target.*)) {
.mcv => |mcv| switch (mcv) {
.none => .none,
.undef => .undef,

View File

@ -40,7 +40,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.offset = end_offset - 4,
.length = @intCast(end_offset - start_offset),
}),
.linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
.linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
// Add relocation to the decl.
const zo = elf_file.zigObjectPtr().?;
const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
@ -50,7 +50,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
.r_addend = -4,
});
} else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {
} else if (emit.lower.bin_file.cast(.macho)) |macho_file| {
// Add relocation to the decl.
const zo = macho_file.getZigObject().?;
const atom = zo.symbols.items[symbol.atom_index].getAtom(macho_file).?;
@ -67,7 +67,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.symbolnum = @intCast(symbol.sym_index),
},
});
} else if (emit.lower.bin_file.cast(link.File.Coff)) |coff_file| {
} else if (emit.lower.bin_file.cast(.coff)) |coff_file| {
// Add relocation to the decl.
const atom_index = coff_file.getAtomIndexForSymbol(
.{ .sym_index = symbol.atom_index, .file = null },
@ -88,7 +88,7 @@ pub fn emitMir(emit: *Emit) Error!void {
@tagName(emit.lower.bin_file.tag),
}),
.linker_tlsld => |data| {
const elf_file = emit.lower.bin_file.cast(link.File.Elf).?;
const elf_file = emit.lower.bin_file.cast(.elf).?;
const zo = elf_file.zigObjectPtr().?;
const atom = zo.symbol(data.atom_index).atom(elf_file).?;
const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD);
@ -99,7 +99,7 @@ pub fn emitMir(emit: *Emit) Error!void {
});
},
.linker_dtpoff => |data| {
const elf_file = emit.lower.bin_file.cast(link.File.Elf).?;
const elf_file = emit.lower.bin_file.cast(.elf).?;
const zo = elf_file.zigObjectPtr().?;
const atom = zo.symbol(data.atom_index).atom(elf_file).?;
const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32);
@ -109,7 +109,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.r_addend = 0,
});
},
.linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
.linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
const is_obj_or_static_lib = switch (emit.lower.output_mode) {
.Exe => false,
.Obj => true,
@ -157,7 +157,7 @@ pub fn emitMir(emit: *Emit) Error!void {
});
}
}
} else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {
} else if (emit.lower.bin_file.cast(.macho)) |macho_file| {
const is_obj_or_static_lib = switch (emit.lower.output_mode) {
.Exe => false,
.Obj => true,
@ -196,11 +196,11 @@ pub fn emitMir(emit: *Emit) Error!void {
.linker_got,
.linker_direct,
.linker_import,
=> |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |_| {
=> |symbol| if (emit.lower.bin_file.cast(.elf)) |_| {
unreachable;
} else if (emit.lower.bin_file.cast(link.File.MachO)) |_| {
} else if (emit.lower.bin_file.cast(.macho)) |_| {
unreachable;
} else if (emit.lower.bin_file.cast(link.File.Coff)) |coff_file| {
} else if (emit.lower.bin_file.cast(.coff)) |coff_file| {
const atom_index = coff_file.getAtomIndexForSymbol(.{
.sym_index = symbol.atom_index,
.file = null,
@ -222,7 +222,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.pcrel = true,
.length = 2,
});
} else if (emit.lower.bin_file.cast(link.File.Plan9)) |p9_file| {
} else if (emit.lower.bin_file.cast(.plan9)) |p9_file| {
const atom_index = symbol.atom_index;
try p9_file.addReloc(atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct
.target = symbol.sym_index, // we set sym_index to just be the atom index

View File

@ -348,7 +348,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
assert(mem_op.sib.disp == 0);
assert(mem_op.sib.scale_index.scale == 0);
if (lower.bin_file.cast(link.File.Elf)) |elf_file| {
if (lower.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
const elf_sym = zo.symbol(sym.sym_index);
@ -424,7 +424,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
},
else => unreachable,
};
} else if (lower.bin_file.cast(link.File.MachO)) |macho_file| {
} else if (lower.bin_file.cast(.macho)) |macho_file| {
const zo = macho_file.getZigObject().?;
const macho_sym = zo.symbols.items[sym.sym_index];

View File

@ -17,7 +17,7 @@ const ErrorMsg = Zcu.ErrorMsg;
const InternPool = @import("InternPool.zig");
const Liveness = @import("Liveness.zig");
const Zcu = @import("Zcu.zig");
const Target = std.Target;
const Type = @import("Type.zig");
const Value = @import("Value.zig");
const Zir = std.zig.Zir;
@ -26,7 +26,7 @@ const dev = @import("dev.zig");
pub const Result = union(enum) {
/// The `code` parameter passed to `generateSymbol` has the value ok.
ok: void,
ok,
/// There was a codegen error.
fail: *ErrorMsg,
@ -39,7 +39,7 @@ pub const CodeGenError = error{
};
pub const DebugInfoOutput = union(enum) {
dwarf: *link.File.Dwarf.DeclState,
dwarf: *link.File.Dwarf.NavState,
plan9: *link.File.Plan9.DebugInfoOutput,
none,
};
@ -73,9 +73,7 @@ pub fn generateFunction(
) CodeGenError!Result {
const zcu = pt.zcu;
const func = zcu.funcInfo(func_index);
const decl = zcu.declPtr(func.owner_decl);
const namespace = zcu.namespacePtr(decl.src_namespace);
const target = namespace.fileScope(zcu).mod.resolved_target.result;
const target = zcu.navFileScope(func.owner_nav).mod.resolved_target.result;
switch (target_util.zigBackend(target, false)) {
else => unreachable,
inline .stage2_aarch64,
@ -100,10 +98,8 @@ pub fn generateLazyFunction(
debug_output: DebugInfoOutput,
) CodeGenError!Result {
const zcu = pt.zcu;
const decl_index = lazy_sym.ty.getOwnerDecl(zcu);
const decl = zcu.declPtr(decl_index);
const namespace = zcu.namespacePtr(decl.src_namespace);
const target = namespace.fileScope(zcu).mod.resolved_target.result;
const file = Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(&zcu.intern_pool).file;
const target = zcu.fileByIndex(file).mod.resolved_target.result;
switch (target_util.zigBackend(target, false)) {
else => unreachable,
inline .stage2_x86_64,
@ -115,7 +111,7 @@ pub fn generateLazyFunction(
}
}
fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian, code: []u8) void {
fn writeFloat(comptime F: type, f: F, target: std.Target, endian: std.builtin.Endian, code: []u8) void {
_ = target;
const bits = @typeInfo(F).Float.bits;
const Int = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = bits } });
@ -147,7 +143,7 @@ pub fn generateLazySymbol(
log.debug("generateLazySymbol: kind = {s}, ty = {}", .{
@tagName(lazy_sym.kind),
lazy_sym.ty.fmt(pt),
Type.fromInterned(lazy_sym.ty).fmt(pt),
});
if (lazy_sym.kind == .code) {
@ -155,7 +151,7 @@ pub fn generateLazySymbol(
return generateLazyFunction(bin_file, pt, src_loc, lazy_sym, code, debug_output);
}
if (lazy_sym.ty.isAnyError(pt.zcu)) {
if (lazy_sym.ty == .anyerror_type) {
alignment.* = .@"4";
const err_names = ip.global_error_set.getNamesFromMainThread();
mem.writeInt(u32, try code.addManyAsArray(4), @intCast(err_names.len), endian);
@ -171,9 +167,10 @@ pub fn generateLazySymbol(
}
mem.writeInt(u32, code.items[offset..][0..4], @intCast(code.items.len), endian);
return Result.ok;
} else if (lazy_sym.ty.zigTypeTag(pt.zcu) == .Enum) {
} else if (Type.fromInterned(lazy_sym.ty).zigTypeTag(pt.zcu) == .Enum) {
alignment.* = .@"1";
const tag_names = lazy_sym.ty.enumFields(pt.zcu);
const enum_ty = Type.fromInterned(lazy_sym.ty);
const tag_names = enum_ty.enumFields(pt.zcu);
for (0..tag_names.len) |tag_index| {
const tag_name = tag_names.get(ip)[tag_index].toSlice(ip);
try code.ensureUnusedCapacity(tag_name.len + 1);
@ -185,7 +182,7 @@ pub fn generateLazySymbol(
gpa,
src_loc,
"TODO implement generateLazySymbol for {s} {}",
.{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(pt) },
.{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt) },
) };
}
@ -251,7 +248,7 @@ pub fn generateSymbol(
}),
},
.variable,
.extern_func,
.@"extern",
.func,
.enum_literal,
.empty_enum_value,
@ -651,8 +648,8 @@ fn lowerPtr(
const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
const offset: u64 = prev_offset + ptr.byte_offset;
return switch (ptr.base_addr) {
.decl => |decl| try lowerDeclRef(bin_file, pt, src_loc, decl, code, debug_output, reloc_info, offset),
.anon_decl => |ad| try lowerAnonDeclRef(bin_file, pt, src_loc, ad, code, debug_output, reloc_info, offset),
.nav => |nav| try lowerNavRef(bin_file, pt, src_loc, nav, code, debug_output, reloc_info, offset),
.uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, code, debug_output, reloc_info, offset),
.int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), code, debug_output, reloc_info),
.eu_payload => |eu_ptr| try lowerPtr(
bin_file,
@ -705,11 +702,11 @@ const RelocInfo = struct {
parent_atom_index: u32,
};
fn lowerAnonDeclRef(
fn lowerUavRef(
lf: *link.File,
pt: Zcu.PerThread,
src_loc: Zcu.LazySrcLoc,
anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
uav: InternPool.Key.Ptr.BaseAddr.Uav,
code: *std.ArrayList(u8),
debug_output: DebugInfoOutput,
reloc_info: RelocInfo,
@ -720,23 +717,23 @@ fn lowerAnonDeclRef(
const target = lf.comp.root_mod.resolved_target.result;
const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
const decl_val = anon_decl.val;
const decl_ty = Type.fromInterned(ip.typeOf(decl_val));
log.debug("lowerAnonDecl: ty = {}", .{decl_ty.fmt(pt)});
const is_fn_body = decl_ty.zigTypeTag(pt.zcu) == .Fn;
if (!is_fn_body and !decl_ty.hasRuntimeBits(pt)) {
const uav_val = uav.val;
const uav_ty = Type.fromInterned(ip.typeOf(uav_val));
log.debug("lowerUavRef: ty = {}", .{uav_ty.fmt(pt)});
const is_fn_body = uav_ty.zigTypeTag(pt.zcu) == .Fn;
if (!is_fn_body and !uav_ty.hasRuntimeBits(pt)) {
try code.appendNTimes(0xaa, ptr_width_bytes);
return Result.ok;
}
const decl_align = ip.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment;
const res = try lf.lowerAnonDecl(pt, decl_val, decl_align, src_loc);
const uav_align = ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment;
const res = try lf.lowerUav(pt, uav_val, uav_align, src_loc);
switch (res) {
.ok => {},
.mcv => {},
.fail => |em| return .{ .fail = em },
}
const vaddr = try lf.getAnonDeclVAddr(decl_val, .{
const vaddr = try lf.getUavVAddr(uav_val, .{
.parent_atom_index = reloc_info.parent_atom_index,
.offset = code.items.len,
.addend = @intCast(offset),
@ -752,11 +749,11 @@ fn lowerAnonDeclRef(
return Result.ok;
}
fn lowerDeclRef(
fn lowerNavRef(
lf: *link.File,
pt: Zcu.PerThread,
src_loc: Zcu.LazySrcLoc,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
code: *std.ArrayList(u8),
debug_output: DebugInfoOutput,
reloc_info: RelocInfo,
@ -765,18 +762,18 @@ fn lowerDeclRef(
_ = src_loc;
_ = debug_output;
const zcu = pt.zcu;
const decl = zcu.declPtr(decl_index);
const namespace = zcu.namespacePtr(decl.src_namespace);
const target = namespace.fileScope(zcu).mod.resolved_target.result;
const ip = &zcu.intern_pool;
const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
const ptr_width = target.ptrBitWidth();
const is_fn_body = decl.typeOf(zcu).zigTypeTag(zcu) == .Fn;
if (!is_fn_body and !decl.typeOf(zcu).hasRuntimeBits(pt)) {
const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip));
const is_fn_body = nav_ty.zigTypeTag(zcu) == .Fn;
if (!is_fn_body and !nav_ty.hasRuntimeBits(pt)) {
try code.appendNTimes(0xaa, @divExact(ptr_width, 8));
return Result.ok;
}
const vaddr = try lf.getDeclVAddr(pt, decl_index, .{
const vaddr = try lf.getNavVAddr(pt, nav_index, .{
.parent_atom_index = reloc_info.parent_atom_index,
.offset = code.items.len,
.addend = @intCast(offset),
@ -848,34 +845,21 @@ pub const GenResult = union(enum) {
}
};
fn genDeclRef(
fn genNavRef(
lf: *link.File,
pt: Zcu.PerThread,
src_loc: Zcu.LazySrcLoc,
val: Value,
ptr_decl_index: InternPool.DeclIndex,
ref_nav_index: InternPool.Nav.Index,
target: std.Target,
) CodeGenError!GenResult {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const ty = val.typeOf(zcu);
log.debug("genDeclRef: val = {}", .{val.fmtValue(pt)});
log.debug("genNavRef: val = {}", .{val.fmtValue(pt)});
const ptr_decl = zcu.declPtr(ptr_decl_index);
const namespace = zcu.namespacePtr(ptr_decl.src_namespace);
const target = namespace.fileScope(zcu).mod.resolved_target.result;
const ptr_bits = target.ptrBitWidth();
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
const decl_index = switch (ip.indexToKey(ptr_decl.val.toIntern())) {
.func => |func| func.owner_decl,
.extern_func => |extern_func| extern_func.decl,
else => ptr_decl_index,
};
const decl = zcu.declPtr(decl_index);
if (!decl.typeOf(zcu).isFnOrHasRuntimeBitsIgnoreComptime(pt)) {
const imm: u64 = switch (ptr_bytes) {
if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(pt)) {
const imm: u64 = switch (@divExact(target.ptrBitWidth(), 8)) {
1 => 0xaa,
2 => 0xaaaa,
4 => 0xaaaaaaaa,
@ -900,96 +884,56 @@ fn genDeclRef(
}
}
const decl_namespace = zcu.namespacePtr(decl.src_namespace);
const single_threaded = decl_namespace.fileScope(zcu).mod.single_threaded;
const is_threadlocal = val.isPtrToThreadLocal(zcu) and !single_threaded;
const is_extern = decl.isExtern(zcu);
if (lf.cast(link.File.Elf)) |elf_file| {
const nav_index, const is_extern, const lib_name, const is_threadlocal = switch (ip.indexToKey(zcu.navValue(ref_nav_index).toIntern())) {
.func => |func| .{ func.owner_nav, false, .none, false },
.variable => |variable| .{ variable.owner_nav, false, variable.lib_name, variable.is_threadlocal },
.@"extern" => |@"extern"| .{ @"extern".owner_nav, true, @"extern".lib_name, @"extern".is_threadlocal },
else => .{ ref_nav_index, false, .none, false },
};
const single_threaded = zcu.navFileScope(nav_index).mod.single_threaded;
const name = ip.getNav(nav_index).name;
if (lf.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
if (is_extern) {
const name = decl.name.toSlice(ip);
// TODO audit this
const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
const sym_index = try elf_file.getGlobalSymbol(name, lib_name);
const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
zo.symbol(sym_index).flags.needs_got = true;
return GenResult.mcv(.{ .load_symbol = sym_index });
}
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, decl_index);
if (is_threadlocal) {
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index);
if (!single_threaded and is_threadlocal) {
return GenResult.mcv(.{ .load_tlv = sym_index });
}
return GenResult.mcv(.{ .load_symbol = sym_index });
} else if (lf.cast(link.File.MachO)) |macho_file| {
} else if (lf.cast(.macho)) |macho_file| {
const zo = macho_file.getZigObject().?;
if (is_extern) {
const name = decl.name.toSlice(ip);
const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
const sym_index = try macho_file.getGlobalSymbol(name, lib_name);
const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
zo.symbols.items[sym_index].setSectionFlags(.{ .needs_got = true });
return GenResult.mcv(.{ .load_symbol = sym_index });
}
const sym_index = try zo.getOrCreateMetadataForDecl(macho_file, decl_index);
const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
const sym = zo.symbols.items[sym_index];
if (is_threadlocal) {
if (!single_threaded and is_threadlocal) {
return GenResult.mcv(.{ .load_tlv = sym.nlist_idx });
}
return GenResult.mcv(.{ .load_symbol = sym.nlist_idx });
} else if (lf.cast(link.File.Coff)) |coff_file| {
} else if (lf.cast(.coff)) |coff_file| {
if (is_extern) {
const name = decl.name.toSlice(ip);
// TODO audit this
const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
const global_index = try coff_file.getGlobalSymbol(name, lib_name);
const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
return GenResult.mcv(.{ .load_got = link.File.Coff.global_symbol_bit | global_index });
}
const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index);
const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
return GenResult.mcv(.{ .load_got = sym_index });
} else if (lf.cast(link.File.Plan9)) |p9| {
const atom_index = try p9.seeDecl(decl_index);
} else if (lf.cast(.plan9)) |p9| {
const atom_index = try p9.seeNav(pt, nav_index);
const atom = p9.getAtom(atom_index);
return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(p9) });
} else {
return GenResult.fail(gpa, src_loc, "TODO genDeclRef for target {}", .{target});
}
}
fn genUnnamedConst(
lf: *link.File,
pt: Zcu.PerThread,
src_loc: Zcu.LazySrcLoc,
val: Value,
owner_decl_index: InternPool.DeclIndex,
) CodeGenError!GenResult {
const gpa = lf.comp.gpa;
log.debug("genUnnamedConst: val = {}", .{val.fmtValue(pt)});
const local_sym_index = lf.lowerUnnamedConst(pt, val, owner_decl_index) catch |err| {
return GenResult.fail(gpa, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)});
};
switch (lf.tag) {
.elf => {
return GenResult.mcv(.{ .load_symbol = local_sym_index });
},
.macho => {
const macho_file = lf.cast(link.File.MachO).?;
const local = macho_file.getZigObject().?.symbols.items[local_sym_index];
return GenResult.mcv(.{ .load_symbol = local.nlist_idx });
},
.coff => {
return GenResult.mcv(.{ .load_direct = local_sym_index });
},
.plan9 => {
const atom_index = local_sym_index; // plan9 returns the atom_index
return GenResult.mcv(.{ .load_direct = atom_index });
},
.c => return GenResult.fail(gpa, src_loc, "TODO genUnnamedConst for -ofmt=c", .{}),
.wasm => return GenResult.fail(gpa, src_loc, "TODO genUnnamedConst for wasm", .{}),
.spirv => return GenResult.fail(gpa, src_loc, "TODO genUnnamedConst for spirv", .{}),
.nvptx => return GenResult.fail(gpa, src_loc, "TODO genUnnamedConst for nvptx", .{}),
return GenResult.fail(gpa, src_loc, "TODO genNavRef for target {}", .{target});
}
}
@ -998,7 +942,7 @@ pub fn genTypedValue(
pt: Zcu.PerThread,
src_loc: Zcu.LazySrcLoc,
val: Value,
owner_decl_index: InternPool.DeclIndex,
target: std.Target,
) CodeGenError!GenResult {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
@ -1010,14 +954,9 @@ pub fn genTypedValue(
return GenResult.mcv(.undef);
}
const owner_decl = zcu.declPtr(owner_decl_index);
const namespace = zcu.namespacePtr(owner_decl.src_namespace);
const target = namespace.fileScope(zcu).mod.resolved_target.result;
const ptr_bits = target.ptrBitWidth();
if (!ty.isSlice(zcu)) switch (ip.indexToKey(val.toIntern())) {
.ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
.decl => |decl| return genDeclRef(lf, pt, src_loc, val, decl),
.nav => |nav| return genNavRef(lf, pt, src_loc, val, nav, target),
else => {},
},
else => {},
@ -1042,7 +981,7 @@ pub fn genTypedValue(
},
.Int => {
const info = ty.intInfo(zcu);
if (info.bits <= ptr_bits) {
if (info.bits <= target.ptrBitWidth()) {
const unsigned: u64 = switch (info.signedness) {
.signed => @bitCast(val.toSignedInt(pt)),
.unsigned => val.toUnsignedInt(pt),
@ -1060,7 +999,7 @@ pub fn genTypedValue(
pt,
src_loc,
val.optionalValue(zcu) orelse return GenResult.mcv(.{ .immediate = 0 }),
owner_decl_index,
target,
);
} else if (ty.abiSize(pt) == 1) {
return GenResult.mcv(.{ .immediate = @intFromBool(!val.isNull(zcu)) });
@ -1073,7 +1012,7 @@ pub fn genTypedValue(
pt,
src_loc,
Value.fromInterned(enum_tag.int),
owner_decl_index,
target,
);
},
.ErrorSet => {
@ -1096,14 +1035,14 @@ pub fn genTypedValue(
.ty = err_type.toIntern(),
.name = err_name,
} })),
owner_decl_index,
target,
),
.payload => return genTypedValue(
lf,
pt,
src_loc,
try pt.intValue(err_int_ty, 0),
owner_decl_index,
target,
),
}
}
@ -1121,7 +1060,7 @@ pub fn genTypedValue(
else => {},
}
return genUnnamedConst(lf, pt, src_loc, val, owner_decl_index);
return lf.lowerUav(pt, val.toIntern(), .none, src_loc);
}
pub fn errUnionPayloadOffset(payload_ty: Type, pt: Zcu.PerThread) u64 {

View File

@ -38,8 +38,8 @@ pub const CValue = union(enum) {
/// Index into a tuple's fields
field: usize,
/// By-value
decl: InternPool.DeclIndex,
decl_ref: InternPool.DeclIndex,
nav: InternPool.Nav.Index,
nav_ref: InternPool.Nav.Index,
/// An undefined value (cannot be dereferenced)
undef: Type,
/// Rendered as an identifier (using fmtIdent)
@ -58,19 +58,12 @@ const BlockData = struct {
pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
pub const LazyFnKey = union(enum) {
tag_name: InternPool.DeclIndex,
never_tail: InternPool.DeclIndex,
never_inline: InternPool.DeclIndex,
tag_name: InternPool.Index,
never_tail: InternPool.Nav.Index,
never_inline: InternPool.Nav.Index,
};
pub const LazyFnValue = struct {
fn_name: CType.Pool.String,
data: Data,
const Data = union {
tag_name: Type,
never_tail: void,
never_inline: void,
};
};
pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
@ -498,10 +491,11 @@ pub const Function = struct {
return f.object.dg.fmtIntLiteral(val, .Other);
}
fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 {
fn getLazyFnName(f: *Function, key: LazyFnKey) ![]const u8 {
const gpa = f.object.dg.gpa;
const pt = f.object.dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const ctype_pool = &f.object.dg.ctype_pool;
const gop = try f.lazy_fns.getOrPut(gpa, key);
@ -511,19 +505,19 @@ pub const Function = struct {
gop.value_ptr.* = .{
.fn_name = switch (key) {
.tag_name,
=> |enum_ty| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{
@tagName(key),
fmtIdent(ip.loadEnumType(enum_ty).name.toSlice(ip)),
@intFromEnum(enum_ty),
}),
.never_tail,
.never_inline,
=> |owner_decl| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{
=> |owner_nav| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{
@tagName(key),
fmtIdent(zcu.declPtr(owner_decl).name.toSlice(&zcu.intern_pool)),
@intFromEnum(owner_decl),
fmtIdent(ip.getNav(owner_nav).name.toSlice(ip)),
@intFromEnum(owner_nav),
}),
},
.data = switch (key) {
.tag_name => .{ .tag_name = data.tag_name },
.never_tail => .{ .never_tail = data.never_tail },
.never_inline => .{ .never_inline = data.never_inline },
},
};
}
return gop.value_ptr.fn_name.toSlice(ctype_pool).?;
@ -618,12 +612,12 @@ pub const DeclGen = struct {
scratch: std.ArrayListUnmanaged(u32),
/// Keeps track of anonymous decls that need to be rendered before this
/// (named) Decl in the output C code.
anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock),
aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
uav_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.AvBlock),
aligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
pub const Pass = union(enum) {
decl: InternPool.DeclIndex,
anon: InternPool.Index,
nav: InternPool.Nav.Index,
uav: InternPool.Index,
flush,
};
@ -634,39 +628,37 @@ pub const DeclGen = struct {
fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
@setCold(true);
const zcu = dg.pt.zcu;
const decl_index = dg.pass.decl;
const decl = zcu.declPtr(decl_index);
const src_loc = decl.navSrcLoc(zcu);
const src_loc = zcu.navSrcLoc(dg.pass.nav);
dg.error_msg = try Zcu.ErrorMsg.create(dg.gpa, src_loc, format, args);
return error.AnalysisFail;
}
fn renderAnonDeclValue(
fn renderUav(
dg: *DeclGen,
writer: anytype,
anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
uav: InternPool.Key.Ptr.BaseAddr.Uav,
location: ValueRenderLocation,
) error{ OutOfMemory, AnalysisFail }!void {
const pt = dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const ctype_pool = &dg.ctype_pool;
const decl_val = Value.fromInterned(anon_decl.val);
const decl_ty = decl_val.typeOf(zcu);
const uav_val = Value.fromInterned(uav.val);
const uav_ty = uav_val.typeOf(zcu);
// Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
const ptr_ty = Type.fromInterned(anon_decl.orig_ty);
if (ptr_ty.isPtrAtRuntime(zcu) and !decl_ty.isFnOrHasRuntimeBits(pt)) {
const ptr_ty = Type.fromInterned(uav.orig_ty);
if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isFnOrHasRuntimeBits(pt)) {
return dg.writeCValue(writer, .{ .undef = ptr_ty });
}
// Chase function values in order to be able to reference the original function.
if (decl_val.getFunction(zcu)) |func|
return dg.renderDeclValue(writer, func.owner_decl, location);
if (decl_val.getExternFunc(zcu)) |extern_func|
return dg.renderDeclValue(writer, extern_func.decl, location);
assert(decl_val.getVariable(zcu) == null);
switch (ip.indexToKey(uav.val)) {
.variable => unreachable,
.func => |func| return dg.renderNav(writer, func.owner_nav, location),
.@"extern" => |@"extern"| return dg.renderNav(writer, @"extern".owner_nav, location),
else => {},
}
// We shouldn't cast C function pointers as this is UB (when you call
// them). The analysis until now should ensure that the C function
@ -674,22 +666,22 @@ pub const DeclGen = struct {
// somewhere and we should let the C compiler tell us about it.
const ptr_ctype = try dg.ctypeFromType(ptr_ty, .complete);
const elem_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
const need_cast = !elem_ctype.eql(decl_ctype) and
(elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
const uav_ctype = try dg.ctypeFromType(uav_ty, .complete);
const need_cast = !elem_ctype.eql(uav_ctype) and
(elem_ctype.info(ctype_pool) != .function or uav_ctype.info(ctype_pool) != .function);
if (need_cast) {
try writer.writeAll("((");
try dg.renderCType(writer, ptr_ctype);
try writer.writeByte(')');
}
try writer.writeByte('&');
try renderAnonDeclName(writer, decl_val);
try renderUavName(writer, uav_val);
if (need_cast) try writer.writeByte(')');
// Indicate that the anon decl should be rendered to the output so that
// our reference above is not undefined.
const ptr_type = ip.indexToKey(anon_decl.orig_ty).ptr_type;
const gop = try dg.anon_decl_deps.getOrPut(dg.gpa, anon_decl.val);
const ptr_type = ip.indexToKey(uav.orig_ty).ptr_type;
const gop = try dg.uav_deps.getOrPut(dg.gpa, uav.val);
if (!gop.found_existing) gop.value_ptr.* = .{};
// Only insert an alignment entry if the alignment is greater than ABI
@ -698,7 +690,7 @@ pub const DeclGen = struct {
if (explicit_alignment != .none) {
const abi_alignment = Type.fromInterned(ptr_type.child).abiAlignment(pt);
if (explicit_alignment.order(abi_alignment).compare(.gt)) {
const aligned_gop = try dg.aligned_anon_decls.getOrPut(dg.gpa, anon_decl.val);
const aligned_gop = try dg.aligned_uavs.getOrPut(dg.gpa, uav.val);
aligned_gop.value_ptr.* = if (aligned_gop.found_existing)
aligned_gop.value_ptr.maxStrict(explicit_alignment)
else
@ -707,30 +699,32 @@ pub const DeclGen = struct {
}
}
fn renderDeclValue(
fn renderNav(
dg: *DeclGen,
writer: anytype,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
location: ValueRenderLocation,
) error{ OutOfMemory, AnalysisFail }!void {
_ = location;
const pt = dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const ctype_pool = &dg.ctype_pool;
const decl = zcu.declPtr(decl_index);
assert(decl.has_tv);
// Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
const decl_ty = decl.typeOf(zcu);
const ptr_ty = try decl.declPtrType(pt);
if (!decl_ty.isFnOrHasRuntimeBits(pt)) {
return dg.writeCValue(writer, .{ .undef = ptr_ty });
}
// Chase function values in order to be able to reference the original function.
if (decl.val.getFunction(zcu)) |func| if (func.owner_decl != decl_index)
return dg.renderDeclValue(writer, func.owner_decl, location);
if (decl.val.getExternFunc(zcu)) |extern_func| if (extern_func.decl != decl_index)
return dg.renderDeclValue(writer, extern_func.decl, location);
const owner_nav = switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
.variable => |variable| variable.owner_nav,
.func => |func| func.owner_nav,
.@"extern" => |@"extern"| @"extern".owner_nav,
else => nav_index,
};
// Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
const nav_ty = Type.fromInterned(ip.getNav(owner_nav).typeOf(ip));
const ptr_ty = try pt.navPtrType(owner_nav);
if (!nav_ty.isFnOrHasRuntimeBits(pt)) {
return dg.writeCValue(writer, .{ .undef = ptr_ty });
}
// We shouldn't cast C function pointers as this is UB (when you call
// them). The analysis until now should ensure that the C function
@ -738,16 +732,16 @@ pub const DeclGen = struct {
// somewhere and we should let the C compiler tell us about it.
const ctype = try dg.ctypeFromType(ptr_ty, .complete);
const elem_ctype = ctype.info(ctype_pool).pointer.elem_ctype;
const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
const need_cast = !elem_ctype.eql(decl_ctype) and
(elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
const nav_ctype = try dg.ctypeFromType(nav_ty, .complete);
const need_cast = !elem_ctype.eql(nav_ctype) and
(elem_ctype.info(ctype_pool) != .function or nav_ctype.info(ctype_pool) != .function);
if (need_cast) {
try writer.writeAll("((");
try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
try writer.writeByte('&');
try dg.renderDeclName(writer, decl_index);
try dg.renderNavName(writer, owner_nav);
if (need_cast) try writer.writeByte(')');
}
@ -769,8 +763,8 @@ pub const DeclGen = struct {
try writer.print("){x}", .{try dg.fmtIntLiteral(addr_val, .Other)});
},
.decl_ptr => |decl| try dg.renderDeclValue(writer, decl, location),
.anon_decl_ptr => |ad| try dg.renderAnonDeclValue(writer, ad, location),
.nav_ptr => |nav| try dg.renderNav(writer, nav, location),
.uav_ptr => |uav| try dg.renderUav(writer, uav, location),
inline .eu_payload_ptr, .opt_payload_ptr => |info| {
try writer.writeAll("&(");
@ -918,7 +912,7 @@ pub const DeclGen = struct {
.true => try writer.writeAll("true"),
},
.variable,
.extern_func,
.@"extern",
.func,
.enum_literal,
.empty_enum_value,
@ -1743,7 +1737,7 @@ pub const DeclGen = struct {
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -1758,7 +1752,7 @@ pub const DeclGen = struct {
.aggregate,
.un,
.memoized_call,
=> unreachable,
=> unreachable, // values, not types
},
}
}
@ -1770,7 +1764,7 @@ pub const DeclGen = struct {
fn_align: InternPool.Alignment,
kind: CType.Kind,
name: union(enum) {
decl: InternPool.DeclIndex,
nav: InternPool.Nav.Index,
fmt_ctype_pool_string: std.fmt.Formatter(formatCTypePoolString),
@"export": struct {
main_name: InternPool.NullTerminatedString,
@ -1805,7 +1799,7 @@ pub const DeclGen = struct {
try w.print("{}", .{trailing});
switch (name) {
.decl => |decl_index| try dg.renderDeclName(w, decl_index),
.nav => |nav| try dg.renderNavName(w, nav),
.fmt_ctype_pool_string => |fmt| try w.print("{ }", .{fmt}),
.@"export" => |@"export"| try w.print("{ }", .{fmtIdent(@"export".extern_name.toSlice(ip))}),
}
@ -1828,7 +1822,7 @@ pub const DeclGen = struct {
.forward => {
if (fn_align.toByteUnits()) |a| try w.print(" zig_align_fn({})", .{a});
switch (name) {
.decl, .fmt_ctype_pool_string => {},
.nav, .fmt_ctype_pool_string => {},
.@"export" => |@"export"| {
const extern_name = @"export".extern_name.toSlice(ip);
const is_mangled = isMangledIdent(extern_name, true);
@ -2069,8 +2063,8 @@ pub const DeclGen = struct {
fn writeName(dg: *DeclGen, w: anytype, c_value: CValue) !void {
switch (c_value) {
.new_local, .local => |i| try w.print("t{d}", .{i}),
.constant => |val| try renderAnonDeclName(w, val),
.decl => |decl| try dg.renderDeclName(w, decl),
.constant => |uav| try renderUavName(w, uav),
.nav => |nav| try dg.renderNavName(w, nav),
.identifier => |ident| try w.print("{ }", .{fmtIdent(ident)}),
else => unreachable,
}
@ -2079,13 +2073,13 @@ pub const DeclGen = struct {
fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void {
switch (c_value) {
.none, .new_local, .local, .local_ref => unreachable,
.constant => |val| try renderAnonDeclName(w, val),
.constant => |uav| try renderUavName(w, uav),
.arg, .arg_array => unreachable,
.field => |i| try w.print("f{d}", .{i}),
.decl => |decl| try dg.renderDeclName(w, decl),
.decl_ref => |decl| {
.nav => |nav| try dg.renderNavName(w, nav),
.nav_ref => |nav| {
try w.writeByte('&');
try dg.renderDeclName(w, decl);
try dg.renderNavName(w, nav);
},
.undef => |ty| try dg.renderUndefValue(w, ty, .Other),
.identifier => |ident| try w.print("{ }", .{fmtIdent(ident)}),
@ -2111,12 +2105,12 @@ pub const DeclGen = struct {
.ctype_pool_string,
=> unreachable,
.field => |i| try w.print("f{d}", .{i}),
.decl => |decl| {
.nav => |nav| {
try w.writeAll("(*");
try dg.renderDeclName(w, decl);
try dg.renderNavName(w, nav);
try w.writeByte(')');
},
.decl_ref => |decl| try dg.renderDeclName(w, decl),
.nav_ref => |nav| try dg.renderNavName(w, nav),
.undef => unreachable,
.identifier => |ident| try w.print("(*{ })", .{fmtIdent(ident)}),
.payload_identifier => |ident| try w.print("(*{ }.{ })", .{
@ -2150,11 +2144,11 @@ pub const DeclGen = struct {
.arg_array,
.ctype_pool_string,
=> unreachable,
.decl, .identifier, .payload_identifier => {
.nav, .identifier, .payload_identifier => {
try dg.writeCValue(writer, c_value);
try writer.writeAll("->");
},
.decl_ref => {
.nav_ref => {
try dg.writeCValueDeref(writer, c_value);
try writer.writeByte('.');
},
@ -2164,46 +2158,53 @@ pub const DeclGen = struct {
fn renderFwdDecl(
dg: *DeclGen,
decl_index: InternPool.DeclIndex,
variable: InternPool.Key.Variable,
nav_index: InternPool.Nav.Index,
flags: struct {
is_extern: bool,
is_const: bool,
is_threadlocal: bool,
is_weak_linkage: bool,
},
) !void {
const zcu = dg.pt.zcu;
const decl = zcu.declPtr(decl_index);
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
const fwd = dg.fwdDeclWriter();
try fwd.writeAll(if (variable.is_extern) "zig_extern " else "static ");
if (variable.is_weak_linkage) try fwd.writeAll("zig_weak_linkage ");
if (variable.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
try fwd.writeAll(if (flags.is_extern) "zig_extern " else "static ");
if (flags.is_weak_linkage) try fwd.writeAll("zig_weak_linkage ");
if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
try dg.renderTypeAndName(
fwd,
decl.typeOf(zcu),
.{ .decl = decl_index },
CQualifiers.init(.{ .@"const" = variable.is_const }),
decl.alignment,
Type.fromInterned(nav.typeOf(ip)),
.{ .nav = nav_index },
CQualifiers.init(.{ .@"const" = flags.is_const }),
nav.status.resolved.alignment,
.complete,
);
try fwd.writeAll(";\n");
}
fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: InternPool.DeclIndex) !void {
fn renderNavName(dg: *DeclGen, writer: anytype, nav_index: InternPool.Nav.Index) !void {
const zcu = dg.pt.zcu;
const ip = &zcu.intern_pool;
const decl = zcu.declPtr(decl_index);
if (decl.getExternDecl(zcu).unwrap()) |extern_decl_index| try writer.print("{ }", .{
fmtIdent(zcu.declPtr(extern_decl_index).name.toSlice(ip)),
}) else {
// MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
// expand to 3x the length of its input, but let's cut it off at a much shorter limit.
const fqn_slice = decl.fqn.toSlice(ip);
try writer.print("{}__{d}", .{
fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),
@intFromEnum(decl_index),
});
switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
.@"extern" => |@"extern"| try writer.print("{ }", .{
fmtIdent(ip.getNav(@"extern".owner_nav).name.toSlice(ip)),
}),
else => {
// MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
// expand to 3x the length of its input, but let's cut it off at a much shorter limit.
const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
try writer.print("{}__{d}", .{
fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),
@intFromEnum(nav_index),
});
},
}
}
fn renderAnonDeclName(writer: anytype, anon_decl_val: Value) !void {
try writer.print("__anon_{d}", .{@intFromEnum(anon_decl_val.toIntern())});
fn renderUavName(writer: anytype, uav: Value) !void {
try writer.print("__anon_{d}", .{@intFromEnum(uav.toIntern())});
}
fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void {
@ -2301,12 +2302,13 @@ fn renderFwdDeclTypeName(
fwd_decl: CType.Info.FwdDecl,
attributes: []const u8,
) !void {
const ip = &zcu.intern_pool;
try w.print("{s} {s}", .{ @tagName(fwd_decl.tag), attributes });
switch (fwd_decl.name) {
.anon => try w.print("anon__lazy_{d}", .{@intFromEnum(ctype.index)}),
.owner_decl => |owner_decl| try w.print("{}__{d}", .{
fmtIdent(zcu.declPtr(owner_decl).name.toSlice(&zcu.intern_pool)),
@intFromEnum(owner_decl),
.index => |index| try w.print("{}__{d}", .{
fmtIdent(Type.fromInterned(index).containerTypeName(ip).toSlice(&zcu.intern_pool)),
@intFromEnum(index),
}),
}
}
@ -2340,11 +2342,11 @@ fn renderTypePrefix(
},
.aligned => switch (pass) {
.decl => |decl_index| try w.print("decl__{d}_{d}", .{
@intFromEnum(decl_index), @intFromEnum(ctype.index),
.nav => |nav| try w.print("nav__{d}_{d}", .{
@intFromEnum(nav), @intFromEnum(ctype.index),
}),
.anon => |anon_decl| try w.print("anon__{d}_{d}", .{
@intFromEnum(anon_decl), @intFromEnum(ctype.index),
.uav => |uav| try w.print("uav__{d}_{d}", .{
@intFromEnum(uav), @intFromEnum(ctype.index),
}),
.flush => try renderAlignedTypeName(w, ctype),
},
@ -2370,15 +2372,15 @@ fn renderTypePrefix(
.fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
.anon => switch (pass) {
.decl => |decl_index| try w.print("decl__{d}_{d}", .{
@intFromEnum(decl_index), @intFromEnum(ctype.index),
.nav => |nav| try w.print("nav__{d}_{d}", .{
@intFromEnum(nav), @intFromEnum(ctype.index),
}),
.anon => |anon_decl| try w.print("anon__{d}_{d}", .{
@intFromEnum(anon_decl), @intFromEnum(ctype.index),
.uav => |uav| try w.print("uav__{d}_{d}", .{
@intFromEnum(uav), @intFromEnum(ctype.index),
}),
.flush => try renderFwdDeclTypeName(zcu, w, ctype, fwd_decl_info, ""),
},
.owner_decl => try renderFwdDeclTypeName(zcu, w, ctype, fwd_decl_info, ""),
.index => try renderFwdDeclTypeName(zcu, w, ctype, fwd_decl_info, ""),
},
.aggregate => |aggregate_info| switch (aggregate_info.name) {
@ -2557,7 +2559,7 @@ pub fn genTypeDecl(
try writer.writeAll(";\n");
}
switch (pass) {
.decl, .anon => {
.nav, .uav => {
try writer.writeAll("typedef ");
_ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
try writer.writeByte(' ');
@ -2569,7 +2571,7 @@ pub fn genTypeDecl(
},
.fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
.anon => switch (pass) {
.decl, .anon => {
.nav, .uav => {
try writer.writeAll("typedef ");
_ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
try writer.writeByte(' ');
@ -2578,13 +2580,14 @@ pub fn genTypeDecl(
},
.flush => {},
},
.owner_decl => |owner_decl_index| if (!found_existing) {
.index => |index| if (!found_existing) {
const ip = &zcu.intern_pool;
const ty = Type.fromInterned(index);
_ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
try writer.writeByte(';');
const owner_decl = zcu.declPtr(owner_decl_index);
const owner_mod = zcu.namespacePtr(owner_decl.src_namespace).fileScope(zcu).mod;
if (!owner_mod.strip) try writer.print(" /* {} */", .{
owner_decl.fqn.fmt(&zcu.intern_pool),
const file_scope = ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(ip).file;
if (!zcu.fileByIndex(file_scope).mod.strip) try writer.print(" /* {} */", .{
ty.containerTypeName(ip).fmt(ip),
});
try writer.writeByte('\n');
},
@ -2709,9 +2712,8 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
const key = lazy_fn.key_ptr.*;
const val = lazy_fn.value_ptr;
switch (key) {
.tag_name => {
const enum_ty = val.data.tag_name;
.tag_name => |enum_ty_ip| {
const enum_ty = Type.fromInterned(enum_ty_ip);
const name_slice_ty = Type.slice_const_u8_sentinel_0;
try w.writeAll("static ");
@ -2756,25 +2758,25 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
_ = try airBreakpoint(w);
try w.writeAll("}\n");
},
.never_tail, .never_inline => |fn_decl_index| {
const fn_decl = zcu.declPtr(fn_decl_index);
const fn_ctype = try o.dg.ctypeFromType(fn_decl.typeOf(zcu), .complete);
.never_tail, .never_inline => |fn_nav_index| {
const fn_val = zcu.navValue(fn_nav_index);
const fn_ctype = try o.dg.ctypeFromType(fn_val.typeOf(zcu), .complete);
const fn_info = fn_ctype.info(ctype_pool).function;
const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool);
const fwd = o.dg.fwdDeclWriter();
try fwd.print("static zig_{s} ", .{@tagName(key)});
try o.dg.renderFunctionSignature(fwd, fn_decl.val, fn_decl.alignment, .forward, .{
try o.dg.renderFunctionSignature(fwd, fn_val, ip.getNav(fn_nav_index).status.resolved.alignment, .forward, .{
.fmt_ctype_pool_string = fn_name,
});
try fwd.writeAll(";\n");
try w.print("zig_{s} ", .{@tagName(key)});
try o.dg.renderFunctionSignature(w, fn_decl.val, .none, .complete, .{
try o.dg.renderFunctionSignature(w, fn_val, .none, .complete, .{
.fmt_ctype_pool_string = fn_name,
});
try w.writeAll(" {\n return ");
try o.dg.renderDeclName(w, fn_decl_index);
try o.dg.renderNavName(w, fn_nav_index);
try w.writeByte('(');
for (0..fn_info.param_ctypes.len) |arg| {
if (arg > 0) try w.writeAll(", ");
@ -2791,9 +2793,11 @@ pub fn genFunc(f: *Function) !void {
const o = &f.object;
const zcu = o.dg.pt.zcu;
const ip = &zcu.intern_pool;
const gpa = o.dg.gpa;
const decl_index = o.dg.pass.decl;
const decl = zcu.declPtr(decl_index);
const nav_index = o.dg.pass.nav;
const nav_val = zcu.navValue(nav_index);
const nav = ip.getNav(nav_index);
o.code_header = std.ArrayList(u8).init(gpa);
defer o.code_header.deinit();
@ -2802,21 +2806,21 @@ pub fn genFunc(f: *Function) !void {
try fwd.writeAll("static ");
try o.dg.renderFunctionSignature(
fwd,
decl.val,
decl.alignment,
nav_val,
nav.status.resolved.alignment,
.forward,
.{ .decl = decl_index },
.{ .nav = nav_index },
);
try fwd.writeAll(";\n");
if (decl.@"linksection".toSlice(&zcu.intern_pool)) |s|
if (nav.status.resolved.@"linksection".toSlice(ip)) |s|
try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)});
try o.dg.renderFunctionSignature(
o.writer(),
decl.val,
nav_val,
.none,
.complete,
.{ .decl = decl_index },
.{ .nav = nav_index },
);
try o.writer().writeByte(' ');
@ -2883,44 +2887,66 @@ pub fn genDecl(o: *Object) !void {
const pt = o.dg.pt;
const zcu = pt.zcu;
const decl_index = o.dg.pass.decl;
const decl = zcu.declPtr(decl_index);
const decl_ty = decl.typeOf(zcu);
const ip = &zcu.intern_pool;
const nav = ip.getNav(o.dg.pass.nav);
const nav_ty = Type.fromInterned(nav.typeOf(ip));
if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(pt)) return;
if (decl.val.getExternFunc(zcu)) |_| {
const fwd = o.dg.fwdDeclWriter();
try fwd.writeAll("zig_extern ");
try o.dg.renderFunctionSignature(
fwd,
decl.val,
decl.alignment,
.forward,
.{ .@"export" = .{
.main_name = decl.name,
.extern_name = decl.name,
} },
);
try fwd.writeAll(";\n");
} else if (decl.val.getVariable(zcu)) |variable| {
try o.dg.renderFwdDecl(decl_index, variable);
if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(pt)) return;
switch (ip.indexToKey(nav.status.resolved.val)) {
.@"extern" => |@"extern"| {
if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
.is_extern = true,
.is_const = @"extern".is_const,
.is_threadlocal = @"extern".is_threadlocal,
.is_weak_linkage = @"extern".is_weak_linkage,
});
if (variable.is_extern) return;
const w = o.writer();
if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
if (decl.@"linksection".toSlice(&zcu.intern_pool)) |s|
try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
const decl_c_value = .{ .decl = decl_index };
try o.dg.renderTypeAndName(w, decl_ty, decl_c_value, .{}, decl.alignment, .complete);
try w.writeAll(" = ");
try o.dg.renderValue(w, Value.fromInterned(variable.init), .StaticInitializer);
try w.writeByte(';');
try o.indent_writer.insertNewline();
} else {
const decl_c_value = .{ .decl = decl_index };
try genDeclValue(o, decl.val, decl_c_value, decl.alignment, decl.@"linksection");
const fwd = o.dg.fwdDeclWriter();
try fwd.writeAll("zig_extern ");
try o.dg.renderFunctionSignature(
fwd,
Value.fromInterned(nav.status.resolved.val),
nav.status.resolved.alignment,
.forward,
.{ .@"export" = .{
.main_name = nav.name,
.extern_name = nav.name,
} },
);
try fwd.writeAll(";\n");
},
.variable => |variable| {
try o.dg.renderFwdDecl(o.dg.pass.nav, .{
.is_extern = false,
.is_const = false,
.is_threadlocal = variable.is_threadlocal,
.is_weak_linkage = variable.is_weak_linkage,
});
const w = o.writer();
if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
if (nav.status.resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
try o.dg.renderTypeAndName(
w,
nav_ty,
.{ .nav = o.dg.pass.nav },
.{},
nav.status.resolved.alignment,
.complete,
);
try w.writeAll(" = ");
try o.dg.renderValue(w, Value.fromInterned(variable.init), .StaticInitializer);
try w.writeByte(';');
try o.indent_writer.insertNewline();
},
else => try genDeclValue(
o,
Value.fromInterned(nav.status.resolved.val),
.{ .nav = o.dg.pass.nav },
nav.status.resolved.alignment,
nav.status.resolved.@"linksection",
),
}
}
@ -2956,31 +2982,34 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
const main_name = zcu.all_exports.items[export_indices[0]].opts.name;
try fwd.writeAll("#define ");
switch (exported) {
.decl_index => |decl_index| try dg.renderDeclName(fwd, decl_index),
.value => |value| try DeclGen.renderAnonDeclName(fwd, Value.fromInterned(value)),
.nav => |nav| try dg.renderNavName(fwd, nav),
.uav => |uav| try DeclGen.renderUavName(fwd, Value.fromInterned(uav)),
}
try fwd.writeByte(' ');
try fwd.print("{ }", .{fmtIdent(main_name.toSlice(ip))});
try fwd.writeByte('\n');
const is_const = switch (ip.indexToKey(exported.getValue(zcu).toIntern())) {
.func, .extern_func => return for (export_indices) |export_index| {
const @"export" = &zcu.all_exports.items[export_index];
try fwd.writeAll("zig_extern ");
if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn ");
try dg.renderFunctionSignature(
fwd,
exported.getValue(zcu),
exported.getAlign(zcu),
.forward,
.{ .@"export" = .{
.main_name = main_name,
.extern_name = @"export".opts.name,
} },
);
try fwd.writeAll(";\n");
},
.variable => |variable| variable.is_const,
const exported_val = exported.getValue(zcu);
if (ip.isFunctionType(exported_val.typeOf(zcu).toIntern())) return for (export_indices) |export_index| {
const @"export" = &zcu.all_exports.items[export_index];
try fwd.writeAll("zig_extern ");
if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn ");
try dg.renderFunctionSignature(
fwd,
exported.getValue(zcu),
exported.getAlign(zcu),
.forward,
.{ .@"export" = .{
.main_name = main_name,
.extern_name = @"export".opts.name,
} },
);
try fwd.writeAll(";\n");
};
const is_const = switch (ip.indexToKey(exported_val.toIntern())) {
.func => unreachable,
.@"extern" => |@"extern"| @"extern".is_const,
.variable => false,
else => true,
};
for (export_indices) |export_index| {
@ -4474,24 +4503,19 @@ fn airCall(
callee: {
known: {
const fn_decl = fn_decl: {
const callee_val = (try f.air.value(pl_op.operand, pt)) orelse break :known;
break :fn_decl switch (zcu.intern_pool.indexToKey(callee_val.toIntern())) {
.extern_func => |extern_func| extern_func.decl,
.func => |func| func.owner_decl,
.ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
.decl => |decl| decl,
else => break :known,
} else break :known,
const callee_val = (try f.air.value(pl_op.operand, pt)) orelse break :known;
const fn_nav = switch (zcu.intern_pool.indexToKey(callee_val.toIntern())) {
.@"extern" => |@"extern"| @"extern".owner_nav,
.func => |func| func.owner_nav,
.ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
.nav => |nav| nav,
else => break :known,
};
} else break :known,
else => break :known,
};
switch (modifier) {
.auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl),
inline .never_tail, .never_inline => |m| try writer.writeAll(try f.getLazyFnName(
@unionInit(LazyFnKey, @tagName(m), fn_decl),
@unionInit(LazyFnValue.Data, @tagName(m), {}),
)),
.auto, .always_tail => try f.object.dg.renderNavName(writer, fn_nav),
inline .never_tail, .never_inline => |m| try writer.writeAll(try f.getLazyFnName(@unionInit(LazyFnKey, @tagName(m), fn_nav))),
else => unreachable,
}
break :callee;
@ -4554,11 +4578,12 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
const pt = f.object.dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = f.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
const owner_decl = zcu.funcOwnerDeclPtr(extra.data.func);
const owner_nav = ip.getNav(zcu.funcInfo(extra.data.func).owner_nav);
const writer = f.object.writer();
try writer.print("/* inline:{} */\n", .{owner_decl.fqn.fmt(&zcu.intern_pool)});
try writer.print("/* inline:{} */\n", .{owner_nav.fqn.fmt(&zcu.intern_pool)});
return lowerBlock(f, inst, @ptrCast(f.air.extra[extra.end..][0..extra.data.body_len]));
}
@ -5059,7 +5084,7 @@ fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool
else => switch (value) {
.constant => |val| switch (dg.pt.zcu.intern_pool.indexToKey(val.toIntern())) {
.ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
.decl => false,
.nav => false,
else => true,
} else true,
else => true,
@ -6841,8 +6866,6 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
const pt = f.object.dg.pt;
const zcu = pt.zcu;
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const inst_ty = f.typeOfIndex(inst);
@ -6854,7 +6877,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
const local = try f.allocLocal(inst, inst_ty);
try f.writeCValue(writer, local, .Other);
try writer.print(" = {s}(", .{
try f.getLazyFnName(.{ .tag_name = enum_ty.getOwnerDecl(zcu) }, .{ .tag_name = enum_ty }),
try f.getLazyFnName(.{ .tag_name = enum_ty.toIntern() }),
});
try f.writeCValue(writer, operand, .Other);
try writer.writeAll(");\n");
@ -7390,18 +7413,17 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
const pt = f.object.dg.pt;
const zcu = pt.zcu;
const inst_ty = f.typeOfIndex(inst);
const decl_index = f.object.dg.pass.decl;
const decl = zcu.declPtr(decl_index);
const function_ctype = try f.ctypeFromType(decl.typeOf(zcu), .complete);
const params_len = function_ctype.info(&f.object.dg.ctype_pool).function.param_ctypes.len;
const function_ty = zcu.navValue(f.object.dg.pass.nav).typeOf(zcu);
const function_info = (try f.ctypeFromType(function_ty, .complete)).info(&f.object.dg.ctype_pool).function;
assert(function_info.varargs);
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
try writer.writeAll("va_start(*(va_list *)&");
try f.writeCValue(writer, local, .Other);
if (params_len > 0) {
if (function_info.param_ctypes.len > 0) {
try writer.writeAll(", ");
try f.writeCValue(writer, .{ .arg = params_len - 1 }, .FunctionArgument);
try f.writeCValue(writer, .{ .arg = function_info.param_ctypes.len - 1 }, .FunctionArgument);
}
try writer.writeAll(");\n");
return local;
@ -7941,7 +7963,7 @@ const Materialize = struct {
pub fn start(f: *Function, inst: Air.Inst.Index, ty: Type, value: CValue) !Materialize {
return .{ .local = switch (value) {
.local_ref, .constant, .decl_ref, .undef => try f.moveCValue(inst, ty, value),
.local_ref, .constant, .nav_ref, .undef => try f.moveCValue(inst, ty, value),
.new_local => |local| .{ .local = local },
else => value,
} };

View File

@ -449,18 +449,18 @@ pub fn info(ctype: CType, pool: *const Pool) Info {
},
.fwd_decl_struct => return .{ .fwd_decl = .{
.tag = .@"struct",
.name = .{ .owner_decl = @enumFromInt(item.data) },
.name = .{ .index = @enumFromInt(item.data) },
} },
.fwd_decl_union => return .{ .fwd_decl = .{
.tag = .@"union",
.name = .{ .owner_decl = @enumFromInt(item.data) },
.name = .{ .index = @enumFromInt(item.data) },
} },
.aggregate_struct_anon => {
const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
return .{ .aggregate = .{
.tag = .@"struct",
.name = .{ .anon = .{
.owner_decl = extra_trail.extra.owner_decl,
.index = extra_trail.extra.index,
.id = extra_trail.extra.id,
} },
.fields = .{
@ -474,7 +474,7 @@ pub fn info(ctype: CType, pool: *const Pool) Info {
return .{ .aggregate = .{
.tag = .@"union",
.name = .{ .anon = .{
.owner_decl = extra_trail.extra.owner_decl,
.index = extra_trail.extra.index,
.id = extra_trail.extra.id,
} },
.fields = .{
@ -489,7 +489,7 @@ pub fn info(ctype: CType, pool: *const Pool) Info {
.tag = .@"struct",
.@"packed" = true,
.name = .{ .anon = .{
.owner_decl = extra_trail.extra.owner_decl,
.index = extra_trail.extra.index,
.id = extra_trail.extra.id,
} },
.fields = .{
@ -504,7 +504,7 @@ pub fn info(ctype: CType, pool: *const Pool) Info {
.tag = .@"union",
.@"packed" = true,
.name = .{ .anon = .{
.owner_decl = extra_trail.extra.owner_decl,
.index = extra_trail.extra.index,
.id = extra_trail.extra.id,
} },
.fields = .{
@ -834,7 +834,7 @@ pub const Info = union(enum) {
tag: AggregateTag,
name: union(enum) {
anon: Field.Slice,
owner_decl: DeclIndex,
index: InternPool.Index,
},
};
@ -843,7 +843,7 @@ pub const Info = union(enum) {
@"packed": bool = false,
name: union(enum) {
anon: struct {
owner_decl: DeclIndex,
index: InternPool.Index,
id: u32,
},
fwd_decl: CType,
@ -885,14 +885,14 @@ pub const Info = union(enum) {
rhs_pool,
pool_adapter,
),
.owner_decl => |lhs_owner_decl| rhs_info.fwd_decl.name == .owner_decl and
lhs_owner_decl == rhs_info.fwd_decl.name.owner_decl,
.index => |lhs_index| rhs_info.fwd_decl.name == .index and
lhs_index == rhs_info.fwd_decl.name.index,
},
.aggregate => |lhs_aggregate_info| lhs_aggregate_info.tag == rhs_info.aggregate.tag and
lhs_aggregate_info.@"packed" == rhs_info.aggregate.@"packed" and
switch (lhs_aggregate_info.name) {
.anon => |lhs_anon| rhs_info.aggregate.name == .anon and
lhs_anon.owner_decl == rhs_info.aggregate.name.anon.owner_decl and
lhs_anon.index == rhs_info.aggregate.name.anon.index and
lhs_anon.id == rhs_info.aggregate.name.anon.id,
.fwd_decl => |lhs_fwd_decl| rhs_info.aggregate.name == .fwd_decl and
pool_adapter.eql(lhs_fwd_decl, rhs_info.aggregate.name.fwd_decl),
@ -1105,7 +1105,7 @@ pub const Pool = struct {
tag: Info.AggregateTag,
name: union(enum) {
anon: []const Info.Field,
owner_decl: DeclIndex,
index: InternPool.Index,
},
},
) !CType {
@ -1145,13 +1145,13 @@ pub const Pool = struct {
.@"enum" => unreachable,
}, extra_index);
},
.owner_decl => |owner_decl| {
hasher.update(owner_decl);
.index => |index| {
hasher.update(index);
return pool.tagData(allocator, hasher, switch (fwd_decl_info.tag) {
.@"struct" => .fwd_decl_struct,
.@"union" => .fwd_decl_union,
.@"enum" => unreachable,
}, @intFromEnum(owner_decl));
}, @intFromEnum(index));
},
}
}
@ -1164,7 +1164,7 @@ pub const Pool = struct {
@"packed": bool = false,
name: union(enum) {
anon: struct {
owner_decl: DeclIndex,
index: InternPool.Index,
id: u32,
},
fwd_decl: CType,
@ -1176,7 +1176,7 @@ pub const Pool = struct {
switch (aggregate_info.name) {
.anon => |anon| {
const extra: AggregateAnon = .{
.owner_decl = anon.owner_decl,
.index = anon.index,
.id = anon.id,
.fields_len = @intCast(aggregate_info.fields.len),
};
@ -1683,7 +1683,7 @@ pub const Pool = struct {
.auto, .@"extern" => {
const fwd_decl = try pool.getFwdDecl(allocator, .{
.tag = .@"struct",
.name = .{ .owner_decl = loaded_struct.decl.unwrap().? },
.name = .{ .index = ip_index },
});
if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(pt))
fwd_decl
@ -1822,7 +1822,7 @@ pub const Pool = struct {
const has_tag = loaded_union.hasTag(ip);
const fwd_decl = try pool.getFwdDecl(allocator, .{
.tag = if (has_tag) .@"struct" else .@"union",
.name = .{ .owner_decl = loaded_union.decl },
.name = .{ .index = ip_index },
});
if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(pt))
fwd_decl
@ -1837,7 +1837,7 @@ pub const Pool = struct {
);
var hasher = Hasher.init;
var tag: Pool.Tag = .aggregate_union;
var payload_align: Alignment = .@"1";
var payload_align: InternPool.Alignment = .@"1";
for (0..loaded_union.field_types.len) |field_index| {
const field_type = Type.fromInterned(
loaded_union.field_types.get(ip)[field_index],
@ -1915,7 +1915,7 @@ pub const Pool = struct {
&hasher,
AggregateAnon,
.{
.owner_decl = loaded_union.decl,
.index = ip_index,
.id = 0,
.fields_len = fields_len,
},
@ -2017,7 +2017,7 @@ pub const Pool = struct {
.undef,
.simple_value,
.variable,
.extern_func,
.@"extern",
.func,
.int,
.err,
@ -2032,7 +2032,7 @@ pub const Pool = struct {
.aggregate,
.un,
.memoized_call,
=> unreachable,
=> unreachable, // values, not types
},
}
}
@ -2123,9 +2123,9 @@ pub const Pool = struct {
});
}
},
.owner_decl => |owner_decl| pool.items.appendAssumeCapacity(.{
.index => |index| pool.items.appendAssumeCapacity(.{
.tag = tag,
.data = @intFromEnum(owner_decl),
.data = @intFromEnum(index),
}),
},
.aggregate => |aggregate_info| {
@ -2133,7 +2133,7 @@ pub const Pool = struct {
.tag = tag,
.data = switch (aggregate_info.name) {
.anon => |anon| try pool.addExtra(allocator, AggregateAnon, .{
.owner_decl = anon.owner_decl,
.index = anon.index,
.id = anon.id,
.fields_len = aggregate_info.fields.len,
}, aggregate_info.fields.len * @typeInfo(Field).Struct.fields.len),
@ -2221,7 +2221,7 @@ pub const Pool = struct {
Pool.Tag => @compileError("pass tag to final"),
CType, CType.Index => @compileError("hash ctype.hash(pool) instead"),
String, String.Index => @compileError("hash string.slice(pool) instead"),
u32, DeclIndex, Aligned.Flags => hasher.impl.update(std.mem.asBytes(&data)),
u32, InternPool.Index, Aligned.Flags => hasher.impl.update(std.mem.asBytes(&data)),
[]const u8 => hasher.impl.update(data),
else => @compileError("unhandled type: " ++ @typeName(@TypeOf(data))),
}
@ -2426,7 +2426,7 @@ pub const Pool = struct {
};
const AggregateAnon = struct {
owner_decl: DeclIndex,
index: InternPool.Index,
id: u32,
fields_len: u32,
};
@ -2467,7 +2467,7 @@ pub const Pool = struct {
const value = @field(extra, field.name);
array.appendAssumeCapacity(switch (field.type) {
u32 => value,
CType.Index, String.Index, DeclIndex => @intFromEnum(value),
CType.Index, String.Index, InternPool.Index => @intFromEnum(value),
Aligned.Flags => @bitCast(value),
else => @compileError("bad field type: " ++ field.name ++ ": " ++
@typeName(field.type)),
@ -2530,7 +2530,7 @@ pub const Pool = struct {
inline for (fields, pool.extra.items[extra_index..][0..fields.len]) |field, value|
@field(extra, field.name) = switch (field.type) {
u32 => value,
CType.Index, String.Index, DeclIndex => @enumFromInt(value),
CType.Index, String.Index, InternPool.Index => @enumFromInt(value),
Aligned.Flags => @bitCast(value),
else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
};
@ -2546,8 +2546,8 @@ pub const Pool = struct {
};
pub const AlignAs = packed struct {
@"align": Alignment,
abi: Alignment,
@"align": InternPool.Alignment,
abi: InternPool.Alignment,
pub fn fromAlignment(alignas: AlignAs) AlignAs {
assert(alignas.abi != .none);
@ -2556,14 +2556,14 @@ pub const AlignAs = packed struct {
.abi = alignas.abi,
};
}
pub fn fromAbiAlignment(abi: Alignment) AlignAs {
pub fn fromAbiAlignment(abi: InternPool.Alignment) AlignAs {
assert(abi != .none);
return .{ .@"align" = abi, .abi = abi };
}
pub fn fromByteUnits(@"align": u64, abi: u64) AlignAs {
return fromAlignment(.{
.@"align" = Alignment.fromByteUnits(@"align"),
.abi = Alignment.fromNonzeroByteUnits(abi),
.@"align" = InternPool.Alignment.fromByteUnits(@"align"),
.abi = InternPool.Alignment.fromNonzeroByteUnits(abi),
});
}
@ -2578,11 +2578,10 @@ pub const AlignAs = packed struct {
}
};
const Alignment = @import("../../InternPool.zig").Alignment;
const assert = std.debug.assert;
const CType = @This();
const InternPool = @import("../../InternPool.zig");
const Module = @import("../../Package/Module.zig");
const std = @import("std");
const Type = @import("../../Type.zig");
const Zcu = @import("../../Zcu.zig");
const DeclIndex = @import("../../InternPool.zig").DeclIndex;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -216,8 +216,8 @@ pub const File = struct {
}
}
pub fn cast(base: *File, comptime T: type) ?*T {
return if (base.tag == T.base_tag) @fieldParentPtr("base", base) else null;
pub fn cast(base: *File, comptime tag: Tag) if (dev.env.supports(tag.devFeature())) ?*tag.Type() else ?noreturn {
return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;
}
pub fn makeWritable(base: *File) !void {
@ -231,7 +231,7 @@ pub const File = struct {
const emit = base.emit;
if (base.child_pid) |pid| {
if (builtin.os.tag == .windows) {
base.cast(Coff).?.ptraceAttach(pid) catch |err| {
base.cast(.coff).?.ptraceAttach(pid) catch |err| {
log.warn("attaching failed with error: {s}", .{@errorName(err)});
};
} else {
@ -249,7 +249,7 @@ pub const File = struct {
.linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
log.warn("ptrace failure: {s}", .{@errorName(err)});
},
.macos => base.cast(MachO).?.ptraceAttach(pid) catch |err| {
.macos => base.cast(.macho).?.ptraceAttach(pid) catch |err| {
log.warn("attaching failed with error: {s}", .{@errorName(err)});
},
.windows => unreachable,
@ -317,10 +317,10 @@ pub const File = struct {
if (base.child_pid) |pid| {
switch (builtin.os.tag) {
.macos => base.cast(MachO).?.ptraceDetach(pid) catch |err| {
.macos => base.cast(.macho).?.ptraceDetach(pid) catch |err| {
log.warn("detaching failed with error: {s}", .{@errorName(err)});
},
.windows => base.cast(Coff).?.ptraceDetach(pid),
.windows => base.cast(.coff).?.ptraceDetach(pid),
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
@ -329,7 +329,7 @@ pub const File = struct {
}
}
pub const UpdateDeclError = error{
pub const UpdateNavError = error{
OutOfMemory,
Overflow,
Underflow,
@ -367,27 +367,12 @@ pub const File = struct {
HotSwapUnavailableOnHostOperatingSystem,
};
/// Called from within the CodeGen to lower a local variable instantion as an unnamed
/// constant. Returns the symbol index of the lowered constant in the read-only section
/// of the final binary.
pub fn lowerUnnamedConst(base: *File, pt: Zcu.PerThread, val: Value, decl_index: InternPool.DeclIndex) UpdateDeclError!u32 {
switch (base.tag) {
.spirv => unreachable,
.c => unreachable,
.nvptx => unreachable,
inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerUnnamedConst(pt, val, decl_index);
},
}
}
/// Called from within CodeGen to retrieve the symbol index of a global symbol.
/// If no symbol exists yet with this name, a new undefined global symbol will
/// be created. This symbol may get resolved once all relocatables are (re-)linked.
/// Optionally, it is possible to specify where to expect the symbol defined if it
/// is an import.
pub fn getGlobalSymbol(base: *File, name: []const u8, lib_name: ?[]const u8) UpdateDeclError!u32 {
pub fn getGlobalSymbol(base: *File, name: []const u8, lib_name: ?[]const u8) UpdateNavError!u32 {
log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name });
switch (base.tag) {
.plan9 => unreachable,
@ -401,14 +386,14 @@ pub const File = struct {
}
}
/// May be called before or after updateExports for any given Decl.
pub fn updateDecl(base: *File, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) UpdateDeclError!void {
const decl = pt.zcu.declPtr(decl_index);
assert(decl.has_tv);
/// May be called before or after updateExports for any given Nav.
pub fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
const nav = pt.zcu.intern_pool.getNav(nav_index);
assert(nav.status == .resolved);
switch (base.tag) {
inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateDecl(pt, decl_index);
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateNav(pt, nav_index);
},
}
}
@ -420,7 +405,7 @@ pub const File = struct {
func_index: InternPool.Index,
air: Air,
liveness: Liveness,
) UpdateDeclError!void {
) UpdateNavError!void {
switch (base.tag) {
inline else => |tag| {
dev.check(tag.devFeature());
@ -429,14 +414,16 @@ pub const File = struct {
}
}
pub fn updateDeclLineNumber(base: *File, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) UpdateDeclError!void {
const decl = pt.zcu.declPtr(decl_index);
assert(decl.has_tv);
pub fn updateNavLineNumber(
base: *File,
pt: Zcu.PerThread,
nav_index: InternPool.Nav.Index,
) UpdateNavError!void {
switch (base.tag) {
.spirv, .nvptx => {},
inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateDeclLineNumber(pt, decl_index);
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateNavineNumber(pt, nav_index);
},
}
}
@ -675,52 +662,50 @@ pub const File = struct {
addend: u32,
};
/// Get allocated `Decl`'s address in virtual memory.
/// Get allocated `Nav`'s address in virtual memory.
/// The linker is passed information about the containing atom, `parent_atom_index`, and offset within it's
/// memory buffer, `offset`, so that it can make a note of potential relocation sites, should the
/// `Decl`'s address was not yet resolved, or the containing atom gets moved in virtual memory.
/// May be called before or after updateFunc/updateDecl therefore it is up to the linker to allocate
/// `Nav`'s address was not yet resolved, or the containing atom gets moved in virtual memory.
/// May be called before or after updateFunc/updateNav therefore it is up to the linker to allocate
/// the block/atom.
pub fn getDeclVAddr(base: *File, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex, reloc_info: RelocInfo) !u64 {
pub fn getNavVAddr(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: RelocInfo) !u64 {
switch (base.tag) {
.c => unreachable,
.spirv => unreachable,
.nvptx => unreachable,
inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).getDeclVAddr(pt, decl_index, reloc_info);
return @as(*tag.Type(), @fieldParentPtr("base", base)).getNavVAddr(pt, nav_index, reloc_info);
},
}
}
pub const LowerResult = @import("codegen.zig").Result;
pub fn lowerAnonDecl(
pub fn lowerUav(
base: *File,
pt: Zcu.PerThread,
decl_val: InternPool.Index,
decl_align: InternPool.Alignment,
src_loc: Zcu.LazySrcLoc,
) !LowerResult {
) !@import("codegen.zig").GenResult {
switch (base.tag) {
.c => unreachable,
.spirv => unreachable,
.nvptx => unreachable,
inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerAnonDecl(pt, decl_val, decl_align, src_loc);
return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerUav(pt, decl_val, decl_align, src_loc);
},
}
}
pub fn getAnonDeclVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 {
pub fn getUavVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 {
switch (base.tag) {
.c => unreachable,
.spirv => unreachable,
.nvptx => unreachable,
inline else => |tag| {
dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).getAnonDeclVAddr(decl_val, reloc_info);
return @as(*tag.Type(), @fieldParentPtr("base", base)).getUavVAddr(decl_val, reloc_info);
},
}
}
@ -964,18 +949,7 @@ pub const File = struct {
pub const Kind = enum { code, const_data };
kind: Kind,
ty: Type,
pub fn initDecl(kind: Kind, decl: ?InternPool.DeclIndex, mod: *Zcu) LazySymbol {
return .{ .kind = kind, .ty = if (decl) |decl_index|
mod.declPtr(decl_index).val.toType()
else
Type.anyerror };
}
pub fn getDecl(self: LazySymbol, mod: *Zcu) InternPool.OptionalDeclIndex {
return InternPool.OptionalDeclIndex.init(self.ty.getOwnerDeclOrNull(mod));
}
ty: InternPool.Index,
};
pub fn effectiveOutputMode(

View File

@ -19,28 +19,27 @@ const Value = @import("../Value.zig");
const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
pub const base_tag: link.File.Tag = .c;
pub const zig_h = "#include \"zig.h\"\n";
base: link.File,
/// This linker backend does not try to incrementally link output C source code.
/// Instead, it tracks all declarations in this table, and iterates over it
/// in the flush function, stitching pre-rendered pieces of C code together.
decl_table: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, DeclBlock) = .{},
navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvBlock) = .{},
/// All the string bytes of rendered C code, all squished into one array.
/// While in progress, a separate buffer is used, and then when finished, the
/// buffer is copied into this one.
string_bytes: std.ArrayListUnmanaged(u8) = .{},
/// Tracks all the anonymous decls that are used by all the decls so they can
/// be rendered during flush().
anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, DeclBlock) = .{},
/// Sparse set of anon decls that are overaligned. Underaligned anon decls are
uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, AvBlock) = .{},
/// Sparse set of uavs that are overaligned. Underaligned anon decls are
/// lowered the same as ABI-aligned anon decls. The keys here are a subset of
/// the keys of `anon_decls`.
aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .{},
/// the keys of `uavs`.
aligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .{},
exported_decls: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, ExportedBlock) = .{},
exported_values: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock) = .{},
exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ExportedBlock) = .{},
exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock) = .{},
/// Optimization, `updateDecl` reuses this buffer rather than creating a new
/// one with every call.
@ -67,7 +66,7 @@ const String = extern struct {
};
/// Per-declaration data.
pub const DeclBlock = struct {
pub const AvBlock = struct {
code: String = String.empty,
fwd_decl: String = String.empty,
/// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
@ -76,10 +75,10 @@ pub const DeclBlock = struct {
/// May contain string references to ctype_pool
lazy_fns: codegen.LazyFnMap = .{},
fn deinit(db: *DeclBlock, gpa: Allocator) void {
db.lazy_fns.deinit(gpa);
db.ctype_pool.deinit(gpa);
db.* = undefined;
fn deinit(ab: *AvBlock, gpa: Allocator) void {
ab.lazy_fns.deinit(gpa);
ab.ctype_pool.deinit(gpa);
ab.* = undefined;
}
};
@ -158,16 +157,16 @@ pub fn createEmpty(
pub fn deinit(self: *C) void {
const gpa = self.base.comp.gpa;
for (self.decl_table.values()) |*db| {
for (self.navs.values()) |*db| {
db.deinit(gpa);
}
self.decl_table.deinit(gpa);
self.navs.deinit(gpa);
for (self.anon_decls.values()) |*db| {
for (self.uavs.values()) |*db| {
db.deinit(gpa);
}
self.anon_decls.deinit(gpa);
self.aligned_anon_decls.deinit(gpa);
self.uavs.deinit(gpa);
self.aligned_uavs.deinit(gpa);
self.string_bytes.deinit(gpa);
self.fwd_decl_buf.deinit(gpa);
@ -194,9 +193,7 @@ pub fn updateFunc(
const zcu = pt.zcu;
const gpa = zcu.gpa;
const func = zcu.funcInfo(func_index);
const decl_index = func.owner_decl;
const decl = zcu.declPtr(decl_index);
const gop = try self.decl_table.getOrPut(gpa, decl_index);
const gop = try self.navs.getOrPut(gpa, func.owner_nav);
if (!gop.found_existing) gop.value_ptr.* = .{};
const ctype_pool = &gop.value_ptr.ctype_pool;
const lazy_fns = &gop.value_ptr.lazy_fns;
@ -208,8 +205,6 @@ pub fn updateFunc(
fwd_decl.clearRetainingCapacity();
code.clearRetainingCapacity();
const file_scope = zcu.namespacePtr(decl.src_namespace).fileScope(zcu);
var function: codegen.Function = .{
.value_map = codegen.CValueMap.init(gpa),
.air = air,
@ -219,15 +214,15 @@ pub fn updateFunc(
.dg = .{
.gpa = gpa,
.pt = pt,
.mod = file_scope.mod,
.mod = zcu.navFileScope(func.owner_nav).mod,
.error_msg = null,
.pass = .{ .decl = decl_index },
.is_naked_fn = decl.typeOf(zcu).fnCallingConvention(zcu) == .Naked,
.pass = .{ .nav = func.owner_nav },
.is_naked_fn = zcu.navValue(func.owner_nav).typeOf(zcu).fnCallingConvention(zcu) == .Naked,
.fwd_decl = fwd_decl.toManaged(gpa),
.ctype_pool = ctype_pool.*,
.scratch = .{},
.anon_decl_deps = self.anon_decls,
.aligned_anon_decls = self.aligned_anon_decls,
.uav_deps = self.uavs,
.aligned_uavs = self.aligned_uavs,
},
.code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
@ -236,8 +231,8 @@ pub fn updateFunc(
};
function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
defer {
self.anon_decls = function.object.dg.anon_decl_deps;
self.aligned_anon_decls = function.object.dg.aligned_anon_decls;
self.uavs = function.object.dg.uav_deps;
self.aligned_uavs = function.object.dg.aligned_uavs;
fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
ctype_pool.* = function.object.dg.ctype_pool.move();
ctype_pool.freeUnusedCapacity(gpa);
@ -248,13 +243,10 @@ pub fn updateFunc(
function.deinit();
}
try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
try zcu.failed_codegen.ensureUnusedCapacity(gpa, 1);
codegen.genFunc(&function) catch |err| switch (err) {
error.AnalysisFail => {
zcu.failed_analysis.putAssumeCapacityNoClobber(
InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
function.object.dg.error_msg.?,
);
zcu.failed_codegen.putAssumeCapacityNoClobber(func.owner_nav, function.object.dg.error_msg.?);
return;
},
else => |e| return e,
@ -263,9 +255,9 @@ pub fn updateFunc(
gop.value_ptr.code = try self.addString(function.object.code.items);
}
fn updateAnonDecl(self: *C, pt: Zcu.PerThread, i: usize) !void {
fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
const gpa = self.base.comp.gpa;
const anon_decl = self.anon_decls.keys()[i];
const uav = self.uavs.keys()[i];
const fwd_decl = &self.fwd_decl_buf;
const code = &self.code_buf;
@ -278,21 +270,21 @@ fn updateAnonDecl(self: *C, pt: Zcu.PerThread, i: usize) !void {
.pt = pt,
.mod = pt.zcu.root_mod,
.error_msg = null,
.pass = .{ .anon = anon_decl },
.pass = .{ .uav = uav },
.is_naked_fn = false,
.fwd_decl = fwd_decl.toManaged(gpa),
.ctype_pool = codegen.CType.Pool.empty,
.scratch = .{},
.anon_decl_deps = self.anon_decls,
.aligned_anon_decls = self.aligned_anon_decls,
.uav_deps = self.uavs,
.aligned_uavs = self.aligned_uavs,
},
.code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
};
object.indent_writer = .{ .underlying_writer = object.code.writer() };
defer {
self.anon_decls = object.dg.anon_decl_deps;
self.aligned_anon_decls = object.dg.aligned_anon_decls;
self.uavs = object.dg.uav_deps;
self.aligned_uavs = object.dg.aligned_uavs;
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
object.dg.ctype_pool.deinit(object.dg.gpa);
object.dg.scratch.deinit(gpa);
@ -300,8 +292,8 @@ fn updateAnonDecl(self: *C, pt: Zcu.PerThread, i: usize) !void {
}
try object.dg.ctype_pool.init(gpa);
const c_value: codegen.CValue = .{ .constant = Value.fromInterned(anon_decl) };
const alignment: Alignment = self.aligned_anon_decls.get(anon_decl) orelse .none;
const c_value: codegen.CValue = .{ .constant = Value.fromInterned(uav) };
const alignment: Alignment = self.aligned_uavs.get(uav) orelse .none;
codegen.genDeclValue(&object, c_value.constant, c_value, alignment, .none) catch |err| switch (err) {
error.AnalysisFail => {
@panic("TODO: C backend AnalysisFail on anonymous decl");
@ -312,23 +304,22 @@ fn updateAnonDecl(self: *C, pt: Zcu.PerThread, i: usize) !void {
};
object.dg.ctype_pool.freeUnusedCapacity(gpa);
object.dg.anon_decl_deps.values()[i] = .{
object.dg.uav_deps.values()[i] = .{
.code = try self.addString(object.code.items),
.fwd_decl = try self.addString(object.dg.fwd_decl.items),
.ctype_pool = object.dg.ctype_pool.move(),
};
}
pub fn updateDecl(self: *C, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = self.base.comp.gpa;
const zcu = pt.zcu;
const decl = zcu.declPtr(decl_index);
const gop = try self.decl_table.getOrPut(gpa, decl_index);
errdefer _ = self.decl_table.pop();
const gop = try self.navs.getOrPut(gpa, nav_index);
errdefer _ = self.navs.pop();
if (!gop.found_existing) gop.value_ptr.* = .{};
const ctype_pool = &gop.value_ptr.ctype_pool;
const fwd_decl = &self.fwd_decl_buf;
@ -338,29 +329,27 @@ pub fn updateDecl(self: *C, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex)
fwd_decl.clearRetainingCapacity();
code.clearRetainingCapacity();
const file_scope = zcu.namespacePtr(decl.src_namespace).fileScope(zcu);
var object: codegen.Object = .{
.dg = .{
.gpa = gpa,
.pt = pt,
.mod = file_scope.mod,
.mod = zcu.navFileScope(nav_index).mod,
.error_msg = null,
.pass = .{ .decl = decl_index },
.pass = .{ .nav = nav_index },
.is_naked_fn = false,
.fwd_decl = fwd_decl.toManaged(gpa),
.ctype_pool = ctype_pool.*,
.scratch = .{},
.anon_decl_deps = self.anon_decls,
.aligned_anon_decls = self.aligned_anon_decls,
.uav_deps = self.uavs,
.aligned_uavs = self.aligned_uavs,
},
.code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
};
object.indent_writer = .{ .underlying_writer = object.code.writer() };
defer {
self.anon_decls = object.dg.anon_decl_deps;
self.aligned_anon_decls = object.dg.aligned_anon_decls;
self.uavs = object.dg.uav_deps;
self.aligned_uavs = object.dg.aligned_uavs;
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
ctype_pool.* = object.dg.ctype_pool.move();
ctype_pool.freeUnusedCapacity(gpa);
@ -368,13 +357,10 @@ pub fn updateDecl(self: *C, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex)
code.* = object.code.moveToUnmanaged();
}
try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
try zcu.failed_codegen.ensureUnusedCapacity(gpa, 1);
codegen.genDecl(&object) catch |err| switch (err) {
error.AnalysisFail => {
zcu.failed_analysis.putAssumeCapacityNoClobber(
InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
object.dg.error_msg.?,
);
zcu.failed_codegen.putAssumeCapacityNoClobber(nav_index, object.dg.error_msg.?);
return;
},
else => |e| return e,
@ -383,12 +369,12 @@ pub fn updateDecl(self: *C, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex)
gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);
}
pub fn updateDeclLineNumber(self: *C, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
pub fn updateNavLineNumber(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
// The C backend does not have the ability to fix line numbers without re-generating
// the entire Decl.
_ = self;
_ = pt;
_ = decl_index;
_ = nav_index;
}
pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
@ -422,12 +408,13 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
const comp = self.base.comp;
const gpa = comp.gpa;
const zcu = self.base.comp.module.?;
const ip = &zcu.intern_pool;
const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = tid };
{
var i: usize = 0;
while (i < self.anon_decls.count()) : (i += 1) {
try updateAnonDecl(self, pt, i);
while (i < self.uavs.count()) : (i += 1) {
try self.updateUav(pt, i);
}
}
@ -484,30 +471,28 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
}
}
for (self.anon_decls.keys(), self.anon_decls.values()) |value, *decl_block| try self.flushDeclBlock(
for (self.uavs.keys(), self.uavs.values()) |uav, *av_block| try self.flushAvBlock(
pt,
zcu.root_mod,
&f,
decl_block,
self.exported_values.getPtr(value),
av_block,
self.exported_uavs.getPtr(uav),
export_names,
.none,
);
for (self.decl_table.keys(), self.decl_table.values()) |decl_index, *decl_block| {
const decl = zcu.declPtr(decl_index);
const extern_name = if (decl.isExtern(zcu)) decl.name.toOptional() else .none;
const mod = zcu.namespacePtr(decl.src_namespace).fileScope(zcu).mod;
try self.flushDeclBlock(
pt,
mod,
&f,
decl_block,
self.exported_decls.getPtr(decl_index),
export_names,
extern_name,
);
}
for (self.navs.keys(), self.navs.values()) |nav, *av_block| try self.flushAvBlock(
pt,
zcu.navFileScope(nav).mod,
&f,
av_block,
self.exported_navs.getPtr(nav),
export_names,
if (ip.indexToKey(zcu.navValue(nav).toIntern()) == .@"extern")
ip.getNav(nav).name.toOptional()
else
.none,
);
}
{
@ -516,12 +501,12 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
try f.ctype_pool.init(gpa);
try self.flushCTypes(zcu, &f, .flush, &f.lazy_ctype_pool);
for (self.anon_decls.keys(), self.anon_decls.values()) |anon_decl, decl_block| {
try self.flushCTypes(zcu, &f, .{ .anon = anon_decl }, &decl_block.ctype_pool);
for (self.uavs.keys(), self.uavs.values()) |uav, av_block| {
try self.flushCTypes(zcu, &f, .{ .uav = uav }, &av_block.ctype_pool);
}
for (self.decl_table.keys(), self.decl_table.values()) |decl_index, decl_block| {
try self.flushCTypes(zcu, &f, .{ .decl = decl_index }, &decl_block.ctype_pool);
for (self.navs.keys(), self.navs.values()) |nav, av_block| {
try self.flushCTypes(zcu, &f, .{ .nav = nav }, &av_block.ctype_pool);
}
}
@ -539,26 +524,21 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
f.file_size += lazy_fwd_decl_len;
// Now the code.
try f.all_buffers.ensureUnusedCapacity(gpa, 1 + (self.anon_decls.count() + self.decl_table.count()) * 2);
try f.all_buffers.ensureUnusedCapacity(gpa, 1 + (self.uavs.count() + self.navs.count()) * 2);
f.appendBufAssumeCapacity(self.lazy_code_buf.items);
for (self.anon_decls.keys(), self.anon_decls.values()) |anon_decl, decl_block| f.appendCodeAssumeCapacity(
if (self.exported_values.contains(anon_decl))
.default
else switch (zcu.intern_pool.indexToKey(anon_decl)) {
.extern_func => .zig_extern,
.variable => |variable| if (variable.is_extern) .zig_extern else .static,
for (self.uavs.keys(), self.uavs.values()) |uav, av_block| f.appendCodeAssumeCapacity(
if (self.exported_uavs.contains(uav)) .default else switch (ip.indexToKey(uav)) {
.@"extern" => .zig_extern,
else => .static,
},
self.getString(decl_block.code),
self.getString(av_block.code),
);
for (self.decl_table.keys(), self.decl_table.values()) |decl_index, decl_block| f.appendCodeAssumeCapacity(
if (self.exported_decls.contains(decl_index))
.default
else if (zcu.declPtr(decl_index).isExtern(zcu))
.zig_extern
else
.static,
self.getString(decl_block.code),
for (self.navs.keys(), self.navs.values()) |nav, av_block| f.appendCodeAssumeCapacity(
if (self.exported_navs.contains(nav)) .default else switch (ip.indexToKey(zcu.navValue(nav).toIntern())) {
.@"extern" => .zig_extern,
else => .static,
},
self.getString(av_block.code),
);
const file = self.base.file.?;
@ -689,16 +669,16 @@ fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) F
.fwd_decl = fwd_decl.toManaged(gpa),
.ctype_pool = ctype_pool.*,
.scratch = .{},
.anon_decl_deps = self.anon_decls,
.aligned_anon_decls = self.aligned_anon_decls,
.uav_deps = self.uavs,
.aligned_uavs = self.aligned_uavs,
},
.code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
};
object.indent_writer = .{ .underlying_writer = object.code.writer() };
defer {
self.anon_decls = object.dg.anon_decl_deps;
self.aligned_anon_decls = object.dg.aligned_anon_decls;
self.uavs = object.dg.uav_deps;
self.aligned_uavs = object.dg.aligned_uavs;
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
ctype_pool.* = object.dg.ctype_pool.move();
ctype_pool.freeUnusedCapacity(gpa);
@ -736,8 +716,8 @@ fn flushLazyFn(
.fwd_decl = fwd_decl.toManaged(gpa),
.ctype_pool = ctype_pool.*,
.scratch = .{},
.anon_decl_deps = .{},
.aligned_anon_decls = .{},
.uav_deps = .{},
.aligned_uavs = .{},
},
.code = code.toManaged(gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
@ -746,8 +726,8 @@ fn flushLazyFn(
defer {
// If this assert trips just handle the anon_decl_deps the same as
// `updateFunc()` does.
assert(object.dg.anon_decl_deps.count() == 0);
assert(object.dg.aligned_anon_decls.count() == 0);
assert(object.dg.uav_deps.count() == 0);
assert(object.dg.aligned_uavs.count() == 0);
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
ctype_pool.* = object.dg.ctype_pool.move();
ctype_pool.freeUnusedCapacity(gpa);
@ -781,31 +761,33 @@ fn flushLazyFns(
}
}
fn flushDeclBlock(
fn flushAvBlock(
self: *C,
pt: Zcu.PerThread,
mod: *Module,
f: *Flush,
decl_block: *const DeclBlock,
av_block: *const AvBlock,
exported_block: ?*const ExportedBlock,
export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
extern_name: InternPool.OptionalNullTerminatedString,
) FlushDeclError!void {
const gpa = self.base.comp.gpa;
try self.flushLazyFns(pt, mod, f, &decl_block.ctype_pool, decl_block.lazy_fns);
try self.flushLazyFns(pt, mod, f, &av_block.ctype_pool, av_block.lazy_fns);
try f.all_buffers.ensureUnusedCapacity(gpa, 1);
// avoid emitting extern decls that are already exported
if (extern_name.unwrap()) |name| if (export_names.contains(name)) return;
f.appendBufAssumeCapacity(self.getString(if (exported_block) |exported|
exported.fwd_decl
else
decl_block.fwd_decl));
av_block.fwd_decl));
}
pub fn flushEmitH(zcu: *Zcu) !void {
const tracy = trace(@src());
defer tracy.end();
if (true) return; // emit-h is regressed
const emit_h = zcu.emit_h orelse return;
// We collect a list of buffers to write, and write them all at once with pwritev 😎
@ -854,17 +836,17 @@ pub fn updateExports(
const zcu = pt.zcu;
const gpa = zcu.gpa;
const mod, const pass: codegen.DeclGen.Pass, const decl_block, const exported_block = switch (exported) {
.decl_index => |decl_index| .{
zcu.namespacePtr(zcu.declPtr(decl_index).src_namespace).fileScope(zcu).mod,
.{ .decl = decl_index },
self.decl_table.getPtr(decl_index).?,
(try self.exported_decls.getOrPut(gpa, decl_index)).value_ptr,
.nav => |nav| .{
zcu.navFileScope(nav).mod,
.{ .nav = nav },
self.navs.getPtr(nav).?,
(try self.exported_navs.getOrPut(gpa, nav)).value_ptr,
},
.value => |value| .{
.uav => |uav| .{
zcu.root_mod,
.{ .anon = value },
self.anon_decls.getPtr(value).?,
(try self.exported_values.getOrPut(gpa, value)).value_ptr,
.{ .uav = uav },
self.uavs.getPtr(uav).?,
(try self.exported_uavs.getOrPut(gpa, uav)).value_ptr,
},
};
const ctype_pool = &decl_block.ctype_pool;
@ -880,12 +862,12 @@ pub fn updateExports(
.fwd_decl = fwd_decl.toManaged(gpa),
.ctype_pool = decl_block.ctype_pool,
.scratch = .{},
.anon_decl_deps = .{},
.aligned_anon_decls = .{},
.uav_deps = .{},
.aligned_uavs = .{},
};
defer {
assert(dg.anon_decl_deps.count() == 0);
assert(dg.aligned_anon_decls.count() == 0);
assert(dg.uav_deps.count() == 0);
assert(dg.aligned_uavs.count() == 0);
fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
ctype_pool.* = dg.ctype_pool.move();
ctype_pool.freeUnusedCapacity(gpa);
@ -901,7 +883,7 @@ pub fn deleteExport(
_: InternPool.NullTerminatedString,
) void {
switch (exported) {
.decl_index => |decl_index| _ = self.exported_decls.swapRemove(decl_index),
.value => |value| _ = self.exported_values.swapRemove(value),
.nav => |nav| _ = self.exported_navs.swapRemove(nav),
.uav => |uav| _ = self.exported_uavs.swapRemove(uav),
}
}

View File

@ -65,8 +65,8 @@ imports_count_dirty: bool = true,
/// Table of tracked LazySymbols.
lazy_syms: LazySymbolTable = .{},
/// Table of tracked Decls.
decls: DeclTable = .{},
/// Table of tracked `Nav`s.
navs: NavTable = .{},
/// List of atoms that are either synthetic or map directly to the Zig source program.
atoms: std.ArrayListUnmanaged(Atom) = .{},
@ -74,27 +74,7 @@ atoms: std.ArrayListUnmanaged(Atom) = .{},
/// Table of atoms indexed by the symbol index.
atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
/// Table of unnamed constants associated with a parent `Decl`.
/// We store them here so that we can free the constants whenever the `Decl`
/// needs updating or is freed.
///
/// For example,
///
/// ```zig
/// const Foo = struct{
/// a: u8,
/// };
///
/// pub fn main() void {
/// var foo = Foo{ .a = 1 };
/// _ = foo;
/// }
/// ```
///
/// value assigned to label `foo` is an unnamed constant belonging/associated
/// with `Decl` `main`, and lives as long as that `Decl`.
unnamed_const_atoms: UnnamedConstTable = .{},
anon_decls: AnonDeclTable = .{},
uavs: UavTable = .{},
/// A table of relocations indexed by the owning them `Atom`.
/// Note that once we refactor `Atom`'s lifetime and ownership rules,
@ -120,11 +100,10 @@ const HotUpdateState = struct {
loaded_base_address: ?std.os.windows.HMODULE = null,
};
const DeclTable = std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata);
const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);
const UavTable = std.AutoHashMapUnmanaged(InternPool.Index, AvMetadata);
const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, std.ArrayListUnmanaged(Atom.Index));
const default_file_alignment: u16 = 0x200;
const default_size_of_stack_reserve: u32 = 0x1000000;
@ -155,7 +134,7 @@ const Section = struct {
free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
};
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.OptionalDeclIndex, LazySymbolMetadata);
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);
const LazySymbolMetadata = struct {
const State = enum { unused, pending_flush, flushed };
@ -165,17 +144,17 @@ const LazySymbolMetadata = struct {
rdata_state: State = .unused,
};
const DeclMetadata = struct {
const AvMetadata = struct {
atom: Atom.Index,
section: u16,
/// A list of all exports aliases of this Decl.
exports: std.ArrayListUnmanaged(u32) = .{},
fn deinit(m: *DeclMetadata, allocator: Allocator) void {
fn deinit(m: *AvMetadata, allocator: Allocator) void {
m.exports.deinit(allocator);
}
fn getExport(m: DeclMetadata, coff_file: *const Coff, name: []const u8) ?u32 {
fn getExport(m: AvMetadata, coff_file: *const Coff, name: []const u8) ?u32 {
for (m.exports.items) |exp| {
if (mem.eql(u8, name, coff_file.getSymbolName(.{
.sym_index = exp,
@ -185,7 +164,7 @@ const DeclMetadata = struct {
return null;
}
fn getExportPtr(m: *DeclMetadata, coff_file: *Coff, name: []const u8) ?*u32 {
fn getExportPtr(m: *AvMetadata, coff_file: *Coff, name: []const u8) ?*u32 {
for (m.exports.items) |*exp| {
if (mem.eql(u8, name, coff_file.getSymbolName(.{
.sym_index = exp.*,
@ -486,24 +465,19 @@ pub fn deinit(self: *Coff) void {
self.lazy_syms.deinit(gpa);
for (self.decls.values()) |*metadata| {
for (self.navs.values()) |*metadata| {
metadata.deinit(gpa);
}
self.decls.deinit(gpa);
self.navs.deinit(gpa);
self.atom_by_index_table.deinit(gpa);
for (self.unnamed_const_atoms.values()) |*atoms| {
atoms.deinit(gpa);
}
self.unnamed_const_atoms.deinit(gpa);
{
var it = self.anon_decls.iterator();
var it = self.uavs.iterator();
while (it.next()) |entry| {
entry.value_ptr.exports.deinit(gpa);
}
self.anon_decls.deinit(gpa);
self.uavs.deinit(gpa);
}
for (self.relocs.values()) |*relocs| {
@ -1132,23 +1106,20 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,
const tracy = trace(@src());
defer tracy.end();
const mod = pt.zcu;
const func = mod.funcInfo(func_index);
const decl_index = func.owner_decl;
const decl = mod.declPtr(decl_index);
const zcu = pt.zcu;
const gpa = zcu.gpa;
const func = zcu.funcInfo(func_index);
const atom_index = try self.getOrCreateAtomForDecl(decl_index);
self.freeUnnamedConsts(decl_index);
const atom_index = try self.getOrCreateAtomForNav(func.owner_nav);
Atom.freeRelocations(self, atom_index);
const gpa = self.base.comp.gpa;
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
const res = try codegen.generateFunction(
&self.base,
pt,
decl.navSrcLoc(mod),
zcu.navSrcLoc(func.owner_nav),
func_index,
air,
liveness,
@ -1158,45 +1129,16 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
func.setAnalysisState(&mod.intern_pool, .codegen_failure);
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
try zcu.failed_codegen.put(zcu.gpa, func.owner_nav, em);
return;
},
};
try self.updateDeclCode(pt, decl_index, code, .FUNCTION);
try self.updateNavCode(pt, func.owner_nav, code, .FUNCTION);
// Exports will be updated by `Zcu.processExports` after the update.
}
pub fn lowerUnnamedConst(self: *Coff, pt: Zcu.PerThread, val: Value, decl_index: InternPool.DeclIndex) !u32 {
const mod = pt.zcu;
const gpa = mod.gpa;
const decl = mod.declPtr(decl_index);
const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
const unnamed_consts = gop.value_ptr;
const index = unnamed_consts.items.len;
const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{}_{d}", .{
decl.fqn.fmt(&mod.intern_pool), index,
});
defer gpa.free(sym_name);
const ty = val.typeOf(mod);
const atom_index = switch (try self.lowerConst(pt, sym_name, val, ty.abiAlignment(pt), self.rdata_section_index.?, decl.navSrcLoc(mod))) {
.ok => |atom_index| atom_index,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
log.err("{s}", .{em.msg});
return error.CodegenFail;
},
};
try unnamed_consts.append(gpa, atom_index);
return self.getAtom(atom_index).getSymbolIndex().?;
}
const LowerConstResult = union(enum) {
ok: Atom.Index,
fail: *Module.ErrorMsg,
@ -1246,57 +1188,62 @@ fn lowerConst(
return .{ .ok = atom_index };
}
pub fn updateDecl(
pub fn updateNav(
self: *Coff,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
) link.File.UpdateDeclError!void {
const mod = pt.zcu;
nav_index: InternPool.Nav.Index,
) link.File.UpdateNavError!void {
if (build_options.skip_non_native and builtin.object_format != .coff) {
@panic("Attempted to compile for object format that was disabled by build configuration");
}
if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(pt, decl_index);
if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index);
const tracy = trace(@src());
defer tracy.end();
const decl = mod.declPtr(decl_index);
const zcu = pt.zcu;
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
if (decl.val.getExternFunc(mod)) |_| {
return;
}
const init_val = switch (ip.indexToKey(nav.status.resolved.val)) {
.variable => |variable| variable.init,
.@"extern" => |@"extern"| {
if (ip.isFunctionType(nav.typeOf(ip))) return;
// TODO make this part of getGlobalSymbol
const name = nav.name.toSlice(ip);
const lib_name = @"extern".lib_name.toSlice(ip);
const global_index = try self.getGlobalSymbol(name, lib_name);
try self.need_got_table.put(gpa, global_index, {});
return;
},
else => nav.status.resolved.val,
};
const gpa = self.base.comp.gpa;
if (decl.isExtern(mod)) {
// TODO make this part of getGlobalSymbol
const variable = decl.getOwnedVariable(mod).?;
const name = decl.name.toSlice(&mod.intern_pool);
const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
const global_index = try self.getGlobalSymbol(name, lib_name);
try self.need_got_table.put(gpa, global_index, {});
return;
}
const atom_index = try self.getOrCreateAtomForDecl(decl_index);
const atom_index = try self.getOrCreateAtomForNav(nav_index);
Atom.freeRelocations(self, atom_index);
const atom = self.getAtom(atom_index);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
const res = try codegen.generateSymbol(&self.base, pt, decl.navSrcLoc(mod), decl_val, &code_buffer, .none, .{
.parent_atom_index = atom.getSymbolIndex().?,
});
const res = try codegen.generateSymbol(
&self.base,
pt,
zcu.navSrcLoc(nav_index),
Value.fromInterned(init_val),
&code_buffer,
.none,
.{ .parent_atom_index = atom.getSymbolIndex().? },
);
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
try zcu.failed_codegen.put(gpa, nav_index, em);
return;
},
};
try self.updateDeclCode(pt, decl_index, code, .NULL);
try self.updateNavCode(pt, nav_index, code, .NULL);
// Exports will be updated by `Zcu.processExports` after the update.
}
@ -1317,14 +1264,14 @@ fn updateLazySymbolAtom(
const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
@tagName(sym.kind),
sym.ty.fmt(pt),
Type.fromInterned(sym.ty).fmt(pt),
});
defer gpa.free(name);
const atom = self.getAtomPtr(atom_index);
const local_sym_index = atom.getSymbolIndex().?;
const src = sym.ty.srcLocOrNull(mod) orelse Module.LazySrcLoc.unneeded;
const src = Type.fromInterned(sym.ty).srcLocOrNull(mod) orelse Module.LazySrcLoc.unneeded;
const res = try codegen.generateLazySymbol(
&self.base,
pt,
@ -1362,52 +1309,55 @@ fn updateLazySymbolAtom(
try self.writeAtom(atom_index, code);
}
pub fn getOrCreateAtomForLazySymbol(self: *Coff, pt: Zcu.PerThread, sym: link.File.LazySymbol) !Atom.Index {
const gpa = self.base.comp.gpa;
const mod = self.base.comp.module.?;
const gop = try self.lazy_syms.getOrPut(gpa, sym.getDecl(mod));
pub fn getOrCreateAtomForLazySymbol(
self: *Coff,
pt: Zcu.PerThread,
lazy_sym: link.File.LazySymbol,
) !Atom.Index {
const gop = try self.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty);
errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
if (!gop.found_existing) gop.value_ptr.* = .{};
const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
.code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
.const_data => .{ .atom = &gop.value_ptr.rdata_atom, .state = &gop.value_ptr.rdata_state },
const atom_ptr, const state_ptr = switch (lazy_sym.kind) {
.code => .{ &gop.value_ptr.text_atom, &gop.value_ptr.text_state },
.const_data => .{ &gop.value_ptr.rdata_atom, &gop.value_ptr.rdata_state },
};
switch (metadata.state.*) {
.unused => metadata.atom.* = try self.createAtom(),
.pending_flush => return metadata.atom.*,
switch (state_ptr.*) {
.unused => atom_ptr.* = try self.createAtom(),
.pending_flush => return atom_ptr.*,
.flushed => {},
}
metadata.state.* = .pending_flush;
const atom = metadata.atom.*;
state_ptr.* = .pending_flush;
const atom = atom_ptr.*;
// anyerror needs to be deferred until flushModule
if (sym.getDecl(mod) != .none) try self.updateLazySymbolAtom(pt, sym, atom, switch (sym.kind) {
if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbolAtom(pt, lazy_sym, atom, switch (lazy_sym.kind) {
.code => self.text_section_index.?,
.const_data => self.rdata_section_index.?,
});
return atom;
}
pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: InternPool.DeclIndex) !Atom.Index {
pub fn getOrCreateAtomForNav(self: *Coff, nav_index: InternPool.Nav.Index) !Atom.Index {
const gpa = self.base.comp.gpa;
const gop = try self.decls.getOrPut(gpa, decl_index);
const gop = try self.navs.getOrPut(gpa, nav_index);
if (!gop.found_existing) {
gop.value_ptr.* = .{
.atom = try self.createAtom(),
.section = self.getDeclOutputSection(decl_index),
.section = self.getNavOutputSection(nav_index),
.exports = .{},
};
}
return gop.value_ptr.atom;
}
fn getDeclOutputSection(self: *Coff, decl_index: InternPool.DeclIndex) u16 {
const decl = self.base.comp.module.?.declPtr(decl_index);
const mod = self.base.comp.module.?;
const ty = decl.typeOf(mod);
const zig_ty = ty.zigTypeTag(mod);
const val = decl.val;
fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 {
const zcu = self.base.comp.module.?;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
const ty = Type.fromInterned(nav.typeOf(ip));
const zig_ty = ty.zigTypeTag(zcu);
const val = Value.fromInterned(nav.status.resolved.val);
const index: u16 = blk: {
if (val.isUndefDeep(mod)) {
if (val.isUndefDeep(zcu)) {
// TODO in release-fast and release-small, we should put undef in .bss
break :blk self.data_section_index.?;
}
@ -1416,7 +1366,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: InternPool.DeclIndex) u16 {
// TODO: what if this is a function pointer?
.Fn => break :blk self.text_section_index.?,
else => {
if (val.getVariable(mod)) |_| {
if (val.getVariable(zcu)) |_| {
break :blk self.data_section_index.?;
}
break :blk self.rdata_section_index.?;
@ -1426,31 +1376,41 @@ fn getDeclOutputSection(self: *Coff, decl_index: InternPool.DeclIndex) u16 {
return index;
}
fn updateDeclCode(self: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex, code: []u8, complex_type: coff.ComplexType) !void {
const mod = pt.zcu;
const decl = mod.declPtr(decl_index);
fn updateNavCode(
self: *Coff,
pt: Zcu.PerThread,
nav_index: InternPool.Nav.Index,
code: []u8,
complex_type: coff.ComplexType,
) !void {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
log.debug("updateDeclCode {}{*}", .{ decl.fqn.fmt(&mod.intern_pool), decl });
const required_alignment: u32 = @intCast(decl.getAlignment(pt).toByteUnits() orelse 0);
log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
const decl_metadata = self.decls.get(decl_index).?;
const atom_index = decl_metadata.atom;
const required_alignment = pt.navAlignment(nav_index).max(
target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result),
);
const nav_metadata = self.navs.get(nav_index).?;
const atom_index = nav_metadata.atom;
const atom = self.getAtom(atom_index);
const sym_index = atom.getSymbolIndex().?;
const sect_index = decl_metadata.section;
const sect_index = nav_metadata.section;
const code_len = @as(u32, @intCast(code.len));
if (atom.size != 0) {
const sym = atom.getSymbolPtr(self);
try self.setSymbolName(sym, decl.fqn.toSlice(&mod.intern_pool));
try self.setSymbolName(sym, nav.fqn.toSlice(ip));
sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1));
sym.type = .{ .complex_type = complex_type, .base_type = .NULL };
const capacity = atom.capacity(self);
const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);
const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
if (need_realloc) {
const vaddr = try self.growAtom(atom_index, code_len, required_alignment);
log.debug("growing {} from 0x{x} to 0x{x}", .{ decl.fqn.fmt(&mod.intern_pool), sym.value, vaddr });
const vaddr = try self.growAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr });
log.debug(" (required alignment 0x{x}", .{required_alignment});
if (vaddr != sym.value) {
@ -1466,13 +1426,13 @@ fn updateDeclCode(self: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclInd
self.getAtomPtr(atom_index).size = code_len;
} else {
const sym = atom.getSymbolPtr(self);
try self.setSymbolName(sym, decl.fqn.toSlice(&mod.intern_pool));
try self.setSymbolName(sym, nav.fqn.toSlice(ip));
sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1));
sym.type = .{ .complex_type = complex_type, .base_type = .NULL };
const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
errdefer self.freeAtom(atom_index);
log.debug("allocated atom for {} at 0x{x}", .{ decl.fqn.fmt(&mod.intern_pool), vaddr });
log.debug("allocated atom for {} at 0x{x}", .{ nav.fqn.fmt(ip), vaddr });
self.getAtomPtr(atom_index).size = code_len;
sym.value = vaddr;
@ -1482,28 +1442,15 @@ fn updateDeclCode(self: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclInd
try self.writeAtom(atom_index, code);
}
fn freeUnnamedConsts(self: *Coff, decl_index: InternPool.DeclIndex) void {
const gpa = self.base.comp.gpa;
const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
for (unnamed_consts.items) |atom_index| {
self.freeAtom(atom_index);
}
unnamed_consts.clearAndFree(gpa);
}
pub fn freeDecl(self: *Coff, decl_index: InternPool.DeclIndex) void {
if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
pub fn freeNav(self: *Coff, nav_index: InternPool.NavIndex) void {
if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav_index);
const gpa = self.base.comp.gpa;
const mod = self.base.comp.module.?;
const decl = mod.declPtr(decl_index);
log.debug("freeDecl 0x{x}", .{nav_index});
log.debug("freeDecl {*}", .{decl});
if (self.decls.fetchOrderedRemove(decl_index)) |const_kv| {
if (self.decls.fetchOrderedRemove(nav_index)) |const_kv| {
var kv = const_kv;
self.freeAtom(kv.value.atom);
self.freeUnnamedConsts(decl_index);
kv.value.exports.deinit(gpa);
}
}
@ -1528,20 +1475,21 @@ pub fn updateExports(
// detect the default subsystem.
for (export_indices) |export_idx| {
const exp = mod.all_exports.items[export_idx];
const exported_decl_index = switch (exp.exported) {
.decl_index => |i| i,
.value => continue,
const exported_nav_index = switch (exp.exported) {
.nav => |nav| nav,
.uav => continue,
};
const exported_decl = mod.declPtr(exported_decl_index);
if (exported_decl.getOwnedFunction(mod) == null) continue;
const winapi_cc = switch (target.cpu.arch) {
.x86 => std.builtin.CallingConvention.Stdcall,
else => std.builtin.CallingConvention.C,
const exported_nav = ip.getNav(exported_nav_index);
const exported_ty = exported_nav.typeOf(ip);
if (!ip.isFunctionType(exported_ty)) continue;
const winapi_cc: std.builtin.CallingConvention = switch (target.cpu.arch) {
.x86 => .Stdcall,
else => .C,
};
const decl_cc = exported_decl.typeOf(mod).fnCallingConvention(mod);
if (decl_cc == .C and exp.opts.name.eqlSlice("main", ip) and comp.config.link_libc) {
const exported_cc = Type.fromInterned(exported_ty).fnCallingConvention(mod);
if (exported_cc == .C and exp.opts.name.eqlSlice("main", ip) and comp.config.link_libc) {
mod.stage1_flags.have_c_main = true;
} else if (decl_cc == winapi_cc and target.os.tag == .windows) {
} else if (exported_cc == winapi_cc and target.os.tag == .windows) {
if (exp.opts.name.eqlSlice("WinMain", ip)) {
mod.stage1_flags.have_winmain = true;
} else if (exp.opts.name.eqlSlice("wWinMain", ip)) {
@ -1562,15 +1510,15 @@ pub fn updateExports(
const gpa = comp.gpa;
const metadata = switch (exported) {
.decl_index => |decl_index| blk: {
_ = try self.getOrCreateAtomForDecl(decl_index);
break :blk self.decls.getPtr(decl_index).?;
.nav => |nav| blk: {
_ = try self.getOrCreateAtomForNav(nav);
break :blk self.navs.getPtr(nav).?;
},
.value => |value| self.anon_decls.getPtr(value) orelse blk: {
.uav => |uav| self.uavs.getPtr(uav) orelse blk: {
const first_exp = mod.all_exports.items[export_indices[0]];
const res = try self.lowerAnonDecl(pt, value, .none, first_exp.src);
const res = try self.lowerUav(pt, uav, .none, first_exp.src);
switch (res) {
.ok => {},
.mcv => {},
.fail => |em| {
// TODO maybe it's enough to return an error here and let Module.processExportsInner
// handle the error?
@ -1579,7 +1527,7 @@ pub fn updateExports(
return;
},
}
break :blk self.anon_decls.getPtr(value).?;
break :blk self.uavs.getPtr(uav).?;
},
};
const atom_index = metadata.atom;
@ -1654,9 +1602,9 @@ pub fn deleteExport(
) void {
if (self.llvm_object) |_| return;
const metadata = switch (exported) {
.decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
.value => |value| self.anon_decls.getPtr(value) orelse return,
};
.nav => |nav| self.navs.getPtr(nav),
.uav => |uav| self.uavs.getPtr(uav),
} orelse return;
const mod = self.base.comp.module.?;
const name_slice = name.toSlice(&mod.intern_pool);
const sym_index = metadata.getExportPtr(self, name_slice) orelse return;
@ -1748,7 +1696,7 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
// anyerror needs to wait for everything to be flushed.
if (metadata.text_state != .unused) self.updateLazySymbolAtom(
pt,
link.File.LazySymbol.initDecl(.code, null, pt.zcu),
.{ .kind = .code, .ty = .anyerror_type },
metadata.text_atom,
self.text_section_index.?,
) catch |err| return switch (err) {
@ -1757,7 +1705,7 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
};
if (metadata.rdata_state != .unused) self.updateLazySymbolAtom(
pt,
link.File.LazySymbol.initDecl(.const_data, null, pt.zcu),
.{ .kind = .const_data, .ty = .anyerror_type },
metadata.rdata_atom,
self.rdata_section_index.?,
) catch |err| return switch (err) {
@ -1856,22 +1804,20 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
assert(!self.imports_count_dirty);
}
pub fn getDeclVAddr(self: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex, reloc_info: link.File.RelocInfo) !u64 {
pub fn getNavVAddr(
self: *Coff,
pt: Zcu.PerThread,
nav_index: InternPool.Nav.Index,
reloc_info: link.File.RelocInfo,
) !u64 {
assert(self.llvm_object == null);
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const decl = zcu.declPtr(decl_index);
log.debug("getDeclVAddr {}({d})", .{ decl.fqn.fmt(ip), decl_index });
const sym_index = if (decl.isExtern(zcu)) blk: {
const name = decl.name.toSlice(ip);
const lib_name = if (decl.getOwnedExternFunc(zcu)) |ext_fn|
ext_fn.lib_name.toSlice(ip)
else
decl.getOwnedVariable(zcu).?.lib_name.toSlice(ip);
break :blk try self.getGlobalSymbol(name, lib_name);
} else blk: {
const this_atom_index = try self.getOrCreateAtomForDecl(decl_index);
break :blk self.getAtom(this_atom_index).getSymbolIndex().?;
const nav = ip.getNav(nav_index);
log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
.@"extern" => |@"extern"| try self.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)),
else => self.getAtom(try self.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?,
};
const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
@ -1888,36 +1834,36 @@ pub fn getDeclVAddr(self: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclI
return 0;
}
pub fn lowerAnonDecl(
pub fn lowerUav(
self: *Coff,
pt: Zcu.PerThread,
decl_val: InternPool.Index,
uav: InternPool.Index,
explicit_alignment: InternPool.Alignment,
src_loc: Module.LazySrcLoc,
) !codegen.Result {
const gpa = self.base.comp.gpa;
const mod = self.base.comp.module.?;
const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
const decl_alignment = switch (explicit_alignment) {
.none => ty.abiAlignment(pt),
) !codegen.GenResult {
const zcu = pt.zcu;
const gpa = zcu.gpa;
const val = Value.fromInterned(uav);
const uav_alignment = switch (explicit_alignment) {
.none => val.typeOf(zcu).abiAlignment(pt),
else => explicit_alignment,
};
if (self.anon_decls.get(decl_val)) |metadata| {
const existing_addr = self.getAtom(metadata.atom).getSymbol(self).value;
if (decl_alignment.check(existing_addr))
return .ok;
if (self.uavs.get(uav)) |metadata| {
const atom = self.getAtom(metadata.atom);
const existing_addr = atom.getSymbol(self).value;
if (uav_alignment.check(existing_addr))
return .{ .mcv = .{ .load_direct = atom.getSymbolIndex().? } };
}
const val = Value.fromInterned(decl_val);
var name_buf: [32]u8 = undefined;
const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
@intFromEnum(decl_val),
@intFromEnum(uav),
}) catch unreachable;
const res = self.lowerConst(
pt,
name,
val,
decl_alignment,
uav_alignment,
self.rdata_section_index.?,
src_loc,
) catch |err| switch (err) {
@ -1933,14 +1879,23 @@ pub fn lowerAnonDecl(
.ok => |atom_index| atom_index,
.fail => |em| return .{ .fail = em },
};
try self.anon_decls.put(gpa, decl_val, .{ .atom = atom_index, .section = self.rdata_section_index.? });
return .ok;
try self.uavs.put(gpa, uav, .{
.atom = atom_index,
.section = self.rdata_section_index.?,
});
return .{ .mcv = .{
.load_direct = self.getAtom(atom_index).getSymbolIndex().?,
} };
}
pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
pub fn getUavVAddr(
self: *Coff,
uav: InternPool.Index,
reloc_info: link.File.RelocInfo,
) !u64 {
assert(self.llvm_object == null);
const this_atom_index = self.anon_decls.get(decl_val).?.atom;
const this_atom_index = self.uavs.get(uav).?.atom;
const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
@ -2760,6 +2715,7 @@ const Allocator = std.mem.Allocator;
const codegen = @import("../codegen.zig");
const link = @import("../link.zig");
const lld = @import("Coff/lld.zig");
const target_util = @import("../target.zig");
const trace = @import("../tracy.zig").trace;
const Air = @import("../Air.zig");
@ -2781,6 +2737,4 @@ const Value = @import("../Value.zig");
const AnalUnit = InternPool.AnalUnit;
const dev = @import("../dev.zig");
pub const base_tag: link.File.Tag = .coff;
const msdos_stub = @embedFile("msdos-stub.bin");

File diff suppressed because it is too large Load Diff

View File

@ -478,24 +478,24 @@ pub fn deinit(self: *Elf) void {
self.comdat_group_sections.deinit(gpa);
}
pub fn getDeclVAddr(self: *Elf, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex, reloc_info: link.File.RelocInfo) !u64 {
pub fn getNavVAddr(self: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 {
assert(self.llvm_object == null);
return self.zigObjectPtr().?.getDeclVAddr(self, pt, decl_index, reloc_info);
return self.zigObjectPtr().?.getNavVAddr(self, pt, nav_index, reloc_info);
}
pub fn lowerAnonDecl(
pub fn lowerUav(
self: *Elf,
pt: Zcu.PerThread,
decl_val: InternPool.Index,
uav: InternPool.Index,
explicit_alignment: InternPool.Alignment,
src_loc: Zcu.LazySrcLoc,
) !codegen.Result {
return self.zigObjectPtr().?.lowerAnonDecl(self, pt, decl_val, explicit_alignment, src_loc);
) !codegen.GenResult {
return self.zigObjectPtr().?.lowerUav(self, pt, uav, explicit_alignment, src_loc);
}
pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
pub fn getUavVAddr(self: *Elf, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
assert(self.llvm_object == null);
return self.zigObjectPtr().?.getAnonDeclVAddr(self, decl_val, reloc_info);
return self.zigObjectPtr().?.getUavVAddr(self, uav, reloc_info);
}
/// Returns end pos of collision, if any.
@ -2913,9 +2913,9 @@ pub fn writeElfHeader(self: *Elf) !void {
try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
}
pub fn freeDecl(self: *Elf, decl_index: InternPool.DeclIndex) void {
if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
return self.zigObjectPtr().?.freeDecl(self, decl_index);
pub fn freeNav(self: *Elf, nav: InternPool.Nav.Index) void {
if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav);
return self.zigObjectPtr().?.freeNav(self, nav);
}
pub fn updateFunc(self: *Elf, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
@ -2926,20 +2926,16 @@ pub fn updateFunc(self: *Elf, pt: Zcu.PerThread, func_index: InternPool.Index, a
return self.zigObjectPtr().?.updateFunc(self, pt, func_index, air, liveness);
}
pub fn updateDecl(
pub fn updateNav(
self: *Elf,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
) link.File.UpdateDeclError!void {
nav: InternPool.Nav.Index,
) link.File.UpdateNavError!void {
if (build_options.skip_non_native and builtin.object_format != .elf) {
@panic("Attempted to compile for object format that was disabled by build configuration");
}
if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(pt, decl_index);
return self.zigObjectPtr().?.updateDecl(self, pt, decl_index);
}
pub fn lowerUnnamedConst(self: *Elf, pt: Zcu.PerThread, val: Value, decl_index: InternPool.DeclIndex) !u32 {
return self.zigObjectPtr().?.lowerUnnamedConst(self, pt, val, decl_index);
if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav);
return self.zigObjectPtr().?.updateNav(self, pt, nav);
}
pub fn updateExports(
@ -2955,9 +2951,9 @@ pub fn updateExports(
return self.zigObjectPtr().?.updateExports(self, pt, exported, export_indices);
}
pub fn updateDeclLineNumber(self: *Elf, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
pub fn updateNavLineNumber(self: *Elf, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {
if (self.llvm_object) |_| return;
return self.zigObjectPtr().?.updateDeclLineNumber(pt, decl_index);
return self.zigObjectPtr().?.updateNavLineNumber(pt, nav);
}
pub fn deleteExport(

View File

@ -32,35 +32,14 @@ dwarf: ?Dwarf = null,
/// Table of tracked LazySymbols.
lazy_syms: LazySymbolTable = .{},
/// Table of tracked Decls.
decls: DeclTable = .{},
/// Table of tracked `Nav`s.
navs: NavTable = .{},
/// TLS variables indexed by Atom.Index.
tls_variables: TlsTable = .{},
/// Table of unnamed constants associated with a parent `Decl`.
/// We store them here so that we can free the constants whenever the `Decl`
/// needs updating or is freed.
///
/// For example,
///
/// ```zig
/// const Foo = struct{
/// a: u8,
/// };
///
/// pub fn main() void {
/// var foo = Foo{ .a = 1 };
/// _ = foo;
/// }
/// ```
///
/// value assigned to label `foo` is an unnamed constant belonging/associated
/// with `Decl` `main`, and lives as long as that `Decl`.
unnamed_consts: UnnamedConstTable = .{},
/// Table of tracked AnonDecls.
anon_decls: AnonDeclTable = .{},
/// Table of tracked `Uav`s.
uavs: UavTable = .{},
debug_strtab_dirty: bool = false,
debug_abbrev_section_dirty: bool = false,
@ -124,29 +103,21 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
self.relocs.deinit(allocator);
{
var it = self.decls.iterator();
var it = self.navs.iterator();
while (it.next()) |entry| {
entry.value_ptr.exports.deinit(allocator);
}
self.decls.deinit(allocator);
self.navs.deinit(allocator);
}
self.lazy_syms.deinit(allocator);
{
var it = self.unnamed_consts.valueIterator();
while (it.next()) |syms| {
syms.deinit(allocator);
}
self.unnamed_consts.deinit(allocator);
}
{
var it = self.anon_decls.iterator();
var it = self.uavs.iterator();
while (it.next()) |entry| {
entry.value_ptr.exports.deinit(allocator);
}
self.anon_decls.deinit(allocator);
self.uavs.deinit(allocator);
}
for (self.tls_variables.values()) |*tlv| {
@ -161,7 +132,7 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
// Handle any lazy symbols that were emitted by incremental compilation.
if (self.lazy_syms.getPtr(.none)) |metadata| {
if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
// Most lazy symbols can be updated on first use, but
@ -169,7 +140,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
if (metadata.text_state != .unused) self.updateLazySymbol(
elf_file,
pt,
link.File.LazySymbol.initDecl(.code, null, pt.zcu),
.{ .kind = .code, .ty = .anyerror_type },
metadata.text_symbol_index,
) catch |err| return switch (err) {
error.CodegenFail => error.FlushFailure,
@ -178,7 +149,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
if (metadata.rodata_state != .unused) self.updateLazySymbol(
elf_file,
pt,
link.File.LazySymbol.initDecl(.const_data, null, pt.zcu),
.{ .kind = .const_data, .ty = .anyerror_type },
metadata.rodata_symbol_index,
) catch |err| return switch (err) {
error.CodegenFail => error.FlushFailure,
@ -661,25 +632,25 @@ pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8
return code;
}
pub fn getDeclVAddr(
pub fn getNavVAddr(
self: *ZigObject,
elf_file: *Elf,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
reloc_info: link.File.RelocInfo,
) !u64 {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const decl = zcu.declPtr(decl_index);
log.debug("getDeclVAddr {}({d})", .{ decl.fqn.fmt(ip), decl_index });
const this_sym_index = if (decl.isExtern(zcu)) blk: {
const name = decl.name.toSlice(ip);
const lib_name = if (decl.getOwnedExternFunc(zcu)) |ext_fn|
ext_fn.lib_name.toSlice(ip)
else
decl.getOwnedVariable(zcu).?.lib_name.toSlice(ip);
break :blk try self.getGlobalSymbol(elf_file, name, lib_name);
} else try self.getOrCreateMetadataForDecl(elf_file, decl_index);
const nav = ip.getNav(nav_index);
log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
const this_sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
.@"extern" => |@"extern"| try self.getGlobalSymbol(
elf_file,
nav.name.toSlice(ip),
@"extern".lib_name.toSlice(ip),
),
else => try self.getOrCreateMetadataForNav(elf_file, nav_index),
};
const this_sym = self.symbol(this_sym_index);
const vaddr = this_sym.address(.{}, elf_file);
const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
@ -692,13 +663,13 @@ pub fn getDeclVAddr(
return @intCast(vaddr);
}
pub fn getAnonDeclVAddr(
pub fn getUavVAddr(
self: *ZigObject,
elf_file: *Elf,
decl_val: InternPool.Index,
uav: InternPool.Index,
reloc_info: link.File.RelocInfo,
) !u64 {
const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
const sym_index = self.uavs.get(uav).?.symbol_index;
const sym = self.symbol(sym_index);
const vaddr = sym.address(.{}, elf_file);
const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
@ -711,43 +682,43 @@ pub fn getAnonDeclVAddr(
return @intCast(vaddr);
}
pub fn lowerAnonDecl(
pub fn lowerUav(
self: *ZigObject,
elf_file: *Elf,
pt: Zcu.PerThread,
decl_val: InternPool.Index,
uav: InternPool.Index,
explicit_alignment: InternPool.Alignment,
src_loc: Module.LazySrcLoc,
) !codegen.Result {
const gpa = elf_file.base.comp.gpa;
const mod = elf_file.base.comp.module.?;
const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
const decl_alignment = switch (explicit_alignment) {
.none => ty.abiAlignment(pt),
src_loc: Zcu.LazySrcLoc,
) !codegen.GenResult {
const zcu = pt.zcu;
const gpa = zcu.gpa;
const val = Value.fromInterned(uav);
const uav_alignment = switch (explicit_alignment) {
.none => val.typeOf(zcu).abiAlignment(pt),
else => explicit_alignment,
};
if (self.anon_decls.get(decl_val)) |metadata| {
const existing_alignment = self.symbol(metadata.symbol_index).atom(elf_file).?.alignment;
if (decl_alignment.order(existing_alignment).compare(.lte))
return .ok;
if (self.uavs.get(uav)) |metadata| {
const sym = self.symbol(metadata.symbol_index);
const existing_alignment = sym.atom(elf_file).?.alignment;
if (uav_alignment.order(existing_alignment).compare(.lte))
return .{ .mcv = .{ .load_symbol = metadata.symbol_index } };
}
const val = Value.fromInterned(decl_val);
var name_buf: [32]u8 = undefined;
const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
@intFromEnum(decl_val),
@intFromEnum(uav),
}) catch unreachable;
const res = self.lowerConst(
elf_file,
pt,
name,
val,
decl_alignment,
uav_alignment,
elf_file.zig_data_rel_ro_section_index.?,
src_loc,
) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
else => |e| return .{ .fail = try Module.ErrorMsg.create(
else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
gpa,
src_loc,
"unable to lower constant value: {s}",
@ -758,8 +729,8 @@ pub fn lowerAnonDecl(
.ok => |sym_index| sym_index,
.fail => |em| return .{ .fail = em },
};
try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
return .ok;
try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index });
return .{ .mcv = .{ .load_symbol = sym_index } };
}
pub fn getOrCreateMetadataForLazySymbol(
@ -768,51 +739,32 @@ pub fn getOrCreateMetadataForLazySymbol(
pt: Zcu.PerThread,
lazy_sym: link.File.LazySymbol,
) !Symbol.Index {
const mod = pt.zcu;
const gpa = mod.gpa;
const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod));
const gop = try self.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty);
errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
if (!gop.found_existing) gop.value_ptr.* = .{};
const metadata: struct {
symbol_index: *Symbol.Index,
state: *LazySymbolMetadata.State,
} = switch (lazy_sym.kind) {
.code => .{
.symbol_index = &gop.value_ptr.text_symbol_index,
.state = &gop.value_ptr.text_state,
},
.const_data => .{
.symbol_index = &gop.value_ptr.rodata_symbol_index,
.state = &gop.value_ptr.rodata_state,
},
const symbol_index_ptr, const state_ptr = switch (lazy_sym.kind) {
.code => .{ &gop.value_ptr.text_symbol_index, &gop.value_ptr.text_state },
.const_data => .{ &gop.value_ptr.rodata_symbol_index, &gop.value_ptr.rodata_state },
};
switch (metadata.state.*) {
switch (state_ptr.*) {
.unused => {
const gpa = elf_file.base.comp.gpa;
const symbol_index = try self.newSymbolWithAtom(gpa, 0);
const sym = self.symbol(symbol_index);
sym.flags.needs_zig_got = true;
metadata.symbol_index.* = symbol_index;
symbol_index_ptr.* = symbol_index;
},
.pending_flush => return metadata.symbol_index.*,
.pending_flush => return symbol_index_ptr.*,
.flushed => {},
}
metadata.state.* = .pending_flush;
const symbol_index = metadata.symbol_index.*;
state_ptr.* = .pending_flush;
const symbol_index = symbol_index_ptr.*;
// anyerror needs to be deferred until flushModule
if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(elf_file, pt, lazy_sym, symbol_index);
if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbol(elf_file, pt, lazy_sym, symbol_index);
return symbol_index;
}
fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclIndex) void {
const gpa = elf_file.base.comp.gpa;
const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
for (unnamed_consts.items) |sym_index| {
self.freeDeclMetadata(elf_file, sym_index);
}
unnamed_consts.clearAndFree(gpa);
}
fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {
fn freeNavMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {
const sym = self.symbol(sym_index);
sym.atom(elf_file).?.free(elf_file);
log.debug("adding %{d} to local symbols free list", .{sym_index});
@ -820,38 +772,37 @@ fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) v
// TODO free GOT entry here
}
pub fn freeDecl(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclIndex) void {
pub fn freeNav(self: *ZigObject, elf_file: *Elf, nav_index: InternPool.Nav.Index) void {
const gpa = elf_file.base.comp.gpa;
log.debug("freeDecl ({d})", .{decl_index});
log.debug("freeNav ({d})", .{nav_index});
if (self.decls.fetchRemove(decl_index)) |const_kv| {
if (self.navs.fetchRemove(nav_index)) |const_kv| {
var kv = const_kv;
const sym_index = kv.value.symbol_index;
self.freeDeclMetadata(elf_file, sym_index);
self.freeUnnamedConsts(elf_file, decl_index);
self.freeNavMetadata(elf_file, sym_index);
kv.value.exports.deinit(gpa);
}
if (self.dwarf) |*dw| {
dw.freeDecl(decl_index);
dw.freeNav(nav_index);
}
}
pub fn getOrCreateMetadataForDecl(
pub fn getOrCreateMetadataForNav(
self: *ZigObject,
elf_file: *Elf,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
) !Symbol.Index {
const gpa = elf_file.base.comp.gpa;
const gop = try self.decls.getOrPut(gpa, decl_index);
const gop = try self.navs.getOrPut(gpa, nav_index);
if (!gop.found_existing) {
const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
const symbol_index = try self.newSymbolWithAtom(gpa, 0);
const mod = elf_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
const zcu = elf_file.base.comp.module.?;
const nav_val = Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.resolved.val);
const sym = self.symbol(symbol_index);
if (decl.getOwnedVariable(mod)) |variable| {
if (nav_val.getVariable(zcu)) |variable| {
if (variable.is_threadlocal and any_non_single_threaded) {
sym.flags.is_tls = true;
}
@ -864,89 +815,81 @@ pub fn getOrCreateMetadataForDecl(
return gop.value_ptr.symbol_index;
}
fn getDeclShdrIndex(
fn getNavShdrIndex(
self: *ZigObject,
elf_file: *Elf,
decl: *const Module.Decl,
zcu: *Zcu,
nav_index: InternPool.Nav.Index,
code: []const u8,
) error{OutOfMemory}!u32 {
_ = self;
const mod = elf_file.base.comp.module.?;
const ip = &zcu.intern_pool;
const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
const shdr_index = switch (decl.typeOf(mod).zigTypeTag(mod)) {
.Fn => elf_file.zig_text_section_index.?,
else => blk: {
if (decl.getOwnedVariable(mod)) |variable| {
if (variable.is_threadlocal and any_non_single_threaded) {
const is_all_zeroes = for (code) |byte| {
if (byte != 0) break false;
} else true;
if (is_all_zeroes) break :blk elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{
.type = elf.SHT_NOBITS,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
.name = try elf_file.insertShString(".tbss"),
.offset = std.math.maxInt(u64),
});
break :blk elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{
.type = elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
.name = try elf_file.insertShString(".tdata"),
.offset = std.math.maxInt(u64),
});
}
if (variable.is_const) break :blk elf_file.zig_data_rel_ro_section_index.?;
if (Value.fromInterned(variable.init).isUndefDeep(mod)) {
// TODO: get the optimize_mode from the Module that owns the decl instead
// of using the root module here.
break :blk switch (elf_file.base.comp.root_mod.optimize_mode) {
.Debug, .ReleaseSafe => elf_file.zig_data_section_index.?,
.ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?,
};
}
// TODO I blatantly copied the logic from the Wasm linker, but is there a less
// intrusive check for all zeroes than this?
const is_all_zeroes = for (code) |byte| {
if (byte != 0) break false;
} else true;
if (is_all_zeroes) break :blk elf_file.zig_bss_section_index.?;
break :blk elf_file.zig_data_section_index.?;
}
break :blk elf_file.zig_data_rel_ro_section_index.?;
},
const nav_val = zcu.navValue(nav_index);
if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return elf_file.zig_text_section_index.?;
const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
.variable => |variable| .{ false, variable.is_threadlocal, variable.init },
.@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
else => .{ true, false, nav_val.toIntern() },
};
return shdr_index;
if (any_non_single_threaded and is_threadlocal) {
for (code) |byte| {
if (byte != 0) break;
} else return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{
.type = elf.SHT_NOBITS,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
.name = try elf_file.insertShString(".tbss"),
.offset = std.math.maxInt(u64),
});
return elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{
.type = elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
.name = try elf_file.insertShString(".tdata"),
.offset = std.math.maxInt(u64),
});
}
if (is_const) return elf_file.zig_data_rel_ro_section_index.?;
if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu))
return switch (zcu.navFileScope(nav_index).mod.optimize_mode) {
.Debug, .ReleaseSafe => elf_file.zig_data_section_index.?,
.ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?,
};
for (code) |byte| {
if (byte != 0) break;
} else return elf_file.zig_bss_section_index.?;
return elf_file.zig_data_section_index.?;
}
fn updateDeclCode(
fn updateNavCode(
self: *ZigObject,
elf_file: *Elf,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
sym_index: Symbol.Index,
shdr_index: u32,
code: []const u8,
stt_bits: u8,
) !void {
const gpa = elf_file.base.comp.gpa;
const mod = pt.zcu;
const ip = &mod.intern_pool;
const decl = mod.declPtr(decl_index);
const zcu = pt.zcu;
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
log.debug("updateDeclCode {}({d})", .{ decl.fqn.fmt(ip), decl_index });
log.debug("updateNavCode {}({d})", .{ nav.fqn.fmt(ip), nav_index });
const required_alignment = decl.getAlignment(pt).max(
target_util.minFunctionAlignment(mod.getTarget()),
const required_alignment = pt.navAlignment(nav_index).max(
target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result),
);
const sym = self.symbol(sym_index);
const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
const atom_ptr = sym.atom(elf_file).?;
const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
const name_offset = try self.strtab.insert(gpa, nav.fqn.toSlice(ip));
atom_ptr.alive = true;
atom_ptr.name_offset = name_offset;
atom_ptr.output_section_index = shdr_index;
sym.name_offset = name_offset;
esym.st_name = name_offset;
esym.st_info |= stt_bits;
@ -962,7 +905,7 @@ fn updateDeclCode(
const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value));
if (need_realloc) {
try atom_ptr.grow(elf_file);
log.debug("growing {} from 0x{x} to 0x{x}", .{ decl.fqn.fmt(ip), old_vaddr, atom_ptr.value });
log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value });
if (old_vaddr != atom_ptr.value) {
sym.value = 0;
esym.st_value = 0;
@ -979,7 +922,7 @@ fn updateDeclCode(
}
} else {
try atom_ptr.allocate(elf_file);
errdefer self.freeDeclMetadata(elf_file, sym_index);
errdefer self.freeNavMetadata(elf_file, sym_index);
sym.value = 0;
sym.flags.needs_zig_got = true;
@ -1023,24 +966,24 @@ fn updateTlv(
self: *ZigObject,
elf_file: *Elf,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
sym_index: Symbol.Index,
shndx: u32,
code: []const u8,
) !void {
const mod = pt.zcu;
const ip = &mod.intern_pool;
const gpa = mod.gpa;
const decl = mod.declPtr(decl_index);
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const gpa = zcu.gpa;
const nav = ip.getNav(nav_index);
log.debug("updateTlv {}({d})", .{ decl.fqn.fmt(ip), decl_index });
log.debug("updateTlv {}({d})", .{ nav.fqn.fmt(ip), nav_index });
const required_alignment = decl.getAlignment(pt);
const required_alignment = pt.navAlignment(nav_index);
const sym = self.symbol(sym_index);
const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
const atom_ptr = sym.atom(elf_file).?;
const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
const name_offset = try self.strtab.insert(gpa, nav.fqn.toSlice(ip));
sym.value = 0;
sym.name_offset = name_offset;
@ -1049,6 +992,7 @@ fn updateTlv(
atom_ptr.alive = true;
atom_ptr.name_offset = name_offset;
sym.name_offset = name_offset;
esym.st_value = 0;
esym.st_name = name_offset;
esym.st_info = elf.STT_TLS;
@ -1086,53 +1030,49 @@ pub fn updateFunc(
const tracy = trace(@src());
defer tracy.end();
const mod = pt.zcu;
const ip = &mod.intern_pool;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const gpa = elf_file.base.comp.gpa;
const func = mod.funcInfo(func_index);
const decl_index = func.owner_decl;
const decl = mod.declPtr(decl_index);
const func = zcu.funcInfo(func_index);
log.debug("updateFunc {}({d})", .{ decl.fqn.fmt(ip), decl_index });
log.debug("updateFunc {}({d})", .{ ip.getNav(func.owner_nav).fqn.fmt(ip), func.owner_nav });
const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
self.freeUnnamedConsts(elf_file, decl_index);
const sym_index = try self.getOrCreateMetadataForNav(elf_file, func.owner_nav);
self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(pt, decl_index) else null;
defer if (decl_state) |*ds| ds.deinit();
var dwarf_state = if (self.dwarf) |*dw| try dw.initNavState(pt, func.owner_nav) else null;
defer if (dwarf_state) |*ds| ds.deinit();
const res = try codegen.generateFunction(
&elf_file.base,
pt,
decl.navSrcLoc(mod),
zcu.navSrcLoc(func.owner_nav),
func_index,
air,
liveness,
&code_buffer,
if (decl_state) |*ds| .{ .dwarf = ds } else .none,
if (dwarf_state) |*ds| .{ .dwarf = ds } else .none,
);
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
func.setAnalysisState(&mod.intern_pool, .codegen_failure);
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
try zcu.failed_codegen.put(gpa, func.owner_nav, em);
return;
},
};
const shndx = try self.getDeclShdrIndex(elf_file, decl, code);
try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_FUNC);
const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, code);
try self.updateNavCode(elf_file, pt, func.owner_nav, sym_index, shndx, code, elf.STT_FUNC);
if (decl_state) |*ds| {
if (dwarf_state) |*ds| {
const sym = self.symbol(sym_index);
try self.dwarf.?.commitDeclState(
try self.dwarf.?.commitNavState(
pt,
decl_index,
func.owner_nav,
@intCast(sym.address(.{}, elf_file)),
sym.atom(elf_file).?.size,
ds,
@ -1142,78 +1082,80 @@ pub fn updateFunc(
// Exports will be updated by `Zcu.processExports` after the update.
}
pub fn updateDecl(
pub fn updateNav(
self: *ZigObject,
elf_file: *Elf,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
) link.File.UpdateDeclError!void {
nav_index: InternPool.Nav.Index,
) link.File.UpdateNavError!void {
const tracy = trace(@src());
defer tracy.end();
const mod = pt.zcu;
const ip = &mod.intern_pool;
const decl = mod.declPtr(decl_index);
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
log.debug("updateDecl {}({d})", .{ decl.fqn.fmt(ip), decl_index });
log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index });
if (decl.val.getExternFunc(mod)) |_| return;
if (decl.isExtern(mod)) {
// Extern variable gets a .got entry only.
const variable = decl.getOwnedVariable(mod).?;
const name = decl.name.toSlice(&mod.intern_pool);
const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
const sym_index = try self.getGlobalSymbol(elf_file, name, lib_name);
self.symbol(sym_index).flags.needs_got = true;
return;
}
const nav_val = zcu.navValue(nav_index);
const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
.variable => |variable| Value.fromInterned(variable.init),
.@"extern" => |@"extern"| {
if (ip.isFunctionType(@"extern".ty)) return;
// Extern variable gets a .got entry only.
const sym_index = try self.getGlobalSymbol(
elf_file,
nav.name.toSlice(ip),
@"extern".lib_name.toSlice(ip),
);
self.symbol(sym_index).flags.needs_got = true;
return;
},
else => nav_val,
};
const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
const sym_index = try self.getOrCreateMetadataForNav(elf_file, nav_index);
self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
const gpa = elf_file.base.comp.gpa;
var code_buffer = std.ArrayList(u8).init(gpa);
var code_buffer = std.ArrayList(u8).init(zcu.gpa);
defer code_buffer.deinit();
var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(pt, decl_index) else null;
defer if (decl_state) |*ds| ds.deinit();
var nav_state: ?Dwarf.NavState = if (self.dwarf) |*dw| try dw.initNavState(pt, nav_index) else null;
defer if (nav_state) |*ns| ns.deinit();
// TODO implement .debug_info for global variables
const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
const res = if (decl_state) |*ds|
try codegen.generateSymbol(&elf_file.base, pt, decl.navSrcLoc(mod), decl_val, &code_buffer, .{
.dwarf = ds,
}, .{
.parent_atom_index = sym_index,
})
else
try codegen.generateSymbol(&elf_file.base, pt, decl.navSrcLoc(mod), decl_val, &code_buffer, .none, .{
.parent_atom_index = sym_index,
});
const res = try codegen.generateSymbol(
&elf_file.base,
pt,
zcu.navSrcLoc(nav_index),
nav_init,
&code_buffer,
if (nav_state) |*ns| .{ .dwarf = ns } else .none,
.{ .parent_atom_index = sym_index },
);
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
return;
},
};
const shndx = try self.getDeclShdrIndex(elf_file, decl, code);
const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, code);
if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0)
try self.updateTlv(elf_file, pt, decl_index, sym_index, shndx, code)
try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code)
else
try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_OBJECT);
try self.updateNavCode(elf_file, pt, nav_index, sym_index, shndx, code, elf.STT_OBJECT);
if (decl_state) |*ds| {
if (nav_state) |*ns| {
const sym = self.symbol(sym_index);
try self.dwarf.?.commitDeclState(
try self.dwarf.?.commitNavState(
pt,
decl_index,
nav_index,
@intCast(sym.address(.{}, elf_file)),
sym.atom(elf_file).?.size,
ds,
ns,
);
}
@ -1237,13 +1179,13 @@ fn updateLazySymbol(
const name_str_index = blk: {
const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
@tagName(sym.kind),
sym.ty.fmt(pt),
Type.fromInterned(sym.ty).fmt(pt),
});
defer gpa.free(name);
break :blk try self.strtab.insert(gpa, name);
};
const src = sym.ty.srcLocOrNull(mod) orelse Module.LazySrcLoc.unneeded;
const src = Type.fromInterned(sym.ty).srcLocOrNull(mod) orelse Zcu.LazySrcLoc.unneeded;
const res = try codegen.generateLazySymbol(
&elf_file.base,
pt,
@ -1280,7 +1222,7 @@ fn updateLazySymbol(
atom_ptr.output_section_index = output_section_index;
try atom_ptr.allocate(elf_file);
errdefer self.freeDeclMetadata(elf_file, symbol_index);
errdefer self.freeNavMetadata(elf_file, symbol_index);
local_sym.value = 0;
local_sym.flags.needs_zig_got = true;
@ -1296,49 +1238,9 @@ fn updateLazySymbol(
try elf_file.base.file.?.pwriteAll(code, file_offset);
}
pub fn lowerUnnamedConst(
self: *ZigObject,
elf_file: *Elf,
pt: Zcu.PerThread,
val: Value,
decl_index: InternPool.DeclIndex,
) !u32 {
const gpa = elf_file.base.comp.gpa;
const mod = elf_file.base.comp.module.?;
const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
const unnamed_consts = gop.value_ptr;
const decl = mod.declPtr(decl_index);
const index = unnamed_consts.items.len;
const name = try std.fmt.allocPrint(gpa, "__unnamed_{}_{d}", .{ decl.fqn.fmt(&mod.intern_pool), index });
defer gpa.free(name);
const ty = val.typeOf(mod);
const sym_index = switch (try self.lowerConst(
elf_file,
pt,
name,
val,
ty.abiAlignment(pt),
elf_file.zig_data_rel_ro_section_index.?,
decl.navSrcLoc(mod),
)) {
.ok => |sym_index| sym_index,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
log.err("{s}", .{em.msg});
return error.CodegenFail;
},
};
try unnamed_consts.append(gpa, sym_index);
return sym_index;
}
const LowerConstResult = union(enum) {
ok: Symbol.Index,
fail: *Module.ErrorMsg,
fail: *Zcu.ErrorMsg,
};
fn lowerConst(
@ -1349,7 +1251,7 @@ fn lowerConst(
val: Value,
required_alignment: InternPool.Alignment,
output_section_index: u32,
src_loc: Module.LazySrcLoc,
src_loc: Zcu.LazySrcLoc,
) !LowerConstResult {
const gpa = pt.zcu.gpa;
@ -1384,7 +1286,8 @@ fn lowerConst(
atom_ptr.output_section_index = output_section_index;
try atom_ptr.allocate(elf_file);
errdefer self.freeDeclMetadata(elf_file, sym_index);
// TODO rename and re-audit this method
errdefer self.freeNavMetadata(elf_file, sym_index);
const shdr = elf_file.shdrs.items[output_section_index];
const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
@ -1397,7 +1300,7 @@ pub fn updateExports(
self: *ZigObject,
elf_file: *Elf,
pt: Zcu.PerThread,
exported: Module.Exported,
exported: Zcu.Exported,
export_indices: []const u32,
) link.File.UpdateExportsError!void {
const tracy = trace(@src());
@ -1406,24 +1309,24 @@ pub fn updateExports(
const mod = pt.zcu;
const gpa = elf_file.base.comp.gpa;
const metadata = switch (exported) {
.decl_index => |decl_index| blk: {
_ = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
break :blk self.decls.getPtr(decl_index).?;
.nav => |nav| blk: {
_ = try self.getOrCreateMetadataForNav(elf_file, nav);
break :blk self.navs.getPtr(nav).?;
},
.value => |value| self.anon_decls.getPtr(value) orelse blk: {
.uav => |uav| self.uavs.getPtr(uav) orelse blk: {
const first_exp = mod.all_exports.items[export_indices[0]];
const res = try self.lowerAnonDecl(elf_file, pt, value, .none, first_exp.src);
const res = try self.lowerUav(elf_file, pt, uav, .none, first_exp.src);
switch (res) {
.ok => {},
.mcv => {},
.fail => |em| {
// TODO maybe it's enough to return an error here and let Module.processExportsInner
// TODO maybe it's enough to return an error here and let Zcu.processExportsInner
// handle the error?
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
return;
},
}
break :blk self.anon_decls.getPtr(value).?;
break :blk self.uavs.getPtr(uav).?;
},
};
const sym_index = metadata.symbol_index;
@ -1436,7 +1339,7 @@ pub fn updateExports(
if (exp.opts.section.unwrap()) |section_name| {
if (!section_name.eqlSlice(".text", &mod.intern_pool)) {
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Zcu.ErrorMsg.create(
gpa,
exp.src,
"Unimplemented: ExportOptions.section",
@ -1451,7 +1354,7 @@ pub fn updateExports(
.weak => elf.STB_WEAK,
.link_once => {
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Zcu.ErrorMsg.create(
gpa,
exp.src,
"Unimplemented: GlobalLinkage.LinkOnce",
@ -1487,21 +1390,22 @@ pub fn updateExports(
}
}
/// Must be called only after a successful call to `updateDecl`.
pub fn updateDeclLineNumber(
/// Must be called only after a successful call to `updateNav`.
pub fn updateNavLineNumber(
self: *ZigObject,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
) !void {
const tracy = trace(@src());
defer tracy.end();
const decl = pt.zcu.declPtr(decl_index);
const ip = &pt.zcu.intern_pool;
const nav = ip.getNav(nav_index);
log.debug("updateDeclLineNumber {}({d})", .{ decl.fqn.fmt(&pt.zcu.intern_pool), decl_index });
log.debug("updateNavLineNumber {}({d})", .{ nav.fqn.fmt(ip), nav_index });
if (self.dwarf) |*dw| {
try dw.updateDeclLineNumber(pt.zcu, decl_index);
try dw.updateNavLineNumber(pt.zcu, nav_index);
}
}
@ -1512,9 +1416,9 @@ pub fn deleteExport(
name: InternPool.NullTerminatedString,
) void {
const metadata = switch (exported) {
.decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
.value => |value| self.anon_decls.getPtr(value) orelse return,
};
.nav => |nav| self.navs.getPtr(nav),
.uav => |uav| self.uavs.getPtr(uav),
} orelse return;
const mod = elf_file.base.comp.module.?;
const exp_name = name.toSlice(&mod.intern_pool);
const esym_index = metadata.@"export"(self, exp_name) orelse return;
@ -1754,14 +1658,14 @@ const LazySymbolMetadata = struct {
rodata_state: State = .unused,
};
const DeclMetadata = struct {
const AvMetadata = struct {
symbol_index: Symbol.Index,
/// A list of all exports aliases of this Decl.
/// A list of all exports aliases of this Av.
exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
fn @"export"(m: DeclMetadata, zo: *ZigObject, name: []const u8) ?*u32 {
fn @"export"(m: AvMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
for (m.exports.items) |*exp| {
const exp_name = zo.getString(zo.symbol(exp.*).name_offset);
const exp_name = zig_object.getString(zig_object.symbol(exp.*).name_offset);
if (mem.eql(u8, name, exp_name)) return exp;
}
return null;
@ -1778,10 +1682,9 @@ const TlsVariable = struct {
};
const AtomList = std.ArrayListUnmanaged(Atom.Index);
const UnnamedConstTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, std.ArrayListUnmanaged(Symbol.Index));
const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata);
const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.OptionalDeclIndex, LazySymbolMetadata);
const NavTable = std.AutoHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);
const UavTable = std.AutoHashMapUnmanaged(InternPool.Index, AvMetadata);
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);
const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable);
const assert = std.debug.assert;
@ -1792,8 +1695,8 @@ const link = @import("../../link.zig");
const log = std.log.scoped(.link);
const mem = std.mem;
const relocation = @import("relocation.zig");
const trace = @import("../../tracy.zig").trace;
const target_util = @import("../../target.zig");
const trace = @import("../../tracy.zig").trace;
const std = @import("std");
const Air = @import("../../Air.zig");
@ -1806,8 +1709,6 @@ const File = @import("file.zig").File;
const InternPool = @import("../../InternPool.zig");
const Liveness = @import("../../Liveness.zig");
const Zcu = @import("../../Zcu.zig");
/// Deprecated.
const Module = Zcu;
const Object = @import("Object.zig");
const Symbol = @import("Symbol.zig");
const StringTable = @import("../StringTable.zig");

View File

@ -2998,21 +2998,17 @@ pub fn updateFunc(self: *MachO, pt: Zcu.PerThread, func_index: InternPool.Index,
return self.getZigObject().?.updateFunc(self, pt, func_index, air, liveness);
}
pub fn lowerUnnamedConst(self: *MachO, pt: Zcu.PerThread, val: Value, decl_index: InternPool.DeclIndex) !u32 {
return self.getZigObject().?.lowerUnnamedConst(self, pt, val, decl_index);
}
pub fn updateDecl(self: *MachO, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
pub fn updateNav(self: *MachO, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {
if (build_options.skip_non_native and builtin.object_format != .macho) {
@panic("Attempted to compile for object format that was disabled by build configuration");
}
if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(pt, decl_index);
return self.getZigObject().?.updateDecl(self, pt, decl_index);
if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav);
return self.getZigObject().?.updateNav(self, pt, nav);
}
pub fn updateDeclLineNumber(self: *MachO, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
pub fn updateNavLineNumber(self: *MachO, pt: Zcu.PerThread, nav: InternPool.NavIndex) !void {
if (self.llvm_object) |_| return;
return self.getZigObject().?.updateDeclLineNumber(pt, decl_index);
return self.getZigObject().?.updateNavLineNumber(pt, nav);
}
pub fn updateExports(
@ -3037,29 +3033,29 @@ pub fn deleteExport(
return self.getZigObject().?.deleteExport(self, exported, name);
}
pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void {
if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
return self.getZigObject().?.freeDecl(decl_index);
pub fn freeNav(self: *MachO, nav: InternPool.Nav.Index) void {
if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav);
return self.getZigObject().?.freeNav(nav);
}
pub fn getDeclVAddr(self: *MachO, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex, reloc_info: link.File.RelocInfo) !u64 {
pub fn getNavVAddr(self: *MachO, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 {
assert(self.llvm_object == null);
return self.getZigObject().?.getDeclVAddr(self, pt, decl_index, reloc_info);
return self.getZigObject().?.getNavVAddr(self, pt, nav_index, reloc_info);
}
pub fn lowerAnonDecl(
pub fn lowerUav(
self: *MachO,
pt: Zcu.PerThread,
decl_val: InternPool.Index,
uav: InternPool.Index,
explicit_alignment: InternPool.Alignment,
src_loc: Module.LazySrcLoc,
) !codegen.Result {
return self.getZigObject().?.lowerAnonDecl(self, pt, decl_val, explicit_alignment, src_loc);
) !codegen.GenResult {
return self.getZigObject().?.lowerUav(self, pt, uav, explicit_alignment, src_loc);
}
pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
pub fn getUavVAddr(self: *MachO, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
assert(self.llvm_object == null);
return self.getZigObject().?.getAnonDeclVAddr(self, decl_val, reloc_info);
return self.getZigObject().?.getUavVAddr(self, uav, reloc_info);
}
pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 {
@ -4051,8 +4047,6 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
const default_entry_symbol_name = "_main";
pub const base_tag: link.File.Tag = link.File.Tag.macho;
const Section = struct {
header: macho.section_64,
segment_id: u8,

View File

@ -992,6 +992,8 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
const tracy = trace(@src());
defer tracy.end();
relocs_log.debug("{x}: {s}", .{ self.getAddress(macho_file), self.getName(macho_file) });
const cpu_arch = macho_file.getTarget().cpu.arch;
const relocs = self.getRelocs(macho_file);
@ -1015,6 +1017,24 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
addend += target;
}
switch (rel.tag) {
.local => relocs_log.debug(" {}: [{x} => {d}({s},{s})] + {x}", .{
rel.fmtPretty(cpu_arch),
r_address,
r_symbolnum,
macho_file.sections.items(.header)[r_symbolnum - 1].segName(),
macho_file.sections.items(.header)[r_symbolnum - 1].sectName(),
addend,
}),
.@"extern" => relocs_log.debug(" {}: [{x} => {d}({s})] + {x}", .{
rel.fmtPretty(cpu_arch),
r_address,
r_symbolnum,
rel.getTargetSymbol(self, macho_file).getName(macho_file),
addend,
}),
}
switch (cpu_arch) {
.aarch64 => {
if (rel.type == .unsigned) switch (rel.meta.length) {

View File

@ -19,32 +19,11 @@ atoms_extra: std.ArrayListUnmanaged(u32) = .{},
/// Table of tracked LazySymbols.
lazy_syms: LazySymbolTable = .{},
/// Table of tracked Decls.
decls: DeclTable = .{},
/// Table of tracked Navs.
navs: NavTable = .{},
/// Table of unnamed constants associated with a parent `Decl`.
/// We store them here so that we can free the constants whenever the `Decl`
/// needs updating or is freed.
///
/// For example,
///
/// ```zig
/// const Foo = struct{
/// a: u8,
/// };
///
/// pub fn main() void {
/// var foo = Foo{ .a = 1 };
/// _ = foo;
/// }
/// ```
///
/// value assigned to label `foo` is an unnamed constant belonging/associated
/// with `Decl` `main`, and lives as long as that `Decl`.
unnamed_consts: UnnamedConstTable = .{},
/// Table of tracked AnonDecls.
anon_decls: AnonDeclTable = .{},
/// Table of tracked Uavs.
uavs: UavTable = .{},
/// TLV initializers indexed by Atom.Index.
tlv_initializers: TlvInitializerTable = .{},
@ -100,31 +79,17 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
self.atoms_indexes.deinit(allocator);
self.atoms_extra.deinit(allocator);
{
var it = self.decls.iterator();
while (it.next()) |entry| {
entry.value_ptr.exports.deinit(allocator);
}
self.decls.deinit(allocator);
for (self.navs.values()) |*meta| {
meta.exports.deinit(allocator);
}
self.navs.deinit(allocator);
self.lazy_syms.deinit(allocator);
{
var it = self.unnamed_consts.valueIterator();
while (it.next()) |syms| {
syms.deinit(allocator);
}
self.unnamed_consts.deinit(allocator);
}
{
var it = self.anon_decls.iterator();
while (it.next()) |entry| {
entry.value_ptr.exports.deinit(allocator);
}
self.anon_decls.deinit(allocator);
for (self.uavs.values()) |*meta| {
meta.exports.deinit(allocator);
}
self.uavs.deinit(allocator);
for (self.relocs.items) |*list| {
list.deinit(allocator);
@ -601,7 +566,7 @@ pub fn getInputSection(self: ZigObject, atom: Atom, macho_file: *MachO) macho.se
pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) !void {
// Handle any lazy symbols that were emitted by incremental compilation.
if (self.lazy_syms.getPtr(.none)) |metadata| {
if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
const pt: Zcu.PerThread = .{ .zcu = macho_file.base.comp.module.?, .tid = tid };
// Most lazy symbols can be updated on first use, but
@ -609,7 +574,7 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
if (metadata.text_state != .unused) self.updateLazySymbol(
macho_file,
pt,
link.File.LazySymbol.initDecl(.code, null, pt.zcu),
.{ .kind = .code, .ty = .anyerror_type },
metadata.text_symbol_index,
) catch |err| return switch (err) {
error.CodegenFail => error.FlushFailure,
@ -618,7 +583,7 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
if (metadata.const_state != .unused) self.updateLazySymbol(
macho_file,
pt,
link.File.LazySymbol.initDecl(.const_data, null, pt.zcu),
.{ .kind = .const_data, .ty = .anyerror_type },
metadata.const_symbol_index,
) catch |err| return switch (err) {
error.CodegenFail => error.FlushFailure,
@ -691,25 +656,25 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
assert(!self.debug_strtab_dirty);
}
pub fn getDeclVAddr(
pub fn getNavVAddr(
self: *ZigObject,
macho_file: *MachO,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
reloc_info: link.File.RelocInfo,
) !u64 {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const decl = zcu.declPtr(decl_index);
log.debug("getDeclVAddr {}({d})", .{ decl.fqn.fmt(ip), decl_index });
const sym_index = if (decl.isExtern(zcu)) blk: {
const name = decl.name.toSlice(ip);
const lib_name = if (decl.getOwnedExternFunc(zcu)) |ext_fn|
ext_fn.lib_name.toSlice(ip)
else
decl.getOwnedVariable(zcu).?.lib_name.toSlice(ip);
break :blk try self.getGlobalSymbol(macho_file, name, lib_name);
} else try self.getOrCreateMetadataForDecl(macho_file, decl_index);
const nav = ip.getNav(nav_index);
log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
.@"extern" => |@"extern"| try self.getGlobalSymbol(
macho_file,
nav.name.toSlice(ip),
@"extern".lib_name.toSlice(ip),
),
else => try self.getOrCreateMetadataForNav(macho_file, nav_index),
};
const sym = self.symbols.items[sym_index];
const vaddr = sym.getAddress(.{}, macho_file);
const parent_atom = self.symbols.items[reloc_info.parent_atom_index].getAtom(macho_file).?;
@ -729,13 +694,13 @@ pub fn getDeclVAddr(
return vaddr;
}
pub fn getAnonDeclVAddr(
pub fn getUavVAddr(
self: *ZigObject,
macho_file: *MachO,
decl_val: InternPool.Index,
uav: InternPool.Index,
reloc_info: link.File.RelocInfo,
) !u64 {
const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
const sym_index = self.uavs.get(uav).?.symbol_index;
const sym = self.symbols.items[sym_index];
const vaddr = sym.getAddress(.{}, macho_file);
const parent_atom = self.symbols.items[reloc_info.parent_atom_index].getAtom(macho_file).?;
@ -755,42 +720,43 @@ pub fn getAnonDeclVAddr(
return vaddr;
}
pub fn lowerAnonDecl(
pub fn lowerUav(
self: *ZigObject,
macho_file: *MachO,
pt: Zcu.PerThread,
decl_val: InternPool.Index,
uav: InternPool.Index,
explicit_alignment: Atom.Alignment,
src_loc: Module.LazySrcLoc,
) !codegen.Result {
const gpa = macho_file.base.comp.gpa;
const mod = macho_file.base.comp.module.?;
const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
const decl_alignment = switch (explicit_alignment) {
.none => ty.abiAlignment(pt),
src_loc: Zcu.LazySrcLoc,
) !codegen.GenResult {
const zcu = pt.zcu;
const gpa = zcu.gpa;
const val = Value.fromInterned(uav);
const uav_alignment = switch (explicit_alignment) {
.none => val.typeOf(zcu).abiAlignment(pt),
else => explicit_alignment,
};
if (self.anon_decls.get(decl_val)) |metadata| {
const existing_alignment = self.symbols.items[metadata.symbol_index].getAtom(macho_file).?.alignment;
if (decl_alignment.order(existing_alignment).compare(.lte))
return .ok;
if (self.uavs.get(uav)) |metadata| {
const sym = self.symbols.items[metadata.symbol_index];
const existing_alignment = sym.getAtom(macho_file).?.alignment;
if (uav_alignment.order(existing_alignment).compare(.lte))
return .{ .mcv = .{ .load_symbol = sym.nlist_idx } };
}
var name_buf: [32]u8 = undefined;
const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
@intFromEnum(decl_val),
@intFromEnum(uav),
}) catch unreachable;
const res = self.lowerConst(
macho_file,
pt,
name,
Value.fromInterned(decl_val),
decl_alignment,
val,
uav_alignment,
macho_file.zig_const_sect_index.?,
src_loc,
) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
else => |e| return .{ .fail = try Module.ErrorMsg.create(
else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
gpa,
src_loc,
"unable to lower constant value: {s}",
@ -801,20 +767,13 @@ pub fn lowerAnonDecl(
.ok => |sym_index| sym_index,
.fail => |em| return .{ .fail = em },
};
try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
return .ok;
try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index });
return .{ .mcv = .{
.load_symbol = self.symbols.items[sym_index].nlist_idx,
} };
}
fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {
const gpa = macho_file.base.comp.gpa;
const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
for (unnamed_consts.items) |sym_index| {
self.freeDeclMetadata(macho_file, sym_index);
}
unnamed_consts.clearAndFree(gpa);
}
fn freeDeclMetadata(self: *ZigObject, macho_file: *MachO, sym_index: Symbol.Index) void {
fn freeNavMetadata(self: *ZigObject, macho_file: *MachO, sym_index: Symbol.Index) void {
const sym = self.symbols.items[sym_index];
sym.getAtom(macho_file).?.free(macho_file);
log.debug("adding %{d} to local symbols free list", .{sym_index});
@ -822,18 +781,14 @@ fn freeDeclMetadata(self: *ZigObject, macho_file: *MachO, sym_index: Symbol.Inde
// TODO free GOT entry here
}
pub fn freeDecl(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {
pub fn freeNav(self: *ZigObject, macho_file: *MachO, nav_index: InternPool.Nav.Index) void {
const gpa = macho_file.base.comp.gpa;
const mod = macho_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
log.debug("freeNav 0x{x}", .{nav_index});
log.debug("freeDecl {*}", .{decl});
if (self.decls.fetchRemove(decl_index)) |const_kv| {
if (self.navs.fetchRemove(nav_index)) |const_kv| {
var kv = const_kv;
const sym_index = kv.value.symbol_index;
self.freeDeclMetadata(macho_file, sym_index);
self.freeUnnamedConsts(macho_file, decl_index);
self.freeNavMetadata(macho_file, sym_index);
kv.value.exports.deinit(gpa);
}
@ -851,51 +806,46 @@ pub fn updateFunc(
const tracy = trace(@src());
defer tracy.end();
const mod = pt.zcu;
const gpa = mod.gpa;
const func = mod.funcInfo(func_index);
const decl_index = func.owner_decl;
const decl = mod.declPtr(decl_index);
const zcu = pt.zcu;
const gpa = zcu.gpa;
const func = zcu.funcInfo(func_index);
const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
self.freeUnnamedConsts(macho_file, decl_index);
const sym_index = try self.getOrCreateMetadataForNav(macho_file, func.owner_nav);
self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(pt, decl_index) else null;
defer if (decl_state) |*ds| ds.deinit();
var dwarf_state = if (self.dwarf) |*dw| try dw.initNavState(pt, func.owner_nav) else null;
defer if (dwarf_state) |*ds| ds.deinit();
const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;
const res = try codegen.generateFunction(
&macho_file.base,
pt,
decl.navSrcLoc(mod),
zcu.navSrcLoc(func.owner_nav),
func_index,
air,
liveness,
&code_buffer,
dio,
if (dwarf_state) |*ds| .{ .dwarf = ds } else .none,
);
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
func.setAnalysisState(&mod.intern_pool, .codegen_failure);
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
try zcu.failed_codegen.put(gpa, func.owner_nav, em);
return;
},
};
const sect_index = try self.getDeclOutputSection(macho_file, decl, code);
try self.updateDeclCode(macho_file, pt, decl_index, sym_index, sect_index, code);
const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code);
try self.updateNavCode(macho_file, pt, func.owner_nav, sym_index, sect_index, code);
if (decl_state) |*ds| {
if (dwarf_state) |*ds| {
const sym = self.symbols.items[sym_index];
try self.dwarf.?.commitDeclState(
try self.dwarf.?.commitNavState(
pt,
decl_index,
func.owner_nav,
sym.getAddress(.{}, macho_file),
sym.getAtom(macho_file).?.size,
ds,
@ -905,96 +855,98 @@ pub fn updateFunc(
// Exports will be updated by `Zcu.processExports` after the update.
}
pub fn updateDecl(
pub fn updateNav(
self: *ZigObject,
macho_file: *MachO,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
) link.File.UpdateDeclError!void {
nav_index: InternPool.Nav.Index,
) link.File.UpdateNavError!void {
const tracy = trace(@src());
defer tracy.end();
const mod = pt.zcu;
const decl = mod.declPtr(decl_index);
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav_val = zcu.navValue(nav_index);
const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
.variable => |variable| Value.fromInterned(variable.init),
.@"extern" => |@"extern"| {
if (ip.isFunctionType(@"extern".ty)) return;
// Extern variable gets a __got entry only
const name = @"extern".name.toSlice(ip);
const lib_name = @"extern".lib_name.toSlice(ip);
const index = try self.getGlobalSymbol(macho_file, name, lib_name);
const sym = &self.symbols.items[index];
sym.setSectionFlags(.{ .needs_got = true });
return;
},
else => nav_val,
};
if (decl.val.getExternFunc(mod)) |_| {
return;
}
if (decl.isExtern(mod)) {
// Extern variable gets a __got entry only
const variable = decl.getOwnedVariable(mod).?;
const name = decl.name.toSlice(&mod.intern_pool);
const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
const index = try self.getGlobalSymbol(macho_file, name, lib_name);
const sym = &self.symbols.items[index];
sym.setSectionFlags(.{ .needs_got = true });
return;
}
const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index);
self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
const gpa = macho_file.base.comp.gpa;
var code_buffer = std.ArrayList(u8).init(gpa);
var code_buffer = std.ArrayList(u8).init(zcu.gpa);
defer code_buffer.deinit();
var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(pt, decl_index) else null;
defer if (decl_state) |*ds| ds.deinit();
var nav_state: ?Dwarf.NavState = if (self.dwarf) |*dw| try dw.initNavState(pt, nav_index) else null;
defer if (nav_state) |*ns| ns.deinit();
const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;
const res = try codegen.generateSymbol(&macho_file.base, pt, decl.navSrcLoc(mod), decl_val, &code_buffer, dio, .{
.parent_atom_index = sym_index,
});
const res = try codegen.generateSymbol(
&macho_file.base,
pt,
zcu.navSrcLoc(nav_index),
nav_init,
&code_buffer,
if (nav_state) |*ns| .{ .dwarf = ns } else .none,
.{ .parent_atom_index = sym_index },
);
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
return;
},
};
if (isThreadlocal(macho_file, decl_index)) {
const sect_index = try self.getDeclOutputSection(macho_file, decl, code);
try self.updateTlv(macho_file, pt, decl_index, sym_index, sect_index, code);
} else {
const sect_index = try self.getDeclOutputSection(macho_file, decl, code);
try self.updateDeclCode(macho_file, pt, decl_index, sym_index, sect_index, code);
}
const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code);
if (isThreadlocal(macho_file, nav_index))
try self.updateTlv(macho_file, pt, nav_index, sym_index, sect_index, code)
else
try self.updateNavCode(macho_file, pt, nav_index, sym_index, sect_index, code);
if (decl_state) |*ds| {
if (nav_state) |*ns| {
const sym = self.symbols.items[sym_index];
try self.dwarf.?.commitDeclState(
try self.dwarf.?.commitNavState(
pt,
decl_index,
nav_index,
sym.getAddress(.{}, macho_file),
sym.getAtom(macho_file).?.size,
ds,
ns,
);
}
// Exports will be updated by `Zcu.processExports` after the update.
}
fn updateDeclCode(
fn updateNavCode(
self: *ZigObject,
macho_file: *MachO,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
sym_index: Symbol.Index,
sect_index: u8,
code: []const u8,
) !void {
const gpa = macho_file.base.comp.gpa;
const mod = pt.zcu;
const ip = &mod.intern_pool;
const decl = mod.declPtr(decl_index);
const zcu = pt.zcu;
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
log.debug("updateDeclCode {}{*}", .{ decl.fqn.fmt(ip), decl });
log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
const required_alignment = decl.getAlignment(pt);
const required_alignment = pt.navAlignment(nav_index).max(
target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result),
);
const sect = &macho_file.sections.items(.header)[sect_index];
const sym = &self.symbols.items[sym_index];
@ -1004,7 +956,7 @@ fn updateDeclCode(
sym.out_n_sect = sect_index;
atom.out_n_sect = sect_index;
const sym_name = try std.fmt.allocPrintZ(gpa, "_{s}", .{decl.fqn.toSlice(ip)});
const sym_name = try std.fmt.allocPrintZ(gpa, "_{s}", .{nav.fqn.toSlice(ip)});
defer gpa.free(sym_name);
sym.name = try self.addString(gpa, sym_name);
atom.setAlive(true);
@ -1025,7 +977,7 @@ fn updateDeclCode(
if (need_realloc) {
try atom.grow(macho_file);
log.debug("growing {} from 0x{x} to 0x{x}", .{ decl.fqn.fmt(ip), old_vaddr, atom.value });
log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value });
if (old_vaddr != atom.value) {
sym.value = 0;
nlist.n_value = 0;
@ -1045,7 +997,7 @@ fn updateDeclCode(
}
} else {
try atom.allocate(macho_file);
errdefer self.freeDeclMetadata(macho_file, sym_index);
errdefer self.freeNavMetadata(macho_file, sym_index);
sym.value = 0;
sym.setSectionFlags(.{ .needs_zig_got = true });
@ -1070,27 +1022,27 @@ fn updateTlv(
self: *ZigObject,
macho_file: *MachO,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
sym_index: Symbol.Index,
sect_index: u8,
code: []const u8,
) !void {
const ip = &pt.zcu.intern_pool;
const decl = pt.zcu.declPtr(decl_index);
const nav = ip.getNav(nav_index);
log.debug("updateTlv {} ({*})", .{ decl.fqn.fmt(&pt.zcu.intern_pool), decl });
log.debug("updateTlv {} (0x{x})", .{ nav.fqn.fmt(ip), nav_index });
// 1. Lower TLV initializer
const init_sym_index = try self.createTlvInitializer(
macho_file,
decl.fqn.toSlice(ip),
decl.getAlignment(pt),
nav.fqn.toSlice(ip),
pt.navAlignment(nav_index),
sect_index,
code,
);
// 2. Create TLV descriptor
try self.createTlvDescriptor(macho_file, sym_index, init_sym_index, decl.fqn.toSlice(ip));
try self.createTlvDescriptor(macho_file, sym_index, init_sym_index, nav.fqn.toSlice(ip));
}
fn createTlvInitializer(
@ -1197,102 +1149,52 @@ fn createTlvDescriptor(
});
}
fn getDeclOutputSection(
fn getNavOutputSection(
self: *ZigObject,
macho_file: *MachO,
decl: *const Module.Decl,
zcu: *Zcu,
nav_index: InternPool.Nav.Index,
code: []const u8,
) error{OutOfMemory}!u8 {
_ = self;
const mod = macho_file.base.comp.module.?;
const ip = &zcu.intern_pool;
const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded;
const sect_id: u8 = switch (decl.typeOf(mod).zigTypeTag(mod)) {
.Fn => macho_file.zig_text_sect_index.?,
else => blk: {
if (decl.getOwnedVariable(mod)) |variable| {
if (variable.is_threadlocal and any_non_single_threaded) {
const is_all_zeroes = for (code) |byte| {
if (byte != 0) break false;
} else true;
if (is_all_zeroes) break :blk macho_file.getSectionByName("__DATA", "__thread_bss") orelse try macho_file.addSection(
"__DATA",
"__thread_bss",
.{ .flags = macho.S_THREAD_LOCAL_ZEROFILL },
);
break :blk macho_file.getSectionByName("__DATA", "__thread_data") orelse try macho_file.addSection(
"__DATA",
"__thread_data",
.{ .flags = macho.S_THREAD_LOCAL_REGULAR },
);
}
if (variable.is_const) break :blk macho_file.zig_const_sect_index.?;
if (Value.fromInterned(variable.init).isUndefDeep(mod)) {
// TODO: get the optimize_mode from the Module that owns the decl instead
// of using the root module here.
break :blk switch (macho_file.base.comp.root_mod.optimize_mode) {
.Debug, .ReleaseSafe => macho_file.zig_data_sect_index.?,
.ReleaseFast, .ReleaseSmall => macho_file.zig_bss_sect_index.?,
};
}
// TODO I blatantly copied the logic from the Wasm linker, but is there a less
// intrusive check for all zeroes than this?
const is_all_zeroes = for (code) |byte| {
if (byte != 0) break false;
} else true;
if (is_all_zeroes) break :blk macho_file.zig_bss_sect_index.?;
break :blk macho_file.zig_data_sect_index.?;
}
break :blk macho_file.zig_const_sect_index.?;
},
const nav_val = zcu.navValue(nav_index);
if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return macho_file.zig_text_sect_index.?;
const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
.variable => |variable| .{ false, variable.is_threadlocal, variable.init },
.@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
else => .{ true, false, nav_val.toIntern() },
};
return sect_id;
}
pub fn lowerUnnamedConst(
self: *ZigObject,
macho_file: *MachO,
pt: Zcu.PerThread,
val: Value,
decl_index: InternPool.DeclIndex,
) !u32 {
const mod = pt.zcu;
const gpa = mod.gpa;
const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
if (any_non_single_threaded and is_threadlocal) {
for (code) |byte| {
if (byte != 0) break;
} else return macho_file.getSectionByName("__DATA", "__thread_bss") orelse try macho_file.addSection(
"__DATA",
"__thread_bss",
.{ .flags = macho.S_THREAD_LOCAL_ZEROFILL },
);
return macho_file.getSectionByName("__DATA", "__thread_data") orelse try macho_file.addSection(
"__DATA",
"__thread_data",
.{ .flags = macho.S_THREAD_LOCAL_REGULAR },
);
}
const unnamed_consts = gop.value_ptr;
const decl = mod.declPtr(decl_index);
const index = unnamed_consts.items.len;
const name = try std.fmt.allocPrint(gpa, "__unnamed_{}_{d}", .{ decl.fqn.fmt(&mod.intern_pool), index });
defer gpa.free(name);
const sym_index = switch (try self.lowerConst(
macho_file,
pt,
name,
val,
val.typeOf(mod).abiAlignment(pt),
macho_file.zig_const_sect_index.?,
decl.navSrcLoc(mod),
)) {
.ok => |sym_index| sym_index,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
log.err("{s}", .{em.msg});
return error.CodegenFail;
},
};
const sym = self.symbols.items[sym_index];
try unnamed_consts.append(gpa, sym.atom_ref.index);
return sym_index;
if (is_const) return macho_file.zig_const_sect_index.?;
if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu))
return switch (zcu.navFileScope(nav_index).mod.optimize_mode) {
.Debug, .ReleaseSafe => macho_file.zig_data_sect_index.?,
.ReleaseFast, .ReleaseSmall => macho_file.zig_bss_sect_index.?,
};
for (code) |byte| {
if (byte != 0) break;
} else return macho_file.zig_bss_sect_index.?;
return macho_file.zig_data_sect_index.?;
}
const LowerConstResult = union(enum) {
ok: Symbol.Index,
fail: *Module.ErrorMsg,
fail: *Zcu.ErrorMsg,
};
fn lowerConst(
@ -1303,7 +1205,7 @@ fn lowerConst(
val: Value,
required_alignment: Atom.Alignment,
output_section_index: u8,
src_loc: Module.LazySrcLoc,
src_loc: Zcu.LazySrcLoc,
) !LowerConstResult {
const gpa = macho_file.base.comp.gpa;
@ -1338,7 +1240,7 @@ fn lowerConst(
try atom.allocate(macho_file);
// TODO rename and re-audit this method
errdefer self.freeDeclMetadata(macho_file, sym_index);
errdefer self.freeNavMetadata(macho_file, sym_index);
const sect = macho_file.sections.items(.header)[output_section_index];
const file_offset = sect.offset + atom.value;
@ -1351,7 +1253,7 @@ pub fn updateExports(
self: *ZigObject,
macho_file: *MachO,
pt: Zcu.PerThread,
exported: Module.Exported,
exported: Zcu.Exported,
export_indices: []const u32,
) link.File.UpdateExportsError!void {
const tracy = trace(@src());
@ -1360,24 +1262,24 @@ pub fn updateExports(
const mod = pt.zcu;
const gpa = macho_file.base.comp.gpa;
const metadata = switch (exported) {
.decl_index => |decl_index| blk: {
_ = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
break :blk self.decls.getPtr(decl_index).?;
.nav => |nav| blk: {
_ = try self.getOrCreateMetadataForNav(macho_file, nav);
break :blk self.navs.getPtr(nav).?;
},
.value => |value| self.anon_decls.getPtr(value) orelse blk: {
.uav => |uav| self.uavs.getPtr(uav) orelse blk: {
const first_exp = mod.all_exports.items[export_indices[0]];
const res = try self.lowerAnonDecl(macho_file, pt, value, .none, first_exp.src);
const res = try self.lowerUav(macho_file, pt, uav, .none, first_exp.src);
switch (res) {
.ok => {},
.mcv => {},
.fail => |em| {
// TODO maybe it's enough to return an error here and let Module.processExportsInner
// TODO maybe it's enough to return an error here and let Zcu.processExportsInner
// handle the error?
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
return;
},
}
break :blk self.anon_decls.getPtr(value).?;
break :blk self.uavs.getPtr(uav).?;
},
};
const sym_index = metadata.symbol_index;
@ -1389,7 +1291,7 @@ pub fn updateExports(
if (exp.opts.section.unwrap()) |section_name| {
if (!section_name.eqlSlice("__text", &mod.intern_pool)) {
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Zcu.ErrorMsg.create(
gpa,
exp.src,
"Unimplemented: ExportOptions.section",
@ -1399,7 +1301,7 @@ pub fn updateExports(
}
}
if (exp.opts.linkage == .link_once) {
try mod.failed_exports.putNoClobber(mod.gpa, export_idx, try Module.ErrorMsg.create(
try mod.failed_exports.putNoClobber(mod.gpa, export_idx, try Zcu.ErrorMsg.create(
gpa,
exp.src,
"Unimplemented: GlobalLinkage.link_once",
@ -1454,8 +1356,8 @@ fn updateLazySymbol(
lazy_sym: link.File.LazySymbol,
symbol_index: Symbol.Index,
) !void {
const gpa = macho_file.base.comp.gpa;
const mod = macho_file.base.comp.module.?;
const zcu = pt.zcu;
const gpa = zcu.gpa;
var required_alignment: Atom.Alignment = .none;
var code_buffer = std.ArrayList(u8).init(gpa);
@ -1464,13 +1366,13 @@ fn updateLazySymbol(
const name_str = blk: {
const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
@tagName(lazy_sym.kind),
lazy_sym.ty.fmt(pt),
Type.fromInterned(lazy_sym.ty).fmt(pt),
});
defer gpa.free(name);
break :blk try self.addString(gpa, name);
};
const src = lazy_sym.ty.srcLocOrNull(mod) orelse Module.LazySrcLoc.unneeded;
const src = Type.fromInterned(lazy_sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded;
const res = try codegen.generateLazySymbol(
&macho_file.base,
pt,
@ -1511,7 +1413,7 @@ fn updateLazySymbol(
atom.out_n_sect = output_section_index;
try atom.allocate(macho_file);
errdefer self.freeDeclMetadata(macho_file, symbol_index);
errdefer self.freeNavMetadata(macho_file, symbol_index);
sym.value = 0;
sym.setSectionFlags(.{ .needs_zig_got = true });
@ -1527,10 +1429,14 @@ fn updateLazySymbol(
try macho_file.base.file.?.pwriteAll(code, file_offset);
}
/// Must be called only after a successful call to `updateDecl`.
pub fn updateDeclLineNumber(self: *ZigObject, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
/// Must be called only after a successful call to `updateNav`.
pub fn updateNavLineNumber(
self: *ZigObject,
pt: Zcu.PerThread,
nav_index: InternPool.Nav.Index,
) !void {
if (self.dwarf) |*dw| {
try dw.updateDeclLineNumber(pt.zcu, decl_index);
try dw.updateNavLineNumber(pt.zcu, nav_index);
}
}
@ -1543,9 +1449,9 @@ pub fn deleteExport(
const mod = macho_file.base.comp.module.?;
const metadata = switch (exported) {
.decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
.value => |value| self.anon_decls.getPtr(value) orelse return,
};
.nav => |nav| self.navs.getPtr(nav),
.uav => |uav| self.uavs.getPtr(uav),
} orelse return;
const nlist_index = metadata.@"export"(self, name.toSlice(&mod.intern_pool)) orelse return;
log.debug("deleting export '{}'", .{name.fmt(&mod.intern_pool)});
@ -1577,17 +1483,17 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l
return lookup_gop.value_ptr.*;
}
pub fn getOrCreateMetadataForDecl(
pub fn getOrCreateMetadataForNav(
self: *ZigObject,
macho_file: *MachO,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
) !Symbol.Index {
const gpa = macho_file.base.comp.gpa;
const gop = try self.decls.getOrPut(gpa, decl_index);
const gop = try self.navs.getOrPut(gpa, nav_index);
if (!gop.found_existing) {
const sym_index = try self.newSymbolWithAtom(gpa, .{}, macho_file);
const sym = &self.symbols.items[sym_index];
if (isThreadlocal(macho_file, decl_index)) {
if (isThreadlocal(macho_file, nav_index)) {
sym.flags.tlv = true;
} else {
sym.setSectionFlags(.{ .needs_zig_got = true });
@ -1603,47 +1509,39 @@ pub fn getOrCreateMetadataForLazySymbol(
pt: Zcu.PerThread,
lazy_sym: link.File.LazySymbol,
) !Symbol.Index {
const mod = pt.zcu;
const gpa = mod.gpa;
const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod));
const gop = try self.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty);
errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
if (!gop.found_existing) gop.value_ptr.* = .{};
const metadata: struct {
symbol_index: *Symbol.Index,
state: *LazySymbolMetadata.State,
} = switch (lazy_sym.kind) {
.code => .{
.symbol_index = &gop.value_ptr.text_symbol_index,
.state = &gop.value_ptr.text_state,
},
.const_data => .{
.symbol_index = &gop.value_ptr.const_symbol_index,
.state = &gop.value_ptr.const_state,
},
const symbol_index_ptr, const state_ptr = switch (lazy_sym.kind) {
.code => .{ &gop.value_ptr.text_symbol_index, &gop.value_ptr.text_state },
.const_data => .{ &gop.value_ptr.const_symbol_index, &gop.value_ptr.const_state },
};
switch (metadata.state.*) {
switch (state_ptr.*) {
.unused => {
const symbol_index = try self.newSymbolWithAtom(gpa, .{}, macho_file);
const symbol_index = try self.newSymbolWithAtom(pt.zcu.gpa, .{}, macho_file);
const sym = &self.symbols.items[symbol_index];
sym.setSectionFlags(.{ .needs_zig_got = true });
metadata.symbol_index.* = symbol_index;
symbol_index_ptr.* = symbol_index;
},
.pending_flush => return metadata.symbol_index.*,
.pending_flush => return symbol_index_ptr.*,
.flushed => {},
}
metadata.state.* = .pending_flush;
const symbol_index = metadata.symbol_index.*;
state_ptr.* = .pending_flush;
const symbol_index = symbol_index_ptr.*;
// anyerror needs to be deferred until flushModule
if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(macho_file, pt, lazy_sym, symbol_index);
if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbol(macho_file, pt, lazy_sym, symbol_index);
return symbol_index;
}
fn isThreadlocal(macho_file: *MachO, decl_index: InternPool.DeclIndex) bool {
const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded;
const zcu = macho_file.base.comp.module.?;
const decl = zcu.declPtr(decl_index);
const variable = decl.getOwnedVariable(zcu) orelse return false;
return variable.is_threadlocal and any_non_single_threaded;
fn isThreadlocal(macho_file: *MachO, nav_index: InternPool.Nav.Index) bool {
if (!macho_file.base.comp.config.any_non_single_threaded)
return false;
const ip = &macho_file.base.comp.module.?.intern_pool;
return switch (ip.indexToKey(ip.getNav(nav_index).status.resolved.val)) {
.variable => |variable| variable.is_threadlocal,
.@"extern" => |@"extern"| @"extern".is_threadlocal,
else => false,
};
}
fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
@ -1848,12 +1746,12 @@ fn formatAtoms(
}
}
const DeclMetadata = struct {
const AvMetadata = struct {
symbol_index: Symbol.Index,
/// A list of all exports aliases of this Decl.
/// A list of all exports aliases of this Av.
exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
fn @"export"(m: AvMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
for (m.exports.items) |*exp| {
const nlist = zig_object.symtab.items(.nlist)[exp.*];
const exp_name = zig_object.strtab.getAssumeExists(nlist.n_strx);
@ -1880,10 +1778,9 @@ const TlvInitializer = struct {
}
};
const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata);
const UnnamedConstTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, std.ArrayListUnmanaged(Symbol.Index));
const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.OptionalDeclIndex, LazySymbolMetadata);
const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);
const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata);
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);
const RelocationTable = std.ArrayListUnmanaged(std.ArrayListUnmanaged(Relocation));
const TlvInitializerTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlvInitializer);
@ -1894,6 +1791,7 @@ const link = @import("../../link.zig");
const log = std.log.scoped(.link);
const macho = std.macho;
const mem = std.mem;
const target_util = @import("../../target.zig");
const trace = @import("../../tracy.zig").trace;
const std = @import("std");
@ -1908,8 +1806,6 @@ const Liveness = @import("../../Liveness.zig");
const MachO = @import("../MachO.zig");
const Nlist = Object.Nlist;
const Zcu = @import("../../Zcu.zig");
/// Deprecated.
const Module = Zcu;
const Object = @import("Object.zig");
const Relocation = @import("Relocation.zig");
const Symbol = @import("Symbol.zig");

View File

@ -86,8 +86,8 @@ pub fn updateFunc(self: *NvPtx, pt: Zcu.PerThread, func_index: InternPool.Index,
try self.llvm_object.updateFunc(pt, func_index, air, liveness);
}
pub fn updateDecl(self: *NvPtx, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
return self.llvm_object.updateDecl(pt, decl_index);
pub fn updateNav(self: *NvPtx, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {
return self.llvm_object.updateNav(pt, nav);
}
pub fn updateExports(

View File

@ -24,8 +24,6 @@ const Allocator = std.mem.Allocator;
const log = std.log.scoped(.link);
const assert = std.debug.assert;
pub const base_tag = .plan9;
base: link.File,
sixtyfour_bit: bool,
bases: Bases,
@ -53,40 +51,19 @@ path_arena: std.heap.ArenaAllocator,
/// The debugger looks for the first file (aout.Sym.Type.z) preceeding the text symbol
/// of the function to know what file it came from.
/// If we group the decls by file, it makes it really easy to do this (put the symbol in the correct place)
fn_decl_table: std.AutoArrayHashMapUnmanaged(
*Zcu.File,
struct { sym_index: u32, functions: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, FnDeclOutput) = .{} },
fn_nav_table: std.AutoArrayHashMapUnmanaged(
Zcu.File.Index,
struct { sym_index: u32, functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, FnNavOutput) = .{} },
) = .{},
/// the code is modified when relocated, so that is why it is mutable
data_decl_table: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u8) = .{},
data_nav_table: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, []u8) = .{},
/// When `updateExports` is called, we store the export indices here, to be used
/// during flush.
decl_exports: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u32) = .{},
/// Table of unnamed constants associated with a parent `Decl`.
/// We store them here so that we can free the constants whenever the `Decl`
/// needs updating or is freed.
///
/// For example,
///
/// ```zig
/// const Foo = struct{
/// a: u8,
/// };
///
/// pub fn main() void {
/// var foo = Foo{ .a = 1 };
/// _ = foo;
/// }
/// ```
///
/// value assigned to label `foo` is an unnamed constant belonging/associated
/// with `Decl` `main`, and lives as long as that `Decl`.
unnamed_const_atoms: UnnamedConstTable = .{},
nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, []u32) = .{},
lazy_syms: LazySymbolTable = .{},
anon_decls: std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
uavs: std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
relocs: std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Reloc)) = .{},
hdr: aout.ExecHdr = undefined,
@ -104,7 +81,7 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{},
syms_index_free_list: std.ArrayListUnmanaged(usize) = .{},
atoms: std.ArrayListUnmanaged(Atom) = .{},
decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata) = .{},
navs: std.AutoHashMapUnmanaged(InternPool.Nav.Index, NavMetadata) = .{},
/// Indices of the three "special" symbols into atoms
etext_edata_end_atom_indices: [3]?Atom.Index = .{ null, null, null },
@ -131,9 +108,7 @@ const Bases = struct {
data: u64,
};
const UnnamedConstTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, std.ArrayListUnmanaged(Atom.Index));
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.OptionalDeclIndex, LazySymbolMetadata);
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);
const LazySymbolMetadata = struct {
const State = enum { unused, pending_flush, flushed };
@ -161,7 +136,7 @@ pub const Atom = struct {
/// offset into got
got_index: ?usize,
/// We include the code here to be use in relocs
/// In the case of unnamed_const_atoms and lazy_syms, this atom owns the code.
/// In the case of lazy_syms, this atom owns the code.
/// But, in the case of function and data decls, they own the code and this field
/// is just a pointer for convience.
code: CodePtr,
@ -170,22 +145,23 @@ pub const Atom = struct {
code_ptr: ?[*]u8,
other: union {
code_len: usize,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
},
fn fromSlice(slice: []u8) CodePtr {
return .{ .code_ptr = slice.ptr, .other = .{ .code_len = slice.len } };
}
fn getCode(self: CodePtr, plan9: *const Plan9) []u8 {
const mod = plan9.base.comp.module.?;
const zcu = plan9.base.comp.module.?;
const ip = &zcu.intern_pool;
return if (self.code_ptr) |p| p[0..self.other.code_len] else blk: {
const decl_index = self.other.decl_index;
const decl = mod.declPtr(decl_index);
if (decl.typeOf(mod).zigTypeTag(mod) == .Fn) {
const table = plan9.fn_decl_table.get(decl.getFileScope(mod)).?.functions;
const output = table.get(decl_index).?;
const nav_index = self.other.nav_index;
const nav = ip.getNav(nav_index);
if (ip.isFunctionType(nav.typeOf(ip))) {
const table = plan9.fn_nav_table.get(zcu.navFileScopeIndex(nav_index)).?.functions;
const output = table.get(nav_index).?;
break :blk output.code;
} else {
break :blk plan9.data_decl_table.get(decl_index).?;
break :blk plan9.data_nav_table.get(nav_index).?;
}
};
}
@ -241,11 +217,11 @@ pub const DebugInfoOutput = struct {
pc_quanta: u8,
};
const DeclMetadata = struct {
const NavMetadata = struct {
index: Atom.Index,
exports: std.ArrayListUnmanaged(usize) = .{},
fn getExport(m: DeclMetadata, p9: *const Plan9, name: []const u8) ?usize {
fn getExport(m: NavMetadata, p9: *const Plan9, name: []const u8) ?usize {
for (m.exports.items) |exp| {
const sym = p9.syms.items[exp];
if (mem.eql(u8, name, sym.name)) return exp;
@ -254,7 +230,7 @@ const DeclMetadata = struct {
}
};
const FnDeclOutput = struct {
const FnNavOutput = struct {
/// this code is modified when relocated so it is mutable
code: []u8,
/// this might have to be modified in the linker, so thats why its mutable
@ -338,18 +314,18 @@ pub fn createEmpty(
return self;
}
fn putFn(self: *Plan9, decl_index: InternPool.DeclIndex, out: FnDeclOutput) !void {
fn putFn(self: *Plan9, nav_index: InternPool.Nav.Index, out: FnNavOutput) !void {
const gpa = self.base.comp.gpa;
const mod = self.base.comp.module.?;
const decl = mod.declPtr(decl_index);
const fn_map_res = try self.fn_decl_table.getOrPut(gpa, decl.getFileScope(mod));
const file_scope = mod.navFileScopeIndex(nav_index);
const fn_map_res = try self.fn_nav_table.getOrPut(gpa, file_scope);
if (fn_map_res.found_existing) {
if (try fn_map_res.value_ptr.functions.fetchPut(gpa, decl_index, out)) |old_entry| {
if (try fn_map_res.value_ptr.functions.fetchPut(gpa, nav_index, out)) |old_entry| {
gpa.free(old_entry.value.code);
gpa.free(old_entry.value.lineinfo);
}
} else {
const file = decl.getFileScope(mod);
const file = mod.fileByIndex(file_scope);
const arena = self.path_arena.allocator();
// each file gets a symbol
fn_map_res.value_ptr.* = .{
@ -359,7 +335,7 @@ fn putFn(self: *Plan9, decl_index: InternPool.DeclIndex, out: FnDeclOutput) !voi
break :blk @as(u32, @intCast(self.syms.items.len - 1));
},
};
try fn_map_res.value_ptr.functions.put(gpa, decl_index, out);
try fn_map_res.value_ptr.functions.put(gpa, nav_index, out);
var a = std.ArrayList(u8).init(arena);
errdefer a.deinit();
@ -418,11 +394,8 @@ pub fn updateFunc(self: *Plan9, pt: Zcu.PerThread, func_index: InternPool.Index,
const gpa = mod.gpa;
const target = self.base.comp.root_mod.resolved_target.result;
const func = mod.funcInfo(func_index);
const decl_index = func.owner_decl;
const decl = mod.declPtr(decl_index);
self.freeUnnamedConsts(decl_index);
const atom_idx = try self.seeDecl(decl_index);
const atom_idx = try self.seeNav(pt, func.owner_nav);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
@ -439,7 +412,7 @@ pub fn updateFunc(self: *Plan9, pt: Zcu.PerThread, func_index: InternPool.Index,
const res = try codegen.generateFunction(
&self.base,
pt,
decl.navSrcLoc(mod),
mod.navSrcLoc(func.owner_nav),
func_index,
air,
liveness,
@ -449,128 +422,72 @@ pub fn updateFunc(self: *Plan9, pt: Zcu.PerThread, func_index: InternPool.Index,
const code = switch (res) {
.ok => try code_buffer.toOwnedSlice(),
.fail => |em| {
func.setAnalysisState(&mod.intern_pool, .codegen_failure);
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
try mod.failed_codegen.put(gpa, func.owner_nav, em);
return;
},
};
self.getAtomPtr(atom_idx).code = .{
.code_ptr = null,
.other = .{ .decl_index = decl_index },
.other = .{ .nav_index = func.owner_nav },
};
const out: FnDeclOutput = .{
const out: FnNavOutput = .{
.code = code,
.lineinfo = try dbg_info_output.dbg_line.toOwnedSlice(),
.start_line = dbg_info_output.start_line.?,
.end_line = dbg_info_output.end_line,
};
try self.putFn(decl_index, out);
return self.updateFinish(decl_index);
try self.putFn(func.owner_nav, out);
return self.updateFinish(pt, func.owner_nav);
}
pub fn lowerUnnamedConst(self: *Plan9, pt: Zcu.PerThread, val: Value, decl_index: InternPool.DeclIndex) !u32 {
const mod = pt.zcu;
const gpa = mod.gpa;
_ = try self.seeDecl(decl_index);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
const decl = mod.declPtr(decl_index);
const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
const unnamed_consts = gop.value_ptr;
const index = unnamed_consts.items.len;
// name is freed when the unnamed const is freed
const name = try std.fmt.allocPrint(gpa, "__unnamed_{}_{d}", .{ decl.fqn.fmt(&mod.intern_pool), index });
const sym_index = try self.allocateSymbolIndex();
const new_atom_idx = try self.createAtom();
const info: Atom = .{
.type = .d,
.offset = null,
.sym_index = sym_index,
.got_index = self.allocateGotIndex(),
.code = undefined, // filled in later
};
const sym: aout.Sym = .{
.value = undefined,
.type = info.type,
.name = name,
};
self.syms.items[info.sym_index.?] = sym;
const res = try codegen.generateSymbol(&self.base, pt, decl.navSrcLoc(mod), val, &code_buffer, .{
.none = {},
}, .{
.parent_atom_index = new_atom_idx,
});
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
log.err("{s}", .{em.msg});
return error.CodegenFail;
pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
const zcu = pt.zcu;
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
const nav_val = zcu.navValue(nav_index);
const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
.variable => |variable| Value.fromInterned(variable.init),
.@"extern" => {
log.debug("found extern decl: {}", .{nav.name.fmt(ip)});
return;
},
else => nav_val,
};
// duped_code is freed when the unnamed const is freed
const duped_code = try gpa.dupe(u8, code);
errdefer gpa.free(duped_code);
const new_atom = self.getAtomPtr(new_atom_idx);
new_atom.* = info;
new_atom.code = .{ .code_ptr = duped_code.ptr, .other = .{ .code_len = duped_code.len } };
try unnamed_consts.append(gpa, new_atom_idx);
// we return the new_atom_idx to codegen
return new_atom_idx;
}
pub fn updateDecl(self: *Plan9, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
const gpa = self.base.comp.gpa;
const mod = pt.zcu;
const decl = mod.declPtr(decl_index);
if (decl.isExtern(mod)) {
log.debug("found extern decl: {}", .{decl.name.fmt(&mod.intern_pool)});
return;
}
const atom_idx = try self.seeDecl(decl_index);
const atom_idx = try self.seeNav(pt, nav_index);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
// TODO we need the symbol index for symbol in the table of locals for the containing atom
const res = try codegen.generateSymbol(&self.base, pt, decl.navSrcLoc(mod), decl_val, &code_buffer, .{ .none = {} }, .{
.parent_atom_index = @as(Atom.Index, @intCast(atom_idx)),
const res = try codegen.generateSymbol(&self.base, pt, zcu.navSrcLoc(nav_index), nav_init, &code_buffer, .none, .{
.parent_atom_index = @intCast(atom_idx),
});
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
try zcu.failed_codegen.put(gpa, nav_index, em);
return;
},
};
try self.data_decl_table.ensureUnusedCapacity(gpa, 1);
try self.data_nav_table.ensureUnusedCapacity(gpa, 1);
const duped_code = try gpa.dupe(u8, code);
self.getAtomPtr(self.decls.get(decl_index).?.index).code = .{ .code_ptr = null, .other = .{ .decl_index = decl_index } };
if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| {
self.getAtomPtr(self.navs.get(nav_index).?.index).code = .{ .code_ptr = null, .other = .{ .nav_index = nav_index } };
if (self.data_nav_table.fetchPutAssumeCapacity(nav_index, duped_code)) |old_entry| {
gpa.free(old_entry.value);
}
return self.updateFinish(decl_index);
return self.updateFinish(pt, nav_index);
}
/// called at the end of update{Decl,Func}
fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {
const gpa = self.base.comp.gpa;
const mod = self.base.comp.module.?;
const decl = mod.declPtr(decl_index);
const is_fn = (decl.typeOf(mod).zigTypeTag(mod) == .Fn);
fn updateFinish(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
const zcu = pt.zcu;
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
const is_fn = ip.isFunctionType(nav.typeOf(ip));
const sym_t: aout.Sym.Type = if (is_fn) .t else .d;
const atom = self.getAtomPtr(self.decls.get(decl_index).?.index);
const atom = self.getAtomPtr(self.navs.get(nav_index).?.index);
// write the internal linker metadata
atom.type = sym_t;
// write the symbol
@ -578,7 +495,7 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {
const sym: aout.Sym = .{
.value = undefined, // the value of stuff gets filled in in flushModule
.type = atom.type,
.name = try gpa.dupe(u8, decl.name.toSlice(&mod.intern_pool)),
.name = try gpa.dupe(u8, nav.name.toSlice(ip)),
};
if (atom.sym_index) |s| {
@ -643,29 +560,24 @@ fn externCount(self: *Plan9) usize {
}
return extern_atom_count;
}
// counts decls, unnamed consts, and lazy syms
// counts decls, and lazy syms
fn atomCount(self: *Plan9) usize {
var fn_decl_count: usize = 0;
var itf_files = self.fn_decl_table.iterator();
var fn_nav_count: usize = 0;
var itf_files = self.fn_nav_table.iterator();
while (itf_files.next()) |ent| {
// get the submap
var submap = ent.value_ptr.functions;
fn_decl_count += submap.count();
}
const data_decl_count = self.data_decl_table.count();
var unnamed_const_count: usize = 0;
var it_unc = self.unnamed_const_atoms.iterator();
while (it_unc.next()) |unnamed_consts| {
unnamed_const_count += unnamed_consts.value_ptr.items.len;
fn_nav_count += submap.count();
}
const data_nav_count = self.data_nav_table.count();
var lazy_atom_count: usize = 0;
var it_lazy = self.lazy_syms.iterator();
while (it_lazy.next()) |kv| {
lazy_atom_count += kv.value_ptr.numberOfAtoms();
}
const anon_atom_count = self.anon_decls.count();
const uav_atom_count = self.uavs.count();
const extern_atom_count = self.externCount();
return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count + extern_atom_count + anon_atom_count;
return data_nav_count + fn_nav_count + lazy_atom_count + extern_atom_count + uav_atom_count;
}
pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
@ -700,7 +612,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
// anyerror needs to wait for everything to be flushed.
if (metadata.text_state != .unused) self.updateLazySymbolAtom(
pt,
File.LazySymbol.initDecl(.code, null, pt.zcu),
.{ .kind = .code, .ty = .anyerror_type },
metadata.text_atom,
) catch |err| return switch (err) {
error.CodegenFail => error.FlushFailure,
@ -708,7 +620,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
};
if (metadata.rodata_state != .unused) self.updateLazySymbolAtom(
pt,
File.LazySymbol.initDecl(.const_data, null, pt.zcu),
.{ .kind = .const_data, .ty = .anyerror_type },
metadata.rodata_atom,
) catch |err| return switch (err) {
error.CodegenFail => error.FlushFailure,
@ -734,7 +646,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
var hdr_buf: [40]u8 = undefined;
// account for the fat header
const hdr_size = if (self.sixtyfour_bit) @as(usize, 40) else 32;
const hdr_size: usize = if (self.sixtyfour_bit) 40 else 32;
const hdr_slice: []u8 = hdr_buf[0..hdr_size];
var foff = hdr_size;
iovecs[0] = .{ .base = hdr_slice.ptr, .len = hdr_slice.len };
@ -746,13 +658,13 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
// text
{
var linecount: i64 = -1;
var it_file = self.fn_decl_table.iterator();
var it_file = self.fn_nav_table.iterator();
while (it_file.next()) |fentry| {
var it = fentry.value_ptr.functions.iterator();
while (it.next()) |entry| {
const decl_index = entry.key_ptr.*;
const decl = pt.zcu.declPtr(decl_index);
const atom = self.getAtomPtr(self.decls.get(decl_index).?.index);
const nav_index = entry.key_ptr.*;
const nav = pt.zcu.intern_pool.getNav(nav_index);
const atom = self.getAtomPtr(self.navs.get(nav_index).?.index);
const out = entry.value_ptr.*;
{
// connect the previous decl to the next
@ -771,15 +683,15 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
const off = self.getAddr(text_i, .t);
text_i += out.code.len;
atom.offset = off;
log.debug("write text decl {*} ({}), lines {d} to {d}.;__GOT+0x{x} vaddr: 0x{x}", .{ decl, decl.name.fmt(&pt.zcu.intern_pool), out.start_line + 1, out.end_line, atom.got_index.? * 8, off });
log.debug("write text nav 0x{x} ({}), lines {d} to {d}.;__GOT+0x{x} vaddr: 0x{x}", .{ nav_index, nav.name.fmt(&pt.zcu.intern_pool), out.start_line + 1, out.end_line, atom.got_index.? * 8, off });
if (!self.sixtyfour_bit) {
mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(off)), target.cpu.arch.endian());
mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(off), target.cpu.arch.endian());
} else {
mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
}
self.syms.items[atom.sym_index.?].value = off;
if (self.decl_exports.get(decl_index)) |export_indices| {
try self.addDeclExports(pt.zcu, decl_index, export_indices);
if (self.nav_exports.get(nav_index)) |export_indices| {
try self.addNavExports(pt.zcu, nav_index, export_indices);
}
}
}
@ -826,10 +738,10 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
// data
var data_i: u64 = got_size;
{
var it = self.data_decl_table.iterator();
var it = self.data_nav_table.iterator();
while (it.next()) |entry| {
const decl_index = entry.key_ptr.*;
const atom = self.getAtomPtr(self.decls.get(decl_index).?.index);
const nav_index = entry.key_ptr.*;
const atom = self.getAtomPtr(self.navs.get(nav_index).?.index);
const code = entry.value_ptr.*;
foff += code.len;
@ -844,35 +756,13 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
}
self.syms.items[atom.sym_index.?].value = off;
if (self.decl_exports.get(decl_index)) |export_indices| {
try self.addDeclExports(pt.zcu, decl_index, export_indices);
if (self.nav_exports.get(nav_index)) |export_indices| {
try self.addNavExports(pt.zcu, nav_index, export_indices);
}
}
// write the unnamed constants after the other data decls
var it_unc = self.unnamed_const_atoms.iterator();
while (it_unc.next()) |unnamed_consts| {
for (unnamed_consts.value_ptr.items) |atom_idx| {
const atom = self.getAtomPtr(atom_idx);
const code = atom.code.getOwnedCode().?; // unnamed consts must own their code
log.debug("write unnamed const: ({s})", .{self.syms.items[atom.sym_index.?].name});
foff += code.len;
iovecs[iovecs_i] = .{ .base = code.ptr, .len = code.len };
iovecs_i += 1;
const off = self.getAddr(data_i, .d);
data_i += code.len;
atom.offset = off;
if (!self.sixtyfour_bit) {
mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(off)), target.cpu.arch.endian());
} else {
mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
}
self.syms.items[atom.sym_index.?].value = off;
}
}
// the anon decls
{
var it_anon = self.anon_decls.iterator();
while (it_anon.next()) |kv| {
var it_uav = self.uavs.iterator();
while (it_uav.next()) |kv| {
const atom = self.getAtomPtr(kv.value_ptr.*);
const code = atom.code.getOwnedCode().?;
log.debug("write anon decl: {s}", .{self.syms.items[atom.sym_index.?].name});
@ -1011,14 +901,14 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
// write it all!
try file.pwritevAll(iovecs, 0);
}
fn addDeclExports(
fn addNavExports(
self: *Plan9,
mod: *Zcu,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
export_indices: []const u32,
) !void {
const gpa = self.base.comp.gpa;
const metadata = self.decls.getPtr(decl_index).?;
const metadata = self.navs.getPtr(nav_index).?;
const atom = self.getAtom(metadata.index);
for (export_indices) |export_idx| {
@ -1031,7 +921,7 @@ fn addDeclExports(
{
try mod.failed_exports.put(mod.gpa, export_idx, try Zcu.ErrorMsg.create(
gpa,
mod.declPtr(decl_index).navSrcLoc(mod),
mod.navSrcLoc(nav_index),
"plan9 does not support extra sections",
.{},
));
@ -1090,7 +980,6 @@ pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void {
}
kv.value.exports.deinit(gpa);
}
self.freeUnnamedConsts(decl_index);
{
const atom_index = self.decls.get(decl_index).?.index;
const relocs = self.relocs.getPtr(atom_index) orelse return;
@ -1098,18 +987,6 @@ pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void {
assert(self.relocs.remove(atom_index));
}
}
fn freeUnnamedConsts(self: *Plan9, decl_index: InternPool.DeclIndex) void {
const gpa = self.base.comp.gpa;
const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
for (unnamed_consts.items) |atom_idx| {
const atom = self.getAtom(atom_idx);
gpa.free(self.syms.items[atom.sym_index.?].name);
self.syms.items[atom.sym_index.?] = aout.Sym.undefined_symbol;
self.syms_index_free_list.append(gpa, atom.sym_index.?) catch {};
}
unnamed_consts.clearAndFree(gpa);
}
fn createAtom(self: *Plan9) !Atom.Index {
const gpa = self.base.comp.gpa;
const index = @as(Atom.Index, @intCast(self.atoms.items.len));
@ -1124,9 +1001,11 @@ fn createAtom(self: *Plan9) !Atom.Index {
return index;
}
pub fn seeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) !Atom.Index {
const gpa = self.base.comp.gpa;
const gop = try self.decls.getOrPut(gpa, decl_index);
pub fn seeNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !Atom.Index {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const gpa = zcu.gpa;
const gop = try self.navs.getOrPut(gpa, nav_index);
if (!gop.found_existing) {
const index = try self.createAtom();
self.getAtomPtr(index).got_index = self.allocateGotIndex();
@ -1137,23 +1016,22 @@ pub fn seeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) !Atom.Index {
}
const atom_idx = gop.value_ptr.index;
// handle externs here because they might not get updateDecl called on them
const mod = self.base.comp.module.?;
const decl = mod.declPtr(decl_index);
if (decl.isExtern(mod)) {
const nav = ip.getNav(nav_index);
if (ip.indexToKey(nav.status.resolved.val) == .@"extern") {
// this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs
if (decl.name.eqlSlice("etext", &mod.intern_pool)) {
if (nav.name.eqlSlice("etext", ip)) {
self.etext_edata_end_atom_indices[0] = atom_idx;
} else if (decl.name.eqlSlice("edata", &mod.intern_pool)) {
} else if (nav.name.eqlSlice("edata", ip)) {
self.etext_edata_end_atom_indices[1] = atom_idx;
} else if (decl.name.eqlSlice("end", &mod.intern_pool)) {
} else if (nav.name.eqlSlice("end", ip)) {
self.etext_edata_end_atom_indices[2] = atom_idx;
}
try self.updateFinish(decl_index);
log.debug("seeDecl(extern) for {} (got_addr=0x{x})", .{
decl.name.fmt(&mod.intern_pool),
try self.updateFinish(pt, nav_index);
log.debug("seeNav(extern) for {} (got_addr=0x{x})", .{
nav.name.fmt(ip),
self.getAtom(atom_idx).getOffsetTableAddress(self),
});
} else log.debug("seeDecl for {}", .{decl.name.fmt(&mod.intern_pool)});
} else log.debug("seeNav for {}", .{nav.name.fmt(ip)});
return atom_idx;
}
@ -1165,45 +1043,41 @@ pub fn updateExports(
) !void {
const gpa = self.base.comp.gpa;
switch (exported) {
.value => @panic("TODO: plan9 updateExports handling values"),
.decl_index => |decl_index| {
_ = try self.seeDecl(decl_index);
if (self.decl_exports.fetchSwapRemove(decl_index)) |kv| {
.uav => @panic("TODO: plan9 updateExports handling values"),
.nav => |nav| {
_ = try self.seeNav(pt, nav);
if (self.nav_exports.fetchSwapRemove(nav)) |kv| {
gpa.free(kv.value);
}
try self.decl_exports.ensureUnusedCapacity(gpa, 1);
try self.nav_exports.ensureUnusedCapacity(gpa, 1);
const duped_indices = try gpa.dupe(u32, export_indices);
self.decl_exports.putAssumeCapacityNoClobber(decl_index, duped_indices);
self.nav_exports.putAssumeCapacityNoClobber(nav, duped_indices);
},
}
// all proper work is done in flush
_ = pt;
}
pub fn getOrCreateAtomForLazySymbol(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol) !Atom.Index {
const gpa = pt.zcu.gpa;
const gop = try self.lazy_syms.getOrPut(gpa, sym.getDecl(self.base.comp.module.?));
pub fn getOrCreateAtomForLazySymbol(self: *Plan9, pt: Zcu.PerThread, lazy_sym: File.LazySymbol) !Atom.Index {
const gop = try self.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty);
errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
if (!gop.found_existing) gop.value_ptr.* = .{};
const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
.code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
.const_data => .{ .atom = &gop.value_ptr.rodata_atom, .state = &gop.value_ptr.rodata_state },
const atom_ptr, const state_ptr = switch (lazy_sym.kind) {
.code => .{ &gop.value_ptr.text_atom, &gop.value_ptr.text_state },
.const_data => .{ &gop.value_ptr.rodata_atom, &gop.value_ptr.rodata_state },
};
switch (metadata.state.*) {
.unused => metadata.atom.* = try self.createAtom(),
.pending_flush => return metadata.atom.*,
switch (state_ptr.*) {
.unused => atom_ptr.* = try self.createAtom(),
.pending_flush => return atom_ptr.*,
.flushed => {},
}
metadata.state.* = .pending_flush;
const atom = metadata.atom.*;
state_ptr.* = .pending_flush;
const atom = atom_ptr.*;
_ = try self.getAtomPtr(atom).getOrCreateSymbolTableEntry(self);
_ = self.getAtomPtr(atom).getOrCreateOffsetTableEntry(self);
// anyerror needs to be deferred until flushModule
if (sym.getDecl(self.base.comp.module.?) != .none) {
try self.updateLazySymbolAtom(pt, sym, atom);
}
if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbolAtom(pt, lazy_sym, atom);
return atom;
}
@ -1217,7 +1091,7 @@ fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, a
// create the symbol for the name
const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
@tagName(sym.kind),
sym.ty.fmt(pt),
Type.fromInterned(sym.ty).fmt(pt),
});
const symbol: aout.Sym = .{
@ -1228,7 +1102,7 @@ fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, a
self.syms.items[self.getAtomPtr(atom_index).sym_index.?] = symbol;
// generate the code
const src = sym.ty.srcLocOrNull(pt.zcu) orelse Zcu.LazySrcLoc.unneeded;
const src = Type.fromInterned(sym.ty).srcLocOrNull(pt.zcu) orelse Zcu.LazySrcLoc.unneeded;
const res = try codegen.generateLazySymbol(
&self.base,
pt,
@ -1264,12 +1138,6 @@ pub fn deinit(self: *Plan9) void {
}
self.relocs.deinit(gpa);
}
// free the unnamed consts
var it_unc = self.unnamed_const_atoms.iterator();
while (it_unc.next()) |kv| {
self.freeUnnamedConsts(kv.key_ptr.*);
}
self.unnamed_const_atoms.deinit(gpa);
var it_lzc = self.lazy_syms.iterator();
while (it_lzc.next()) |kv| {
if (kv.value_ptr.text_state != .unused)
@ -1278,7 +1146,7 @@ pub fn deinit(self: *Plan9) void {
gpa.free(self.syms.items[self.getAtom(kv.value_ptr.rodata_atom).sym_index.?].name);
}
self.lazy_syms.deinit(gpa);
var itf_files = self.fn_decl_table.iterator();
var itf_files = self.fn_nav_table.iterator();
while (itf_files.next()) |ent| {
// get the submap
var submap = ent.value_ptr.functions;
@ -1289,21 +1157,21 @@ pub fn deinit(self: *Plan9) void {
gpa.free(entry.value_ptr.lineinfo);
}
}
self.fn_decl_table.deinit(gpa);
var itd = self.data_decl_table.iterator();
self.fn_nav_table.deinit(gpa);
var itd = self.data_nav_table.iterator();
while (itd.next()) |entry| {
gpa.free(entry.value_ptr.*);
}
var it_anon = self.anon_decls.iterator();
while (it_anon.next()) |entry| {
var it_uav = self.uavs.iterator();
while (it_uav.next()) |entry| {
const sym_index = self.getAtom(entry.value_ptr.*).sym_index.?;
gpa.free(self.syms.items[sym_index].name);
}
self.data_decl_table.deinit(gpa);
for (self.decl_exports.values()) |export_indices| {
self.data_nav_table.deinit(gpa);
for (self.nav_exports.values()) |export_indices| {
gpa.free(export_indices);
}
self.decl_exports.deinit(gpa);
self.nav_exports.deinit(gpa);
self.syms.deinit(gpa);
self.got_index_free_list.deinit(gpa);
self.syms_index_free_list.deinit(gpa);
@ -1317,11 +1185,11 @@ pub fn deinit(self: *Plan9) void {
self.atoms.deinit(gpa);
{
var it = self.decls.iterator();
var it = self.navs.iterator();
while (it.next()) |entry| {
entry.value_ptr.exports.deinit(gpa);
}
self.decls.deinit(gpa);
self.navs.deinit(gpa);
}
}
@ -1402,17 +1270,17 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
// write the data symbols
{
var it = self.data_decl_table.iterator();
var it = self.data_nav_table.iterator();
while (it.next()) |entry| {
const decl_index = entry.key_ptr.*;
const decl_metadata = self.decls.get(decl_index).?;
const atom = self.getAtom(decl_metadata.index);
const nav_index = entry.key_ptr.*;
const nav_metadata = self.navs.get(nav_index).?;
const atom = self.getAtom(nav_metadata.index);
const sym = self.syms.items[atom.sym_index.?];
try self.writeSym(writer, sym);
if (self.decl_exports.get(decl_index)) |export_indices| {
if (self.nav_exports.get(nav_index)) |export_indices| {
for (export_indices) |export_idx| {
const exp = mod.all_exports.items[export_idx];
if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
if (nav_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
try self.writeSym(writer, self.syms.items[exp_i]);
}
}
@ -1429,22 +1297,11 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
try self.writeSym(writer, sym);
}
}
// unnamed consts
{
var it = self.unnamed_const_atoms.iterator();
while (it.next()) |kv| {
const consts = kv.value_ptr;
for (consts.items) |atom_index| {
const sym = self.syms.items[self.getAtom(atom_index).sym_index.?];
try self.writeSym(writer, sym);
}
}
}
// text symbols are the hardest:
// the file of a text symbol is the .z symbol before it
// so we have to write everything in the right order
{
var it_file = self.fn_decl_table.iterator();
var it_file = self.fn_nav_table.iterator();
while (it_file.next()) |fentry| {
var symidx_and_submap = fentry.value_ptr;
// write the z symbols
@ -1454,15 +1311,15 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
// write all the decls come from the file of the z symbol
var submap_it = symidx_and_submap.functions.iterator();
while (submap_it.next()) |entry| {
const decl_index = entry.key_ptr.*;
const decl_metadata = self.decls.get(decl_index).?;
const atom = self.getAtom(decl_metadata.index);
const nav_index = entry.key_ptr.*;
const nav_metadata = self.navs.get(nav_index).?;
const atom = self.getAtom(nav_metadata.index);
const sym = self.syms.items[atom.sym_index.?];
try self.writeSym(writer, sym);
if (self.decl_exports.get(decl_index)) |export_indices| {
if (self.nav_exports.get(nav_index)) |export_indices| {
for (export_indices) |export_idx| {
const exp = mod.all_exports.items[export_idx];
if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
if (nav_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
const s = self.syms.items[exp_i];
if (mem.eql(u8, s.name, "_start"))
self.entry_val = s.value;
@ -1500,31 +1357,31 @@ pub fn updateDeclLineNumber(self: *Plan9, pt: Zcu.PerThread, decl_index: InternP
_ = decl_index;
}
pub fn getDeclVAddr(
pub fn getNavVAddr(
self: *Plan9,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
reloc_info: link.File.RelocInfo,
) !u64 {
const ip = &pt.zcu.intern_pool;
const decl = pt.zcu.declPtr(decl_index);
log.debug("getDeclVAddr for {}", .{decl.name.fmt(ip)});
if (decl.isExtern(pt.zcu)) {
if (decl.name.eqlSlice("etext", ip)) {
const nav = ip.getNav(nav_index);
log.debug("getDeclVAddr for {}", .{nav.name.fmt(ip)});
if (ip.indexToKey(nav.status.resolved.val) == .@"extern") {
if (nav.name.eqlSlice("etext", ip)) {
try self.addReloc(reloc_info.parent_atom_index, .{
.target = undefined,
.offset = reloc_info.offset,
.addend = reloc_info.addend,
.type = .special_etext,
});
} else if (decl.name.eqlSlice("edata", ip)) {
} else if (nav.name.eqlSlice("edata", ip)) {
try self.addReloc(reloc_info.parent_atom_index, .{
.target = undefined,
.offset = reloc_info.offset,
.addend = reloc_info.addend,
.type = .special_edata,
});
} else if (decl.name.eqlSlice("end", ip)) {
} else if (nav.name.eqlSlice("end", ip)) {
try self.addReloc(reloc_info.parent_atom_index, .{
.target = undefined,
.offset = reloc_info.offset,
@ -1536,7 +1393,7 @@ pub fn getDeclVAddr(
return undefined;
}
// otherwise, we just add a relocation
const atom_index = try self.seeDecl(decl_index);
const atom_index = try self.seeNav(pt, nav_index);
// the parent_atom_index in this case is just the decl_index of the parent
try self.addReloc(reloc_info.parent_atom_index, .{
.target = atom_index,
@ -1546,15 +1403,14 @@ pub fn getDeclVAddr(
return undefined;
}
pub fn lowerAnonDecl(
pub fn lowerUav(
self: *Plan9,
pt: Zcu.PerThread,
decl_val: InternPool.Index,
uav: InternPool.Index,
explicit_alignment: InternPool.Alignment,
src_loc: Zcu.LazySrcLoc,
) !codegen.Result {
) !codegen.GenResult {
_ = explicit_alignment;
// This is basically the same as lowerUnnamedConst.
// example:
// const ty = mod.intern_pool.typeOf(decl_val).toType();
// const val = decl_val.toValue();
@ -1564,41 +1420,40 @@ pub fn lowerAnonDecl(
// to put it in some location.
// ...
const gpa = self.base.comp.gpa;
const gop = try self.anon_decls.getOrPut(gpa, decl_val);
if (!gop.found_existing) {
const val = Value.fromInterned(decl_val);
const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)});
const gop = try self.uavs.getOrPut(gpa, uav);
if (gop.found_existing) return .{ .mcv = .{ .load_direct = gop.value_ptr.* } };
const val = Value.fromInterned(uav);
const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(uav)});
const index = try self.createAtom();
const got_index = self.allocateGotIndex();
gop.value_ptr.* = index;
// we need to free name latex
var code_buffer = std.ArrayList(u8).init(gpa);
const res = try codegen.generateSymbol(&self.base, pt, src_loc, val, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = index });
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| return .{ .fail = em },
};
const atom_ptr = self.getAtomPtr(index);
atom_ptr.* = .{
.type = .d,
.offset = undefined,
.sym_index = null,
.got_index = got_index,
.code = Atom.CodePtr.fromSlice(code),
};
_ = try atom_ptr.getOrCreateSymbolTableEntry(self);
self.syms.items[atom_ptr.sym_index.?] = .{
.type = .d,
.value = undefined,
.name = name,
};
}
return .ok;
const index = try self.createAtom();
const got_index = self.allocateGotIndex();
gop.value_ptr.* = index;
// we need to free name latex
var code_buffer = std.ArrayList(u8).init(gpa);
const res = try codegen.generateSymbol(&self.base, pt, src_loc, val, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = index });
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| return .{ .fail = em },
};
const atom_ptr = self.getAtomPtr(index);
atom_ptr.* = .{
.type = .d,
.offset = undefined,
.sym_index = null,
.got_index = got_index,
.code = Atom.CodePtr.fromSlice(code),
};
_ = try atom_ptr.getOrCreateSymbolTableEntry(self);
self.syms.items[atom_ptr.sym_index.?] = .{
.type = .d,
.value = undefined,
.name = name,
};
return .{ .mcv = .{ .load_direct = index } };
}
pub fn getAnonDeclVAddr(self: *Plan9, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
const atom_index = self.anon_decls.get(decl_val).?;
pub fn getUavVAddr(self: *Plan9, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
const atom_index = self.uavs.get(uav).?;
try self.addReloc(reloc_info.parent_atom_index, .{
.target = atom_index,
.offset = reloc_info.offset,

View File

@ -36,6 +36,7 @@ const trace = @import("../tracy.zig").trace;
const build_options = @import("build_options");
const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
const Type = @import("../Type.zig");
const Value = @import("../Value.zig");
const SpvModule = @import("../codegen/spirv/Module.zig");
@ -50,8 +51,6 @@ base: link.File,
object: codegen.Object,
pub const base_tag: link.File.Tag = .spirv;
pub fn createEmpty(
arena: Allocator,
comp: *Compilation,
@ -128,22 +127,22 @@ pub fn updateFunc(self: *SpirV, pt: Zcu.PerThread, func_index: InternPool.Index,
@panic("Attempted to compile for architecture that was disabled by build configuration");
}
const ip = &pt.zcu.intern_pool;
const func = pt.zcu.funcInfo(func_index);
const decl = pt.zcu.declPtr(func.owner_decl);
log.debug("lowering function {}", .{decl.name.fmt(&pt.zcu.intern_pool)});
log.debug("lowering function {}", .{ip.getNav(func.owner_nav).name.fmt(ip)});
try self.object.updateFunc(pt, func_index, air, liveness);
}
pub fn updateDecl(self: *SpirV, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
pub fn updateNav(self: *SpirV, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {
if (build_options.skip_non_native) {
@panic("Attempted to compile for architecture that was disabled by build configuration");
}
const decl = pt.zcu.declPtr(decl_index);
log.debug("lowering declaration {}", .{decl.name.fmt(&pt.zcu.intern_pool)});
const ip = &pt.zcu.intern_pool;
log.debug("lowering declaration {}", .{ip.getNav(nav).name.fmt(ip)});
try self.object.updateDecl(pt, decl_index);
try self.object.updateNav(pt, nav);
}
pub fn updateExports(
@ -152,19 +151,20 @@ pub fn updateExports(
exported: Zcu.Exported,
export_indices: []const u32,
) !void {
const mod = pt.zcu;
const decl_index = switch (exported) {
.decl_index => |i| i,
.value => |val| {
_ = val;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav_index = switch (exported) {
.nav => |nav| nav,
.uav => |uav| {
_ = uav;
@panic("TODO: implement SpirV linker code for exporting a constant value");
},
};
const decl = mod.declPtr(decl_index);
if (decl.val.isFuncBody(mod)) {
const target = mod.getTarget();
const spv_decl_index = try self.object.resolveDecl(mod, decl_index);
const execution_model = switch (decl.typeOf(mod).fnCallingConvention(mod)) {
const nav_ty = ip.getNav(nav_index).typeOf(ip);
if (ip.isFunctionType(nav_ty)) {
const target = zcu.getTarget();
const spv_decl_index = try self.object.resolveNav(zcu, nav_index);
const execution_model = switch (Type.fromInterned(nav_ty).fnCallingConvention(zcu)) {
.Vertex => spec.ExecutionModel.Vertex,
.Fragment => spec.ExecutionModel.Fragment,
.Kernel => spec.ExecutionModel.Kernel,
@ -177,10 +177,10 @@ pub fn updateExports(
(is_vulkan and (execution_model == .Fragment or execution_model == .Vertex)))
{
for (export_indices) |export_idx| {
const exp = mod.all_exports.items[export_idx];
const exp = zcu.all_exports.items[export_idx];
try self.object.spv.declareEntryPoint(
spv_decl_index,
exp.opts.name.toSlice(&mod.intern_pool),
exp.opts.name.toSlice(ip),
execution_model,
);
}

View File

@ -39,8 +39,6 @@ const ZigObject = @import("Wasm/ZigObject.zig");
pub const Atom = @import("Wasm/Atom.zig");
pub const Relocation = types.Relocation;
pub const base_tag: link.File.Tag = .wasm;
base: link.File,
/// Symbol name of the entry function to export
entry_name: ?[]const u8,
@ -1451,19 +1449,19 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index,
try wasm.zigObjectPtr().?.updateFunc(wasm, pt, func_index, air, liveness);
}
// Generate code for the Decl, storing it in memory to be later written to
// Generate code for the "Nav", storing it in memory to be later written to
// the file on flush().
pub fn updateDecl(wasm: *Wasm, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {
if (build_options.skip_non_native and builtin.object_format != .wasm) {
@panic("Attempted to compile for object format that was disabled by build configuration");
}
if (wasm.llvm_object) |llvm_object| return llvm_object.updateDecl(pt, decl_index);
try wasm.zigObjectPtr().?.updateDecl(wasm, pt, decl_index);
if (wasm.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav);
try wasm.zigObjectPtr().?.updateNav(wasm, pt, nav);
}
pub fn updateDeclLineNumber(wasm: *Wasm, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
pub fn updateNavLineNumber(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {
if (wasm.llvm_object) |_| return;
try wasm.zigObjectPtr().?.updateDeclLineNumber(pt, decl_index);
try wasm.zigObjectPtr().?.updateNavLineNumber(pt, nav);
}
/// From a given symbol location, returns its `wasm.GlobalType`.
@ -1505,13 +1503,6 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
return wasm.func_types.items[wasm.functions.get(.{ .file = loc.file, .index = symbol.index }).?.func.type_index];
}
/// Lowers a constant typed value to a local symbol and atom.
/// Returns the symbol index of the local
/// The given `decl` is the parent decl whom owns the constant.
pub fn lowerUnnamedConst(wasm: *Wasm, pt: Zcu.PerThread, val: Value, decl_index: InternPool.DeclIndex) !u32 {
return wasm.zigObjectPtr().?.lowerUnnamedConst(wasm, pt, val, decl_index);
}
/// Returns the symbol index from a symbol of which its flag is set global,
/// such as an exported or imported symbol.
/// If the symbol does not yet exist, creates a new one symbol instead
@ -1521,29 +1512,29 @@ pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Sy
return wasm.zigObjectPtr().?.getGlobalSymbol(wasm.base.comp.gpa, name);
}
/// For a given decl, find the given symbol index's atom, and create a relocation for the type.
/// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type.
/// Returns the given pointer address
pub fn getDeclVAddr(
pub fn getNavVAddr(
wasm: *Wasm,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav: InternPool.Nav.Index,
reloc_info: link.File.RelocInfo,
) !u64 {
return wasm.zigObjectPtr().?.getDeclVAddr(wasm, pt, decl_index, reloc_info);
return wasm.zigObjectPtr().?.getNavVAddr(wasm, pt, nav, reloc_info);
}
pub fn lowerAnonDecl(
pub fn lowerUav(
wasm: *Wasm,
pt: Zcu.PerThread,
decl_val: InternPool.Index,
uav: InternPool.Index,
explicit_alignment: Alignment,
src_loc: Zcu.LazySrcLoc,
) !codegen.Result {
return wasm.zigObjectPtr().?.lowerAnonDecl(wasm, pt, decl_val, explicit_alignment, src_loc);
) !codegen.GenResult {
return wasm.zigObjectPtr().?.lowerUav(wasm, pt, uav, explicit_alignment, src_loc);
}
pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
return wasm.zigObjectPtr().?.getAnonDeclVAddr(wasm, decl_val, reloc_info);
pub fn getUavVAddr(wasm: *Wasm, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
return wasm.zigObjectPtr().?.getUavVAddr(wasm, uav, reloc_info);
}
pub fn deleteExport(
@ -4018,11 +4009,11 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {
return index;
}
/// For the given `decl_index`, stores the corresponding type representing the function signature.
/// For the given `nav`, stores the corresponding type representing the function signature.
/// Asserts declaration has an associated `Atom`.
/// Returns the index into the list of types.
pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 {
return wasm.zigObjectPtr().?.storeDeclType(wasm.base.comp.gpa, decl_index, func_type);
pub fn storeNavType(wasm: *Wasm, nav: InternPool.Nav.Index, func_type: std.wasm.Type) !u32 {
return wasm.zigObjectPtr().?.storeDeclType(wasm.base.comp.gpa, nav, func_type);
}
/// Returns the symbol index of the error name table.
@ -4036,8 +4027,8 @@ pub fn getErrorTableSymbol(wasm_file: *Wasm, pt: Zcu.PerThread) !u32 {
/// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`.
/// When the index was not found, a new `Atom` will be created, and its index will be returned.
/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
pub fn getOrCreateAtomForDecl(wasm_file: *Wasm, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !Atom.Index {
return wasm_file.zigObjectPtr().?.getOrCreateAtomForDecl(wasm_file, pt, decl_index);
pub fn getOrCreateAtomForNav(wasm_file: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !Atom.Index {
return wasm_file.zigObjectPtr().?.getOrCreateAtomForNav(wasm_file, pt, nav);
}
/// Verifies all resolved symbols and checks whether itself needs to be marked alive,

View File

@ -6,9 +6,9 @@
path: []const u8,
/// Index within the list of relocatable objects of the linker driver.
index: File.Index,
/// Map of all `Decl` that are currently alive.
/// Each index maps to the corresponding `DeclInfo`.
decls_map: std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclInfo) = .{},
/// Map of all `Nav` that are currently alive.
/// Each index maps to the corresponding `NavInfo`.
navs: std.AutoHashMapUnmanaged(InternPool.Nav.Index, NavInfo) = .{},
/// List of function type signatures for this Zig module.
func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{},
/// List of `std.wasm.Func`. Each entry contains the function signature,
@ -36,7 +36,7 @@ segment_free_list: std.ArrayListUnmanaged(u32) = .{},
/// File encapsulated string table, used to deduplicate strings within the generated file.
string_table: StringTable = .{},
/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
/// List of atom indexes of functions that are generated by the backend.
synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},
/// Represents the symbol index of the error name table
@ -86,12 +86,12 @@ debug_str_index: ?u32 = null,
/// The index of the segment representing the custom '.debug_pubtypes' section.
debug_abbrev_index: ?u32 = null,
const DeclInfo = struct {
const NavInfo = struct {
atom: Atom.Index = .null,
exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
fn @"export"(di: DeclInfo, zig_object: *const ZigObject, name: []const u8) ?Symbol.Index {
for (di.exports.items) |sym_index| {
fn @"export"(ni: NavInfo, zig_object: *const ZigObject, name: []const u8) ?Symbol.Index {
for (ni.exports.items) |sym_index| {
const sym_name_index = zig_object.symbol(sym_index).name;
const sym_name = zig_object.string_table.getAssumeExists(sym_name_index);
if (std.mem.eql(u8, name, sym_name)) {
@ -101,14 +101,14 @@ const DeclInfo = struct {
return null;
}
fn appendExport(di: *DeclInfo, gpa: std.mem.Allocator, sym_index: Symbol.Index) !void {
return di.exports.append(gpa, sym_index);
fn appendExport(ni: *NavInfo, gpa: std.mem.Allocator, sym_index: Symbol.Index) !void {
return ni.exports.append(gpa, sym_index);
}
fn deleteExport(di: *DeclInfo, sym_index: Symbol.Index) void {
for (di.exports.items, 0..) |idx, index| {
fn deleteExport(ni: *NavInfo, sym_index: Symbol.Index) void {
for (ni.exports.items, 0..) |idx, index| {
if (idx == sym_index) {
_ = di.exports.swapRemove(index);
_ = ni.exports.swapRemove(index);
return;
}
}
@ -155,19 +155,19 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {
}
{
var it = zig_object.decls_map.valueIterator();
while (it.next()) |decl_info| {
const atom = wasm_file.getAtomPtr(decl_info.atom);
var it = zig_object.navs.valueIterator();
while (it.next()) |nav_info| {
const atom = wasm_file.getAtomPtr(nav_info.atom);
for (atom.locals.items) |local_index| {
const local_atom = wasm_file.getAtomPtr(local_index);
local_atom.deinit(gpa);
}
atom.deinit(gpa);
decl_info.exports.deinit(gpa);
nav_info.exports.deinit(gpa);
}
}
{
for (zig_object.anon_decls.values()) |atom_index| {
for (zig_object.uavs.values()) |atom_index| {
const atom = wasm_file.getAtomPtr(atom_index);
for (atom.locals.items) |local_index| {
const local_atom = wasm_file.getAtomPtr(local_index);
@ -201,8 +201,8 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {
zig_object.atom_types.deinit(gpa);
zig_object.functions.deinit(gpa);
zig_object.imports.deinit(gpa);
zig_object.decls_map.deinit(gpa);
zig_object.anon_decls.deinit(gpa);
zig_object.navs.deinit(gpa);
zig_object.uavs.deinit(gpa);
zig_object.symbols.deinit(gpa);
zig_object.symbols_free_list.deinit(gpa);
zig_object.segment_info.deinit(gpa);
@ -236,34 +236,35 @@ pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !Symbol.In
return index;
}
// Generate code for the Decl, storing it in memory to be later written to
// Generate code for the `Nav`, storing it in memory to be later written to
// the file on flush().
pub fn updateDecl(
pub fn updateNav(
zig_object: *ZigObject,
wasm_file: *Wasm,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
) !void {
const mod = pt.zcu;
const decl = mod.declPtr(decl_index);
if (decl.val.getFunction(mod)) |_| {
return;
} else if (decl.val.getExternFunc(mod)) |_| {
return;
}
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
const is_extern, const lib_name, const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
.variable => |variable| .{ false, variable.lib_name, variable.init },
.func => return,
.@"extern" => |@"extern"| if (ip.isFunctionType(nav.typeOf(ip)))
return
else
.{ true, @"extern".lib_name, nav.status.resolved.val },
else => .{ false, .none, nav.status.resolved.val },
};
const gpa = wasm_file.base.comp.gpa;
const atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, pt, decl_index);
const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);
const atom = wasm_file.getAtomPtr(atom_index);
atom.clear();
if (decl.isExtern(mod)) {
const variable = decl.getOwnedVariable(mod).?;
const name = decl.name.toSlice(&mod.intern_pool);
const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
return zig_object.addOrUpdateImport(wasm_file, name, atom.sym_index, lib_name, null);
}
const val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
if (is_extern)
return zig_object.addOrUpdateImport(wasm_file, nav.name.toSlice(ip), atom.sym_index, lib_name.toSlice(ip), null);
var code_writer = std.ArrayList(u8).init(gpa);
defer code_writer.deinit();
@ -271,8 +272,8 @@ pub fn updateDecl(
const res = try codegen.generateSymbol(
&wasm_file.base,
pt,
decl.navSrcLoc(mod),
val,
zcu.navSrcLoc(nav_index),
Value.fromInterned(nav_init),
&code_writer,
.none,
.{ .parent_atom_index = @intFromEnum(atom.sym_index) },
@ -281,13 +282,12 @@ pub fn updateDecl(
const code = switch (res) {
.ok => code_writer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
return;
},
};
return zig_object.finishUpdateDecl(wasm_file, pt, decl_index, code);
return zig_object.finishUpdateNav(wasm_file, pt, nav_index, code);
}
pub fn updateFunc(
@ -298,11 +298,10 @@ pub fn updateFunc(
air: Air,
liveness: Liveness,
) !void {
const gpa = wasm_file.base.comp.gpa;
const zcu = pt.zcu;
const gpa = zcu.gpa;
const func = pt.zcu.funcInfo(func_index);
const decl_index = func.owner_decl;
const decl = pt.zcu.declPtr(decl_index);
const atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, pt, decl_index);
const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, func.owner_nav);
const atom = wasm_file.getAtomPtr(atom_index);
atom.clear();
@ -311,7 +310,7 @@ pub fn updateFunc(
const result = try codegen.generateFunction(
&wasm_file.base,
pt,
decl.navSrcLoc(pt.zcu),
zcu.navSrcLoc(func.owner_nav),
func_index,
air,
liveness,
@ -322,79 +321,75 @@ pub fn updateFunc(
const code = switch (result) {
.ok => code_writer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try pt.zcu.failed_analysis.put(gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
try pt.zcu.failed_codegen.put(gpa, func.owner_nav, em);
return;
},
};
return zig_object.finishUpdateDecl(wasm_file, pt, decl_index, code);
return zig_object.finishUpdateNav(wasm_file, pt, func.owner_nav, code);
}
fn finishUpdateDecl(
fn finishUpdateNav(
zig_object: *ZigObject,
wasm_file: *Wasm,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
code: []const u8,
) !void {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const gpa = zcu.gpa;
const decl = zcu.declPtr(decl_index);
const decl_info = zig_object.decls_map.get(decl_index).?;
const atom_index = decl_info.atom;
const nav = ip.getNav(nav_index);
const nav_val = zcu.navValue(nav_index);
const nav_info = zig_object.navs.get(nav_index).?;
const atom_index = nav_info.atom;
const atom = wasm_file.getAtomPtr(atom_index);
const sym = zig_object.symbol(atom.sym_index);
sym.name = try zig_object.string_table.insert(gpa, decl.fqn.toSlice(ip));
sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));
try atom.code.appendSlice(gpa, code);
atom.size = @intCast(code.len);
switch (decl.typeOf(zcu).zigTypeTag(zcu)) {
.Fn => {
sym.index = try zig_object.appendFunction(gpa, .{ .type_index = zig_object.atom_types.get(atom_index).? });
sym.tag = .function;
},
else => {
const segment_name: []const u8 = if (decl.getOwnedVariable(zcu)) |variable| name: {
if (variable.is_const) {
break :name ".rodata.";
} else if (Value.fromInterned(variable.init).isUndefDeep(zcu)) {
const decl_namespace = zcu.namespacePtr(decl.src_namespace);
const optimize_mode = decl_namespace.fileScope(zcu).mod.optimize_mode;
const is_initialized = switch (optimize_mode) {
.Debug, .ReleaseSafe => true,
.ReleaseFast, .ReleaseSmall => false,
};
if (is_initialized) {
break :name ".data.";
}
break :name ".bss.";
}
// when the decl is all zeroes, we store the atom in the bss segment,
// in all other cases it will be in the data segment.
for (atom.code.items) |byte| {
if (byte != 0) break :name ".data.";
}
break :name ".bss.";
} else ".rodata.";
if ((wasm_file.base.isObject() or wasm_file.base.comp.config.import_memory) and
std.mem.startsWith(u8, segment_name, ".bss"))
{
@memset(atom.code.items, 0);
if (ip.isFunctionType(nav.typeOf(ip))) {
sym.index = try zig_object.appendFunction(gpa, .{ .type_index = zig_object.atom_types.get(atom_index).? });
sym.tag = .function;
} else {
const is_const, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
.variable => |variable| .{ false, variable.init },
.@"extern" => |@"extern"| .{ @"extern".is_const, .none },
else => .{ true, nav_val.toIntern() },
};
const segment_name = name: {
if (is_const) break :name ".rodata.";
if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu)) {
break :name switch (zcu.navFileScope(nav_index).mod.optimize_mode) {
.Debug, .ReleaseSafe => ".data.",
.ReleaseFast, .ReleaseSmall => ".bss.",
};
}
// Will be freed upon freeing of decl or after cleanup of Wasm binary.
const full_segment_name = try std.mem.concat(gpa, u8, &.{
segment_name,
decl.fqn.toSlice(ip),
});
errdefer gpa.free(full_segment_name);
sym.tag = .data;
sym.index = try zig_object.createDataSegment(gpa, full_segment_name, decl.alignment);
},
// when the decl is all zeroes, we store the atom in the bss segment,
// in all other cases it will be in the data segment.
for (atom.code.items) |byte| {
if (byte != 0) break :name ".data.";
}
break :name ".bss.";
};
if ((wasm_file.base.isObject() or wasm_file.base.comp.config.import_memory) and
std.mem.startsWith(u8, segment_name, ".bss"))
{
@memset(atom.code.items, 0);
}
// Will be freed upon freeing of decl or after cleanup of Wasm binary.
const full_segment_name = try std.mem.concat(gpa, u8, &.{
segment_name,
nav.fqn.toSlice(ip),
});
errdefer gpa.free(full_segment_name);
sym.tag = .data;
sym.index = try zig_object.createDataSegment(gpa, full_segment_name, pt.navAlignment(nav_index));
}
if (code.len == 0) return;
atom.alignment = decl.getAlignment(pt);
atom.alignment = pt.navAlignment(nav_index);
}
/// Creates and initializes a new segment in the 'Data' section.
@ -420,50 +415,51 @@ fn createDataSegment(
return segment_index;
}
/// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`.
/// For a given `InternPool.Nav.Index` returns its corresponding `Atom.Index`.
/// When the index was not found, a new `Atom` will be created, and its index will be returned.
/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
pub fn getOrCreateAtomForDecl(
pub fn getOrCreateAtomForNav(
zig_object: *ZigObject,
wasm_file: *Wasm,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
) !Atom.Index {
const ip = &pt.zcu.intern_pool;
const gpa = pt.zcu.gpa;
const gop = try zig_object.decls_map.getOrPut(gpa, decl_index);
const gop = try zig_object.navs.getOrPut(gpa, nav_index);
if (!gop.found_existing) {
const sym_index = try zig_object.allocateSymbol(gpa);
gop.value_ptr.* = .{ .atom = try wasm_file.createAtom(sym_index, zig_object.index) };
const decl = pt.zcu.declPtr(decl_index);
const nav = ip.getNav(nav_index);
const sym = zig_object.symbol(sym_index);
sym.name = try zig_object.string_table.insert(gpa, decl.fqn.toSlice(&pt.zcu.intern_pool));
sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));
}
return gop.value_ptr.atom;
}
pub fn lowerAnonDecl(
pub fn lowerUav(
zig_object: *ZigObject,
wasm_file: *Wasm,
pt: Zcu.PerThread,
decl_val: InternPool.Index,
uav: InternPool.Index,
explicit_alignment: InternPool.Alignment,
src_loc: Zcu.LazySrcLoc,
) !codegen.Result {
) !codegen.GenResult {
const gpa = wasm_file.base.comp.gpa;
const gop = try zig_object.anon_decls.getOrPut(gpa, decl_val);
const gop = try zig_object.uavs.getOrPut(gpa, uav);
if (!gop.found_existing) {
var name_buf: [32]u8 = undefined;
const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
@intFromEnum(decl_val),
@intFromEnum(uav),
}) catch unreachable;
switch (try zig_object.lowerConst(wasm_file, pt, name, Value.fromInterned(decl_val), src_loc)) {
.ok => |atom_index| zig_object.anon_decls.values()[gop.index] = atom_index,
switch (try zig_object.lowerConst(wasm_file, pt, name, Value.fromInterned(uav), src_loc)) {
.ok => |atom_index| zig_object.uavs.values()[gop.index] = atom_index,
.fail => |em| return .{ .fail = em },
}
}
const atom = wasm_file.getAtomPtr(zig_object.anon_decls.values()[gop.index]);
const atom = wasm_file.getAtomPtr(zig_object.uavs.values()[gop.index]);
atom.alignment = switch (atom.alignment) {
.none => explicit_alignment,
else => switch (explicit_alignment) {
@ -471,53 +467,7 @@ pub fn lowerAnonDecl(
else => atom.alignment.maxStrict(explicit_alignment),
},
};
return .ok;
}
/// Lowers a constant typed value to a local symbol and atom.
/// Returns the symbol index of the local
/// The given `decl` is the parent decl whom owns the constant.
pub fn lowerUnnamedConst(
zig_object: *ZigObject,
wasm_file: *Wasm,
pt: Zcu.PerThread,
val: Value,
decl_index: InternPool.DeclIndex,
) !u32 {
const mod = pt.zcu;
const gpa = mod.gpa;
std.debug.assert(val.typeOf(mod).zigTypeTag(mod) != .Fn); // cannot create local symbols for functions
const decl = mod.declPtr(decl_index);
const parent_atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, pt, decl_index);
const parent_atom = wasm_file.getAtom(parent_atom_index);
const local_index = parent_atom.locals.items.len;
const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{}_{d}", .{
decl.fqn.fmt(&mod.intern_pool), local_index,
});
defer gpa.free(name);
// We want to lower the source location of `decl`. However, when generating
// lazy functions (for e.g. `@tagName`), `decl` may correspond to a type
// rather than a `Nav`!
// The future split of `Decl` into `Nav` and `Cau` may require rethinking this
// logic. For now, just get the source location conditionally as needed.
const decl_src = if (decl.typeOf(mod).toIntern() == .type_type)
decl.val.toType().srcLoc(mod)
else
decl.navSrcLoc(mod);
switch (try zig_object.lowerConst(wasm_file, pt, name, val, decl_src)) {
.ok => |atom_index| {
try wasm_file.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index);
return @intFromEnum(wasm_file.getAtom(atom_index).sym_index);
},
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
return error.CodegenFail;
},
}
return .{ .mcv = .{ .load_symbol = @intFromEnum(atom.sym_index) } };
}
const LowerConstResult = union(enum) {
@ -782,36 +732,38 @@ pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []c
/// For a given decl, find the given symbol index's atom, and create a relocation for the type.
/// Returns the given pointer address
pub fn getDeclVAddr(
pub fn getNavVAddr(
zig_object: *ZigObject,
wasm_file: *Wasm,
pt: Zcu.PerThread,
decl_index: InternPool.DeclIndex,
nav_index: InternPool.Nav.Index,
reloc_info: link.File.RelocInfo,
) !u64 {
const target = wasm_file.base.comp.root_mod.resolved_target.result;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const gpa = zcu.gpa;
const decl = zcu.declPtr(decl_index);
const nav = ip.getNav(nav_index);
const target = &zcu.navFileScope(nav_index).mod.resolved_target.result;
const target_atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, pt, decl_index);
const target_atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);
const target_atom = wasm_file.getAtom(target_atom_index);
const target_symbol_index = @intFromEnum(target_atom.sym_index);
if (decl.isExtern(zcu)) {
const name = decl.name.toSlice(ip);
const lib_name = if (decl.getOwnedExternFunc(zcu)) |ext_fn|
ext_fn.lib_name.toSlice(ip)
else
decl.getOwnedVariable(zcu).?.lib_name.toSlice(ip);
try zig_object.addOrUpdateImport(wasm_file, name, target_atom.sym_index, lib_name, null);
switch (ip.indexToKey(nav.status.resolved.val)) {
.@"extern" => |@"extern"| try zig_object.addOrUpdateImport(
wasm_file,
nav.name.toSlice(ip),
target_atom.sym_index,
@"extern".lib_name.toSlice(ip),
null,
),
else => {},
}
std.debug.assert(reloc_info.parent_atom_index != 0);
const atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = @enumFromInt(reloc_info.parent_atom_index) }).?;
const atom = wasm_file.getAtomPtr(atom_index);
const is_wasm32 = target.cpu.arch == .wasm32;
if (decl.typeOf(pt.zcu).zigTypeTag(pt.zcu) == .Fn) {
if (ip.isFunctionType(ip.getNav(nav_index).typeOf(ip))) {
std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations
try atom.relocs.append(gpa, .{
.index = target_symbol_index,
@ -834,22 +786,22 @@ pub fn getDeclVAddr(
return target_symbol_index;
}
pub fn getAnonDeclVAddr(
pub fn getUavVAddr(
zig_object: *ZigObject,
wasm_file: *Wasm,
decl_val: InternPool.Index,
uav: InternPool.Index,
reloc_info: link.File.RelocInfo,
) !u64 {
const gpa = wasm_file.base.comp.gpa;
const target = wasm_file.base.comp.root_mod.resolved_target.result;
const atom_index = zig_object.anon_decls.get(decl_val).?;
const atom_index = zig_object.uavs.get(uav).?;
const target_symbol_index = @intFromEnum(wasm_file.getAtom(atom_index).sym_index);
const parent_atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = @enumFromInt(reloc_info.parent_atom_index) }).?;
const parent_atom = wasm_file.getAtomPtr(parent_atom_index);
const is_wasm32 = target.cpu.arch == .wasm32;
const mod = wasm_file.base.comp.module.?;
const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
const ty = Type.fromInterned(mod.intern_pool.typeOf(uav));
if (ty.zigTypeTag(mod) == .Fn) {
std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations
try parent_atom.relocs.append(gpa, .{
@ -880,14 +832,14 @@ pub fn deleteExport(
name: InternPool.NullTerminatedString,
) void {
const mod = wasm_file.base.comp.module.?;
const decl_index = switch (exported) {
.decl_index => |decl_index| decl_index,
.value => @panic("TODO: implement Wasm linker code for exporting a constant value"),
const nav_index = switch (exported) {
.nav => |nav_index| nav_index,
.uav => @panic("TODO: implement Wasm linker code for exporting a constant value"),
};
const decl_info = zig_object.decls_map.getPtr(decl_index) orelse return;
if (decl_info.@"export"(zig_object, name.toSlice(&mod.intern_pool))) |sym_index| {
const nav_info = zig_object.navs.getPtr(nav_index) orelse return;
if (nav_info.@"export"(zig_object, name.toSlice(&mod.intern_pool))) |sym_index| {
const sym = zig_object.symbol(sym_index);
decl_info.deleteExport(sym_index);
nav_info.deleteExport(sym_index);
std.debug.assert(zig_object.global_syms.remove(sym.name));
std.debug.assert(wasm_file.symbol_atom.remove(.{ .file = zig_object.index, .index = sym_index }));
zig_object.symbols_free_list.append(wasm_file.base.comp.gpa, sym_index) catch {};
@ -902,38 +854,39 @@ pub fn updateExports(
exported: Zcu.Exported,
export_indices: []const u32,
) !void {
const mod = pt.zcu;
const decl_index = switch (exported) {
.decl_index => |i| i,
.value => |val| {
_ = val;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav_index = switch (exported) {
.nav => |nav| nav,
.uav => |uav| {
_ = uav;
@panic("TODO: implement Wasm linker code for exporting a constant value");
},
};
const decl = mod.declPtr(decl_index);
const atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, pt, decl_index);
const decl_info = zig_object.decls_map.getPtr(decl_index).?;
const nav = ip.getNav(nav_index);
const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);
const nav_info = zig_object.navs.getPtr(nav_index).?;
const atom = wasm_file.getAtom(atom_index);
const atom_sym = atom.symbolLoc().getSymbol(wasm_file).*;
const gpa = mod.gpa;
log.debug("Updating exports for decl '{}'", .{decl.name.fmt(&mod.intern_pool)});
const gpa = zcu.gpa;
log.debug("Updating exports for decl '{}'", .{nav.name.fmt(ip)});
for (export_indices) |export_idx| {
const exp = mod.all_exports.items[export_idx];
if (exp.opts.section.toSlice(&mod.intern_pool)) |section| {
try mod.failed_exports.putNoClobber(gpa, export_idx, try Zcu.ErrorMsg.create(
const exp = zcu.all_exports.items[export_idx];
if (exp.opts.section.toSlice(ip)) |section| {
try zcu.failed_exports.putNoClobber(gpa, export_idx, try Zcu.ErrorMsg.create(
gpa,
decl.navSrcLoc(mod),
zcu.navSrcLoc(nav_index),
"Unimplemented: ExportOptions.section '{s}'",
.{section},
));
continue;
}
const export_string = exp.opts.name.toSlice(&mod.intern_pool);
const sym_index = if (decl_info.@"export"(zig_object, export_string)) |idx| idx else index: {
const export_string = exp.opts.name.toSlice(ip);
const sym_index = if (nav_info.@"export"(zig_object, export_string)) |idx| idx else index: {
const sym_index = try zig_object.allocateSymbol(gpa);
try decl_info.appendExport(gpa, sym_index);
try nav_info.appendExport(gpa, sym_index);
break :index sym_index;
};
@ -954,9 +907,9 @@ pub fn updateExports(
},
.strong => {}, // symbols are strong by default
.link_once => {
try mod.failed_exports.putNoClobber(gpa, export_idx, try Zcu.ErrorMsg.create(
try zcu.failed_exports.putNoClobber(gpa, export_idx, try Zcu.ErrorMsg.create(
gpa,
decl.navSrcLoc(mod),
zcu.navSrcLoc(nav_index),
"Unimplemented: LinkOnce",
.{},
));
@ -972,21 +925,21 @@ pub fn updateExports(
}
}
pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool.DeclIndex) void {
pub fn freeNav(zig_object: *ZigObject, wasm_file: *Wasm, nav_index: InternPool.Nav.Index) void {
const gpa = wasm_file.base.comp.gpa;
const mod = wasm_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
const decl_info = zig_object.decls_map.getPtr(decl_index).?;
const atom_index = decl_info.atom;
const ip = &mod.intern_pool;
const nav_info = zig_object.navs.getPtr(nav_index).?;
const atom_index = nav_info.atom;
const atom = wasm_file.getAtomPtr(atom_index);
zig_object.symbols_free_list.append(gpa, atom.sym_index) catch {};
for (decl_info.exports.items) |exp_sym_index| {
for (nav_info.exports.items) |exp_sym_index| {
const exp_sym = zig_object.symbol(exp_sym_index);
exp_sym.tag = .dead;
zig_object.symbols_free_list.append(exp_sym_index) catch {};
}
decl_info.exports.deinit(gpa);
std.debug.assert(zig_object.decls_map.remove(decl_index));
nav_info.exports.deinit(gpa);
std.debug.assert(zig_object.navs.remove(nav_index));
const sym = &zig_object.symbols.items[atom.sym_index];
for (atom.locals.items) |local_atom_index| {
const local_atom = wasm_file.getAtom(local_atom_index);
@ -1000,7 +953,8 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool
segment.name = &.{}; // Ensure no accidental double free
}
if (decl.isExtern(mod)) {
const nav_val = mod.navValue(nav_index).toIntern();
if (ip.indexToKey(nav_val) == .@"extern") {
std.debug.assert(zig_object.imports.remove(atom.sym_index));
}
std.debug.assert(wasm_file.symbol_atom.remove(atom.symbolLoc()));
@ -1014,17 +968,14 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool
if (sym.isGlobal()) {
std.debug.assert(zig_object.global_syms.remove(atom.sym_index));
}
switch (decl.typeOf(mod).zigTypeTag(mod)) {
.Fn => {
zig_object.functions_free_list.append(gpa, sym.index) catch {};
std.debug.assert(zig_object.atom_types.remove(atom_index));
},
else => {
zig_object.segment_free_list.append(gpa, sym.index) catch {};
const segment = &zig_object.segment_info.items[sym.index];
gpa.free(segment.name);
segment.name = &.{}; // Prevent accidental double free
},
if (ip.isFunctionType(ip.typeOf(nav_val))) {
zig_object.functions_free_list.append(gpa, sym.index) catch {};
std.debug.assert(zig_object.atom_types.remove(atom_index));
} else {
zig_object.segment_free_list.append(gpa, sym.index) catch {};
const segment = &zig_object.segment_info.items[sym.index];
gpa.free(segment.name);
segment.name = &.{}; // Prevent accidental double free
}
}
@ -1182,10 +1133,10 @@ fn allocateDebugAtoms(zig_object: *ZigObject) !void {
/// For the given `decl_index`, stores the corresponding type representing the function signature.
/// Asserts declaration has an associated `Atom`.
/// Returns the index into the list of types.
pub fn storeDeclType(zig_object: *ZigObject, gpa: std.mem.Allocator, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 {
const decl_info = zig_object.decls_map.get(decl_index).?;
pub fn storeDeclType(zig_object: *ZigObject, gpa: std.mem.Allocator, nav_index: InternPool.Nav.Index, func_type: std.wasm.Type) !u32 {
const nav_info = zig_object.navs.get(nav_index).?;
const index = try zig_object.putOrGetFuncType(gpa, func_type);
try zig_object.atom_types.put(gpa, decl_info.atom, index);
try zig_object.atom_types.put(gpa, nav_info.atom, index);
return index;
}

View File

@ -675,7 +675,7 @@ const Writer = struct {
}
}
const asm_source = std.mem.sliceAsBytes(w.air.extra[extra_i..])[0..extra.data.source_len];
try s.print(", \"{s}\"", .{asm_source});
try s.print(", \"{}\"", .{std.zig.fmtEscapes(asm_source)});
}
fn writeDbgStmt(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {

View File

@ -90,12 +90,8 @@ pub fn print(
else => try writer.writeAll(@tagName(simple_value)),
},
.variable => try writer.writeAll("(variable)"),
.extern_func => |extern_func| try writer.print("(extern function '{}')", .{
mod.declPtr(extern_func.decl).name.fmt(ip),
}),
.func => |func| try writer.print("(function '{}')", .{
mod.declPtr(func.owner_decl).name.fmt(ip),
}),
.@"extern" => |e| try writer.print("(extern '{}')", .{e.name.fmt(ip)}),
.func => |func| try writer.print("(function '{}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}),
.int => |int| switch (int.storage) {
inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}),
.lazy_align => |ty| if (have_sema) {
@ -138,8 +134,8 @@ pub fn print(
.slice => |slice| {
const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) {
.field, .arr_elem, .eu_payload, .opt_payload => unreachable,
.anon_decl, .comptime_alloc, .comptime_field => true,
.decl, .int => false,
.uav, .comptime_alloc, .comptime_field => true,
.nav, .int => false,
};
if (print_contents) {
// TODO: eventually we want to load the slice as an array with `sema`, but that's
@ -157,8 +153,8 @@ pub fn print(
.ptr => {
const print_contents = switch (ip.getBackingAddrTag(val.toIntern()).?) {
.field, .arr_elem, .eu_payload, .opt_payload => unreachable,
.anon_decl, .comptime_alloc, .comptime_field => true,
.decl, .int => false,
.uav, .comptime_alloc, .comptime_field => true,
.nav, .int => false,
};
if (print_contents) {
// TODO: eventually we want to load the pointer with `sema`, but that's
@ -294,11 +290,11 @@ fn printPtr(
else => unreachable,
};
if (ptr.base_addr == .anon_decl) {
if (ptr.base_addr == .uav) {
// If the value is an aggregate, we can potentially print it more nicely.
switch (pt.zcu.intern_pool.indexToKey(ptr.base_addr.anon_decl.val)) {
switch (pt.zcu.intern_pool.indexToKey(ptr.base_addr.uav.val)) {
.aggregate => |agg| return printAggregate(
Value.fromInterned(ptr.base_addr.anon_decl.val),
Value.fromInterned(ptr.base_addr.uav.val),
agg,
true,
writer,
@ -333,13 +329,13 @@ fn printPtrDerivation(
int.ptr_ty.fmt(pt),
int.addr,
}),
.decl_ptr => |decl_index| {
try writer.print("{}", .{zcu.declPtr(decl_index).fqn.fmt(ip)});
.nav_ptr => |nav| {
try writer.print("{}", .{ip.getNav(nav).fqn.fmt(ip)});
},
.anon_decl_ptr => |anon| {
const ty = Value.fromInterned(anon.val).typeOf(zcu);
.uav_ptr => |uav| {
const ty = Value.fromInterned(uav.val).typeOf(zcu);
try writer.print("@as({}, ", .{ty.fmt(pt)});
try print(Value.fromInterned(anon.val), writer, level - 1, pt, have_sema, sema);
try print(Value.fromInterned(uav.val), writer, level - 1, pt, have_sema, sema);
try writer.writeByte(')');
},
.comptime_alloc_ptr => |info| {

View File

@ -605,9 +605,9 @@ test "@typeInfo decls and usingnamespace" {
};
const decls = @typeInfo(B).Struct.decls;
try expect(decls.len == 3);
try expectEqualStrings(decls[0].name, "x");
try expectEqualStrings(decls[1].name, "y");
try expectEqualStrings(decls[2].name, "z");
try expectEqualStrings(decls[0].name, "z");
try expectEqualStrings(decls[1].name, "x");
try expectEqualStrings(decls[2].name, "y");
}
test "@typeInfo decls ignore dependency loops" {

View File

@ -90,10 +90,6 @@ test {
try expect(a.x == AA.c().expected);
}
comptime {
_ = @import("usingnamespace/file_1.zig");
}
const Bar = struct {
usingnamespace Mixin;
};

View File

@ -1 +0,0 @@
pub const A = 123;

View File

@ -1,12 +0,0 @@
const std = @import("std");
const expect = std.testing.expect;
const imports = @import("imports.zig");
const builtin = @import("builtin");
const A = 456;
test {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try expect(imports.A == 123);
}

View File

@ -1,5 +0,0 @@
const file_0 = @import("file_0.zig");
const file_1 = @import("file_1.zig");
pub usingnamespace file_0;
pub usingnamespace file_1;

View File

@ -1,22 +0,0 @@
export fn entry() void {
foo();
}
inline fn foo() void {
@setAlignStack(16);
}
export fn entry1() void {
comptime bar();
}
fn bar() void {
@setAlignStack(16);
}
// error
// backend=stage2
// target=native
//
// :5:5: error: @setAlignStack in inline function
// :2:8: note: called from here
// :12:5: error: @setAlignStack in inline call
// :9:17: note: called from here

View File

@ -1,11 +0,0 @@
export fn entry() void {
@setAlignStack(16);
@setAlignStack(16);
}
// error
// backend=stage2
// target=native
//
// :3:5: error: multiple @setAlignStack in the same function body
// :2:5: note: other instance here

View File

@ -8,5 +8,5 @@ test "enum" {
// target=native
// is_test=true
//
// :3:9: error: no field with value '@enumFromInt(5)' in enum 'test.enum.E'
// :3:9: error: no field with value '@enumFromInt(5)' in enum 'tmp.test.enum.E'
// :2:15: note: declared here