mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
Merge pull request #20964 from mlugg/the-great-decl-split-mk2
compiler: split `Decl` into `Nav` and `Cau`
This commit is contained in:
commit
fc29240806
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
1503
src/InternPool.zig
1503
src/InternPool.zig
File diff suppressed because it is too large
Load Diff
2142
src/Sema.zig
2142
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,
|
||||
|
||||
192
src/Type.zig
192
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,
|
||||
@ -2972,41 +2968,27 @@ pub fn indexableHasLen(ty: Type, mod: *Module) bool {
|
||||
}
|
||||
|
||||
/// Asserts that the type can have a namespace.
|
||||
pub fn getNamespaceIndex(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex {
|
||||
return ty.getNamespace(zcu).?;
|
||||
pub fn getNamespaceIndex(ty: Type, zcu: *Zcu) InternPool.NamespaceIndex {
|
||||
return ty.getNamespace(zcu).unwrap().?;
|
||||
}
|
||||
|
||||
/// Returns null if the type has no namespace.
|
||||
pub fn getNamespace(ty: Type, zcu: *Zcu) ?InternPool.OptionalNamespaceIndex {
|
||||
pub fn getNamespace(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex {
|
||||
const ip = &zcu.intern_pool;
|
||||
return switch (ip.indexToKey(ty.toIntern())) {
|
||||
.opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace,
|
||||
.opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace.toOptional(),
|
||||
.struct_type => ip.loadStructType(ty.toIntern()).namespace,
|
||||
.union_type => ip.loadUnionType(ty.toIntern()).namespace,
|
||||
.enum_type => ip.loadEnumType(ty.toIntern()).namespace,
|
||||
|
||||
.anon_struct_type => .none,
|
||||
.simple_type => |s| switch (s) {
|
||||
.anyopaque,
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_modifier,
|
||||
.prefetch_options,
|
||||
.export_options,
|
||||
.extern_options,
|
||||
.type_info,
|
||||
=> .none,
|
||||
else => null,
|
||||
},
|
||||
|
||||
else => null,
|
||||
.union_type => ip.loadUnionType(ty.toIntern()).namespace.toOptional(),
|
||||
.enum_type => ip.loadEnumType(ty.toIntern()).namespace.toOptional(),
|
||||
else => .none,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: new dwarf structure will also need the enclosing code block for types created in imperative scopes
|
||||
pub fn getParentNamespace(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex {
|
||||
return zcu.namespacePtr(ty.getNamespace(zcu).unwrap() orelse return .none).parent;
|
||||
}
|
||||
|
||||
// Works for vectors and vectors of integers.
|
||||
pub fn minInt(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value {
|
||||
const mod = pt.zcu;
|
||||
@ -3321,21 +3303,6 @@ pub fn structFieldOffset(ty: Type, index: usize, pt: Zcu.PerThread) u64 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getOwnerDecl(ty: Type, mod: *Module) InternPool.DeclIndex {
|
||||
return ty.getOwnerDeclOrNull(mod) orelse unreachable;
|
||||
}
|
||||
|
||||
pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?InternPool.DeclIndex {
|
||||
const ip = &mod.intern_pool;
|
||||
return switch (ip.indexToKey(ty.toIntern())) {
|
||||
.struct_type => ip.loadStructType(ty.toIntern()).decl.unwrap(),
|
||||
.union_type => ip.loadUnionType(ty.toIntern()).decl,
|
||||
.opaque_type => ip.loadOpaqueType(ty.toIntern()).decl,
|
||||
.enum_type => ip.loadEnumType(ty.toIntern()).decl,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Module.LazySrcLoc {
|
||||
const ip = &zcu.intern_pool;
|
||||
return .{
|
||||
@ -3366,7 +3333,7 @@ pub fn isTuple(ty: Type, mod: *Module) bool {
|
||||
.struct_type => {
|
||||
const struct_type = ip.loadStructType(ty.toIntern());
|
||||
if (struct_type.layout == .@"packed") return false;
|
||||
if (struct_type.decl == .none) return false;
|
||||
if (struct_type.cau == .none) return false;
|
||||
return struct_type.flagsUnordered(ip).is_tuple;
|
||||
},
|
||||
.anon_struct_type => |anon_struct| anon_struct.names.len == 0,
|
||||
@ -3388,7 +3355,7 @@ pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool {
|
||||
.struct_type => {
|
||||
const struct_type = ip.loadStructType(ty.toIntern());
|
||||
if (struct_type.layout == .@"packed") return false;
|
||||
if (struct_type.decl == .none) return false;
|
||||
if (struct_type.cau == .none) return false;
|
||||
return struct_type.flagsUnordered(ip).is_tuple;
|
||||
},
|
||||
.anon_struct_type => true,
|
||||
@ -3444,6 +3411,21 @@ pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn typeDeclInstAllowGeneratedTag(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
|
||||
const ip = &zcu.intern_pool;
|
||||
return switch (ip.indexToKey(ty.toIntern())) {
|
||||
.struct_type => ip.loadStructType(ty.toIntern()).zir_index.unwrap(),
|
||||
.union_type => ip.loadUnionType(ty.toIntern()).zir_index,
|
||||
.enum_type => |e| switch (e) {
|
||||
.declared, .reified => ip.loadEnumType(ty.toIntern()).zir_index.unwrap().?,
|
||||
.generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
|
||||
.empty_struct => unreachable,
|
||||
},
|
||||
.opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
|
||||
const ip = &zcu.intern_pool;
|
||||
const tracked = switch (ip.indexToKey(ty.toIntern())) {
|
||||
@ -3471,7 +3453,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
|
||||
};
|
||||
}
|
||||
|
||||
/// Given a namespace type, returns its list of caotured values.
|
||||
/// Given a namespace type, returns its list of captured values.
|
||||
pub fn getCaptures(ty: Type, zcu: *const Zcu) InternPool.CaptureValue.Slice {
|
||||
const ip = &zcu.intern_pool;
|
||||
return switch (ip.indexToKey(ty.toIntern())) {
|
||||
@ -3773,7 +3755,11 @@ fn resolveStructInner(
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
const struct_obj = zcu.typeToStruct(ty).?;
|
||||
const owner_decl_index = struct_obj.decl.unwrap() orelse return;
|
||||
const owner = InternPool.AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap() orelse return });
|
||||
|
||||
if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
|
||||
return error.AnalysisFail;
|
||||
}
|
||||
|
||||
var analysis_arena = std.heap.ArenaAllocator.init(gpa);
|
||||
defer analysis_arena.deinit();
|
||||
@ -3786,24 +3772,30 @@ fn resolveStructInner(
|
||||
.gpa = gpa,
|
||||
.arena = analysis_arena.allocator(),
|
||||
.code = undefined, // This ZIR will not be used.
|
||||
.owner_decl = zcu.declPtr(owner_decl_index),
|
||||
.owner_decl_index = owner_decl_index,
|
||||
.owner = owner,
|
||||
.func_index = .none,
|
||||
.func_is_naked = false,
|
||||
.fn_ret_ty = Type.void,
|
||||
.fn_ret_ty_ies = null,
|
||||
.owner_func_index = .none,
|
||||
.comptime_err_ret_trace = &comptime_err_ret_trace,
|
||||
};
|
||||
defer sema.deinit();
|
||||
|
||||
switch (resolution) {
|
||||
.fields => return sema.resolveTypeFieldsStruct(ty.toIntern(), struct_obj),
|
||||
.inits => return sema.resolveStructFieldInits(ty),
|
||||
.alignment => return sema.resolveStructAlignment(ty.toIntern(), struct_obj),
|
||||
.layout => return sema.resolveStructLayout(ty),
|
||||
.full => return sema.resolveStructFully(ty),
|
||||
}
|
||||
(switch (resolution) {
|
||||
.fields => sema.resolveTypeFieldsStruct(ty.toIntern(), struct_obj),
|
||||
.inits => sema.resolveStructFieldInits(ty),
|
||||
.alignment => sema.resolveStructAlignment(ty.toIntern(), struct_obj),
|
||||
.layout => sema.resolveStructLayout(ty),
|
||||
.full => sema.resolveStructFully(ty),
|
||||
}) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
if (!zcu.failed_analysis.contains(owner)) {
|
||||
try zcu.transitive_failed_analysis.put(gpa, owner, {});
|
||||
}
|
||||
return error.AnalysisFail;
|
||||
},
|
||||
error.OutOfMemory => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
/// `ty` must be a union.
|
||||
@ -3816,7 +3808,11 @@ fn resolveUnionInner(
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
const union_obj = zcu.typeToUnion(ty).?;
|
||||
const owner_decl_index = union_obj.decl;
|
||||
const owner = InternPool.AnalUnit.wrap(.{ .cau = union_obj.cau });
|
||||
|
||||
if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
|
||||
return error.AnalysisFail;
|
||||
}
|
||||
|
||||
var analysis_arena = std.heap.ArenaAllocator.init(gpa);
|
||||
defer analysis_arena.deinit();
|
||||
@ -3829,23 +3825,29 @@ fn resolveUnionInner(
|
||||
.gpa = gpa,
|
||||
.arena = analysis_arena.allocator(),
|
||||
.code = undefined, // This ZIR will not be used.
|
||||
.owner_decl = zcu.declPtr(owner_decl_index),
|
||||
.owner_decl_index = owner_decl_index,
|
||||
.owner = owner,
|
||||
.func_index = .none,
|
||||
.func_is_naked = false,
|
||||
.fn_ret_ty = Type.void,
|
||||
.fn_ret_ty_ies = null,
|
||||
.owner_func_index = .none,
|
||||
.comptime_err_ret_trace = &comptime_err_ret_trace,
|
||||
};
|
||||
defer sema.deinit();
|
||||
|
||||
switch (resolution) {
|
||||
.fields => return sema.resolveTypeFieldsUnion(ty, union_obj),
|
||||
.alignment => return sema.resolveUnionAlignment(ty, union_obj),
|
||||
.layout => return sema.resolveUnionLayout(ty),
|
||||
.full => return sema.resolveUnionFully(ty),
|
||||
}
|
||||
(switch (resolution) {
|
||||
.fields => sema.resolveTypeFieldsUnion(ty, union_obj),
|
||||
.alignment => sema.resolveUnionAlignment(ty, union_obj),
|
||||
.layout => sema.resolveUnionLayout(ty),
|
||||
.full => sema.resolveUnionFully(ty),
|
||||
}) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
if (!zcu.failed_analysis.contains(owner)) {
|
||||
try zcu.transitive_failed_analysis.put(gpa, owner, {});
|
||||
}
|
||||
return error.AnalysisFail;
|
||||
},
|
||||
error.OutOfMemory => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
/// Fully resolves a simple type. This is usually a nop, but for builtin types with
|
||||
@ -3945,6 +3947,16 @@ pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTerminatedString {
|
||||
return switch (ip.indexToKey(ty.toIntern())) {
|
||||
.struct_type => ip.loadStructType(ty.toIntern()).name,
|
||||
.union_type => ip.loadUnionType(ty.toIntern()).name,
|
||||
.enum_type => ip.loadEnumType(ty.toIntern()).name,
|
||||
.opaque_type => ip.loadOpaqueType(ty.toIntern()).name,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub const @"u1": Type = .{ .ip_index = .u1_type };
|
||||
pub const @"u8": Type = .{ .ip_index = .u8_type };
|
||||
pub const @"u16": Type = .{ .ip_index = .u16_type };
|
||||
|
||||
@ -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…
x
Reference in New Issue
Block a user