mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
compiler: split Decl into Nav and Cau
The type `Zcu.Decl` in the compiler is problematic: over time it has gained many responsibilities. Every source declaration, container type, generic instantiation, and `@extern` has a `Decl`. The functions of these `Decl`s are in some cases entirely disjoint. After careful analysis, I determined that the two main responsibilities of `Decl` are as follows: * A `Decl` acts as the "subject" of semantic analysis at comptime. A single unit of analysis is either a runtime function body, or a `Decl`. It registers incremental dependencies, tracks analysis errors, etc. * A `Decl` acts as a "global variable": a pointer to it is consistent, and it may be lowered to a specific symbol by the codegen backend. This commit eliminates `Decl` and introduces new types to model these responsibilities: `Cau` (Comptime Analysis Unit) and `Nav` (Named Addressable Value). Every source declaration, and every container type requiring resolution (so *not* including `opaque`), has a `Cau`. For a source declaration, this `Cau` performs the resolution of its value. (When #131 is implemented, it is unsolved whether type and value resolution will share a `Cau` or have two distinct `Cau`s.) For a type, this `Cau` is the context in which type resolution occurs. Every non-`comptime` source declaration, every generic instantiation, and every distinct `extern` has a `Nav`. These are sent to codegen/link: the backends by definition do not care about `Cau`s. This commit has some minor technically-breaking changes surrounding `usingnamespace`. I don't think they'll impact anyone, since the changes are fixes around semantics which were previously inconsistent (the behavior changed depending on hashmap iteration order!). Aside from that, this changeset has no significant user-facing changes. Instead, it is an internal refactor which makes it easier to correctly model the responsibilities of different objects, particularly regarding incremental compilation. The performance impact should be negligible, but I will take measurements before merging this work into `master`. Co-authored-by: Jacob Young <jacobly0@users.noreply.github.com> Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
This commit is contained in:
parent
531cd177e8
commit
548a087faf
49 changed files with 6387 additions and 7171 deletions
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1394
src/InternPool.zig
1394
src/InternPool.zig
File diff suppressed because it is too large
Load diff
2080
src/Sema.zig
2080
src/Sema.zig
File diff suppressed because it is too large
Load diff
|
|
@ -254,7 +254,7 @@ const UnpackValueBits = struct {
|
|||
.error_set_type,
|
||||
.inferred_error_set_type,
|
||||
.variable,
|
||||
.extern_func,
|
||||
.@"extern",
|
||||
.func,
|
||||
.err,
|
||||
.error_union,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
174
src/Type.zig
174
src/Type.zig
|
|
@ -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,
|
||||
|
|
@ -3007,6 +3003,26 @@ pub fn getNamespace(ty: Type, zcu: *Zcu) ?InternPool.OptionalNamespaceIndex {
|
|||
};
|
||||
}
|
||||
|
||||
// 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 {
|
||||
const ip = &zcu.intern_pool;
|
||||
const cau = switch (ip.indexToKey(ty.toIntern())) {
|
||||
.struct_type => ip.loadStructType(ty.toIntern()).cau,
|
||||
.union_type => ip.loadUnionType(ty.toIntern()).cau.toOptional(),
|
||||
.enum_type => |e| switch (e) {
|
||||
.declared, .reified => ip.loadEnumType(ty.toIntern()).cau,
|
||||
.generated_tag => |gt| ip.loadUnionType(gt.union_type).cau.toOptional(),
|
||||
.empty_struct => unreachable,
|
||||
},
|
||||
// TODO: this doesn't handle opaque types with empty namespaces
|
||||
.opaque_type => return ip.namespacePtr(ip.loadOpaqueType(ty.toIntern()).namespace.unwrap().?).parent,
|
||||
else => return null,
|
||||
};
|
||||
return ip.namespacePtr(ip.getCau(cau.unwrap() orelse return .none).namespace)
|
||||
// TODO: I thought the cau contained the parent namespace based on "analyzed within" but alas
|
||||
.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 +3337,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 +3367,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 +3389,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 +3445,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 +3487,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 +3789,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 +3806,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 +3842,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 +3859,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 +3981,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 };
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
662
src/Zcu.zig
662
src/Zcu.zig
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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).?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
||||
|
|
|
|||
203
src/codegen.zig
203
src/codegen.zig
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
} };
|
||||
|
|
|
|||
|
|
@ -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
88
src/link.zig
88
src/link.zig
|
|
@ -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(
|
||||
|
|
|
|||
242
src/link/C.zig
242
src/link/C.zig
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
1039
src/link/Dwarf.zig
1039
src/link/Dwarf.zig
File diff suppressed because it is too large
Load diff
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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" {
|
||||
|
|
|
|||
|
|
@ -90,10 +90,6 @@ test {
|
|||
try expect(a.x == AA.c().expected);
|
||||
}
|
||||
|
||||
comptime {
|
||||
_ = @import("usingnamespace/file_1.zig");
|
||||
}
|
||||
|
||||
const Bar = struct {
|
||||
usingnamespace Mixin;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
pub const A = 123;
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue